From f365aff0576f568d47efe079664ef00f5039883a Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Wed, 22 May 2024 23:57:21 -0400 Subject: [PATCH 01/39] refactor: one static decl per line Sort the constant string decls from the ones to be moved to module state. --- .../_zope_interface_coptimizations.c | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 2cf453a7..24393669 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -33,22 +33,33 @@ #define PyNative_FromString PyUnicode_FromString -static PyObject *str__dict__, *str__implemented__, *strextends; -static PyObject *BuiltinImplementationSpecifications, *str__provides__; -static PyObject *str__class__, *str__providedBy__; -static PyObject *empty, *fallback; -static PyObject *str__conform__, *str_call_conform, *adapter_hooks; -static PyObject *str_uncached_lookup, *str_uncached_lookupAll; +static PyObject *str__dict__; +static PyObject *str__implemented__; +static PyObject *strextends; +static PyObject *str__provides__; +static PyObject *str__class__; +static PyObject *str__providedBy__; +static PyObject *str__conform__; +static PyObject *str_call_conform; +static PyObject *str_uncached_lookup; +static PyObject *str_uncached_lookupAll; static PyObject *str_uncached_subscriptions; -static PyObject *str_registry, *strro, *str_generation, *strchanged; +static PyObject *str_registry; +static PyObject *strro; +static PyObject *str_generation; +static PyObject *strchanged; static PyObject *str__self__; static PyObject *str__module__; static PyObject *str__name__; static PyObject *str__adapt__; static PyObject *str_CALL_CUSTOM_ADAPT; +/* Moving these statics to module state. */ +static PyObject *adapter_hooks; +static PyObject *BuiltinImplementationSpecifications; +static PyObject *empty; +static PyObject *fallback; static PyTypeObject *Implements; - static int imported_declarations = 0; static int From c2f31b1d4c5a36c2db9a83330535b3a4c221f290 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 00:02:39 -0400 Subject: [PATCH 02/39] feat: add struct for module state Include methods for initializing, traversing, and clearing it. Tidy up module method defs w/ constant docstrings. --- .../_zope_interface_coptimizations.c | 125 ++++++++++++++++-- 1 file changed, 116 insertions(+), 9 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 24393669..84921e66 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -1974,18 +1974,125 @@ static PyTypeObject VerifyingBase = { /* ========================== End: Lookup Bases ======================= */ /* ==================================================================== */ +/* + * Module state struct: holds all data formerly kept as static globals. + */ +typedef struct { + /* our globals (exposed to Python) */ + PyObject* specification_base_class; + PyObject* object_specification_descriptor_class; + PyObject* class_provides_base_class; + PyObject* interface_base_class; + PyObject* lookup_base_class; + PyObject* verifying_base_class; + PyObject* adapter_hooks; + /* members importe from 'zope.interface.declarations' + */ + PyObject* empty; + PyObject* fallback; + PyObject* builtin_impl_specs; + PyTypeObject* implements_class; + /* flag: have we importe the next set of members yet from + * 'zope.interface.declarations? + */ + int decl_imported; +} _zic_module_state; + +/* + * Macro to speed lookup of state members + */ +#define _zic_state(o) ((_zic_module_state*)PyModule_GetState(o)) + +static int +_zic_state_init(PyObject *module) +{ + _zic_module_state *rec = _zic_state(module); + + rec->specification_base_class = NULL; + rec->object_specification_descriptor_class = NULL; + rec->class_provides_base_class = NULL; + rec->interface_base_class = NULL; + rec->lookup_base_class = NULL; + rec->verifying_base_class = NULL; + rec->adapter_hooks = NULL; + + rec->builtin_impl_specs = NULL; + rec->empty = NULL; + rec->fallback = NULL; + rec->implements_class = NULL; + rec->decl_imported = 0; + + return 0; +} + +static int +_zic_state_traverse(PyObject *module, visitproc visit, void* arg) +{ + _zic_module_state *rec = _zic_state(module); + + Py_VISIT(rec->specification_base_class); + Py_VISIT(rec->object_specification_descriptor_class); + Py_VISIT(rec->class_provides_base_class); + Py_VISIT(rec->interface_base_class); + Py_VISIT(rec->lookup_base_class); + Py_VISIT(rec->verifying_base_class); + Py_VISIT(rec->adapter_hooks); + + Py_VISIT(rec->builtin_impl_specs); + Py_VISIT(rec->empty); + Py_VISIT(rec->fallback); + Py_VISIT(rec->implements_class); + + return 0; +} + +static int +_zic_state_clear(PyObject *module) +{ + _zic_module_state *rec = _zic_state(module); + + Py_CLEAR(rec->specification_base_class); + Py_CLEAR(rec->object_specification_descriptor_class); + Py_CLEAR(rec->class_provides_base_class); + Py_CLEAR(rec->interface_base_class); + Py_CLEAR(rec->lookup_base_class); + Py_CLEAR(rec->verifying_base_class); + Py_CLEAR(rec->adapter_hooks); + + Py_CLEAR(rec->builtin_impl_specs); + Py_CLEAR(rec->empty); + Py_CLEAR(rec->fallback); + Py_CLEAR(rec->implements_class); + + return 0; +} +static char implementedBy___doc__[] = ( + "Interfaces implemented by a class or factory.\n" + "Raises TypeError if argument is neither a class nor a callable." +); +static char getObjectSpecification___doc__[] = ( + "Get an object's interfaces (internal api)" +); +static char providedBy___doc__[] = ( + "Get an object's interfaces" +); static struct PyMethodDef m_methods[] = { - {"implementedBy", (PyCFunction)implementedBy, METH_O, - "Interfaces implemented by a class or factory.\n" - "Raises TypeError if argument is neither a class nor a callable."}, - {"getObjectSpecification", (PyCFunction)getObjectSpecification, METH_O, - "Get an object's interfaces (internal api)"}, - {"providedBy", (PyCFunction)providedBy, METH_O, - "Get an object's interfaces"}, - - {NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */ + {"implementedBy", + (PyCFunction)implementedBy, METH_O, + implementedBy___doc__ + }, + {"getObjectSpecification", + (PyCFunction)getObjectSpecification, METH_O, + getObjectSpecification___doc__ + }, + {"providedBy", + (PyCFunction)providedBy, METH_O, + providedBy___doc__ + }, + + {NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */ }; static char module_doc[] = "C optimizations for zope.interface\n\n"; From 14a68b10059287be7a61ac45d7df28342157b16a Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 00:03:50 -0400 Subject: [PATCH 03/39] feat: wire module state into module def Use named members for clarity. --- .../interface/_zope_interface_coptimizations.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 84921e66..ab6c6715 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -2098,15 +2098,14 @@ static struct PyMethodDef m_methods[] = { static char module_doc[] = "C optimizations for zope.interface\n\n"; static struct PyModuleDef _zic_module = { - PyModuleDef_HEAD_INIT, - "_zope_interface_coptimizations", - module_doc, - -1, - m_methods, - NULL, - NULL, - NULL, - NULL + PyModuleDef_HEAD_INIT, + .m_name="_zope_interface_coptimizations", + .m_doc=module_doc, + .m_size=sizeof(_zic_module_state), + .m_methods=m_methods, + /*.m_slots=m_slots,*/ + .m_traverse=_zic_state_traverse, + .m_clear=_zic_state_clear, }; static PyObject * From 7d003c156a9bdf3e00acab7de0f8544a30cdec07 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 00:06:54 -0400 Subject: [PATCH 04/39] refactor: return state pointer from 'zic_state_init' Tidy spelings for pointer vars. --- src/zope/interface/_zope_interface_coptimizations.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index ab6c6715..0167a3a9 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -2003,10 +2003,10 @@ typedef struct { */ #define _zic_state(o) ((_zic_module_state*)PyModule_GetState(o)) -static int -_zic_state_init(PyObject *module) +static _zic_module_state* +_zic_state_init(PyObject* module) { - _zic_module_state *rec = _zic_state(module); + _zic_module_state* rec = _zic_state(module); rec->specification_base_class = NULL; rec->object_specification_descriptor_class = NULL; @@ -2022,13 +2022,13 @@ _zic_state_init(PyObject *module) rec->implements_class = NULL; rec->decl_imported = 0; - return 0; + return rec; } static int -_zic_state_traverse(PyObject *module, visitproc visit, void* arg) +_zic_state_traverse(PyObject* module, visitproc visit, void* arg) { - _zic_module_state *rec = _zic_state(module); + _zic_module_state* rec = _zic_state(module); Py_VISIT(rec->specification_base_class); Py_VISIT(rec->object_specification_descriptor_class); From 61c3abb30acd8e4c2227c589666ac507f890b878 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 00:22:49 -0400 Subject: [PATCH 05/39] refactor: outline multi-phase initialization - Store created objects in the module state first, then copy them where they are needed (in the future, into the module's __dict__ so that Python can use them). - At this point, the module and the types are still all static. - Use 'PyModule_AddType' as a clearer statement of intent. We are going to be creating the types on the heap later, and so will have their addresses to hand. --- .../_zope_interface_coptimizations.c | 164 +++++++++++------- 1 file changed, 100 insertions(+), 64 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 0167a3a9..78102333 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -2111,86 +2111,122 @@ static struct PyModuleDef _zic_module = { static PyObject * init(void) { - PyObject *m; + PyObject *module; #define DEFINE_STRING(S) \ if(! (str ## S = PyUnicode_FromString(# S))) return NULL - DEFINE_STRING(__dict__); - DEFINE_STRING(__implemented__); - DEFINE_STRING(__provides__); - DEFINE_STRING(__class__); - DEFINE_STRING(__providedBy__); - DEFINE_STRING(extends); - DEFINE_STRING(__conform__); - DEFINE_STRING(_call_conform); - DEFINE_STRING(_uncached_lookup); - DEFINE_STRING(_uncached_lookupAll); - DEFINE_STRING(_uncached_subscriptions); - DEFINE_STRING(_registry); - DEFINE_STRING(_generation); - DEFINE_STRING(ro); - DEFINE_STRING(changed); - DEFINE_STRING(__self__); - DEFINE_STRING(__name__); - DEFINE_STRING(__module__); - DEFINE_STRING(__adapt__); - DEFINE_STRING(_CALL_CUSTOM_ADAPT); + DEFINE_STRING(__dict__); + DEFINE_STRING(__implemented__); + DEFINE_STRING(__provides__); + DEFINE_STRING(__class__); + DEFINE_STRING(__providedBy__); + DEFINE_STRING(extends); + DEFINE_STRING(__conform__); + DEFINE_STRING(_call_conform); + DEFINE_STRING(_uncached_lookup); + DEFINE_STRING(_uncached_lookupAll); + DEFINE_STRING(_uncached_subscriptions); + DEFINE_STRING(_registry); + DEFINE_STRING(_generation); + DEFINE_STRING(ro); + DEFINE_STRING(changed); + DEFINE_STRING(__self__); + DEFINE_STRING(__name__); + DEFINE_STRING(__module__); + DEFINE_STRING(__adapt__); + DEFINE_STRING(_CALL_CUSTOM_ADAPT); #undef DEFINE_STRING - adapter_hooks = PyList_New(0); - if (adapter_hooks == NULL) - return NULL; - /* Initialize types: */ - SpecificationBaseType.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&SpecificationBaseType) < 0) - return NULL; - OSDType.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&OSDType) < 0) - return NULL; - CPBType.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&CPBType) < 0) - return NULL; + /* + * To be replaced by a call to PyModuleDef_Init(&_zic_module); + * the function will just return the initilized module def structure, + * allowing the interpreter to create a new module instance + */ + module = PyModule_Create(&_zic_module); + if (module == NULL) + return NULL; - InterfaceBaseType.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&InterfaceBaseType) < 0) - return NULL; + /* + * Below this point, the rest of the function will move to + * the 'mod_exec' phase (run only after the interpreter has + * created the new module instance). + */ - LookupBase.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&LookupBase) < 0) - return NULL; + _zic_module_state *rec = _zic_state_init(module); - VerifyingBase.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&VerifyingBase) < 0) - return NULL; + rec->adapter_hooks = PyList_New(0); + if (rec->adapter_hooks == NULL) + return NULL; - m = PyModule_Create(&_zic_module); - if (m == NULL) - return NULL; + /* temporary: initialize the global static until we can rewire + * the code using it to use module state. + */ + adapter_hooks = rec->adapter_hooks; - /* Add types: */ - if (PyModule_AddObject(m, "SpecificationBase", OBJECT(&SpecificationBaseType)) < 0) - return NULL; - if (PyModule_AddObject(m, "ObjectSpecificationDescriptor", - (PyObject *)&OSDType) < 0) - return NULL; - if (PyModule_AddObject(m, "ClassProvidesBase", OBJECT(&CPBType)) < 0) - return NULL; - if (PyModule_AddObject(m, "InterfaceBase", OBJECT(&InterfaceBaseType)) < 0) - return NULL; - if (PyModule_AddObject(m, "LookupBase", OBJECT(&LookupBase)) < 0) - return NULL; - if (PyModule_AddObject(m, "VerifyingBase", OBJECT(&VerifyingBase)) < 0) - return NULL; - if (PyModule_AddObject(m, "adapter_hooks", adapter_hooks) < 0) - return NULL; - return m; + /* Initialize types: + * Static types are only here until we complete the module state / + * multi-phase initializtion bit. + */ + SpecificationBaseType.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&SpecificationBaseType) < 0) + return NULL; + rec->specification_base_class = OBJECT(&SpecificationBaseType); + + OSDType.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&OSDType) < 0) + return NULL; + rec->object_specification_descriptor_class = OBJECT(&OSDType); + + CPBType.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&CPBType) < 0) + return NULL; + rec->class_provides_base_class = OBJECT(&CPBType); + + InterfaceBaseType.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&InterfaceBaseType) < 0) + return NULL; + rec->interface_base_class = OBJECT(&InterfaceBaseType); + + LookupBase.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&LookupBase) < 0) + return NULL; + rec->lookup_base_class = OBJECT(&LookupBase); + + VerifyingBase.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&VerifyingBase) < 0) + return NULL; + rec->verifying_base_class = OBJECT(&VerifyingBase); + + /* Add types to our dict FBO python; also the adapter hooks */ + if (PyModule_AddType(module, &SpecificationBaseType) < 0) + return NULL; + + if (PyModule_AddType(module, &OSDType) < 0) + return NULL; + + if (PyModule_AddType(module, &CPBType) < 0) + return NULL; + + if (PyModule_AddType(module, &InterfaceBaseType) < 0) + return NULL; + + if (PyModule_AddType(module, &LookupBase) < 0) + return NULL; + + if (PyModule_AddType(module, &VerifyingBase) < 0) + return NULL; + + if (PyModule_AddObject(module, "adapter_hooks", adapter_hooks) < 0) + return NULL; + + return module; } PyMODINIT_FUNC PyInit__zope_interface_coptimizations(void) { - return init(); + return init(); } #ifdef __clang__ From de30f273f4d1081793e4fce2a32fb10cc7f387c2 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 00:27:28 -0400 Subject: [PATCH 06/39] fix: store types in module state as PyTypeObject --- .../_zope_interface_coptimizations.c | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 78102333..ea216b03 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -1979,12 +1979,12 @@ static PyTypeObject VerifyingBase = { */ typedef struct { /* our globals (exposed to Python) */ - PyObject* specification_base_class; - PyObject* object_specification_descriptor_class; - PyObject* class_provides_base_class; - PyObject* interface_base_class; - PyObject* lookup_base_class; - PyObject* verifying_base_class; + PyTypeObject* specification_base_class; + PyTypeObject* object_specification_descriptor_class; + PyTypeObject* class_provides_base_class; + PyTypeObject* interface_base_class; + PyTypeObject* lookup_base_class; + PyTypeObject* verifying_base_class; PyObject* adapter_hooks; /* members importe from 'zope.interface.declarations' */ @@ -2171,50 +2171,52 @@ init(void) SpecificationBaseType.tp_new = PyBaseObject_Type.tp_new; if (PyType_Ready(&SpecificationBaseType) < 0) return NULL; - rec->specification_base_class = OBJECT(&SpecificationBaseType); + rec->specification_base_class = &SpecificationBaseType; OSDType.tp_new = PyBaseObject_Type.tp_new; if (PyType_Ready(&OSDType) < 0) return NULL; - rec->object_specification_descriptor_class = OBJECT(&OSDType); + rec->object_specification_descriptor_class = &OSDType; CPBType.tp_new = PyBaseObject_Type.tp_new; if (PyType_Ready(&CPBType) < 0) return NULL; - rec->class_provides_base_class = OBJECT(&CPBType); + rec->class_provides_base_class = &CPBType; InterfaceBaseType.tp_new = PyBaseObject_Type.tp_new; if (PyType_Ready(&InterfaceBaseType) < 0) return NULL; - rec->interface_base_class = OBJECT(&InterfaceBaseType); + rec->interface_base_class = &InterfaceBaseType; LookupBase.tp_new = PyBaseObject_Type.tp_new; if (PyType_Ready(&LookupBase) < 0) return NULL; - rec->lookup_base_class = OBJECT(&LookupBase); + rec->lookup_base_class = &LookupBase; VerifyingBase.tp_new = PyBaseObject_Type.tp_new; if (PyType_Ready(&VerifyingBase) < 0) return NULL; - rec->verifying_base_class = OBJECT(&VerifyingBase); + rec->verifying_base_class = &VerifyingBase; /* Add types to our dict FBO python; also the adapter hooks */ - if (PyModule_AddType(module, &SpecificationBaseType) < 0) + if (PyModule_AddType(module, rec->specification_base_class) < 0) return NULL; - if (PyModule_AddType(module, &OSDType) < 0) + if (PyModule_AddType( + module, rec->object_specification_descriptor_class + ) < 0) return NULL; - if (PyModule_AddType(module, &CPBType) < 0) + if (PyModule_AddType(module, rec->class_provides_base_class) < 0) return NULL; - if (PyModule_AddType(module, &InterfaceBaseType) < 0) + if (PyModule_AddType(module, rec->interface_base_class) < 0) return NULL; - if (PyModule_AddType(module, &LookupBase) < 0) + if (PyModule_AddType(module, rec->lookup_base_class) < 0) return NULL; - if (PyModule_AddType(module, &VerifyingBase) < 0) + if (PyModule_AddType(module, rec->verifying_base_class) < 0) return NULL; if (PyModule_AddObject(module, "adapter_hooks", adapter_hooks) < 0) From f2e68385e2d05d48c52c8707034cae3f348d2ecb Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 00:34:38 -0400 Subject: [PATCH 07/39] feat: add module-state version of 'import_declarations' - Stores imported values and flag on the module state struct, rather than in global statics. --- .../_zope_interface_coptimizations.c | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index ea216b03..becbdb6e 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -2067,6 +2067,57 @@ _zic_state_clear(PyObject *module) return 0; } +static _zic_module_state* +_zic_state_load_declarations(PyObject* module) +{ + PyObject *declarations; + PyObject *builtin_impl_specs; + PyObject *empty; + PyObject *fallback; + PyObject *implements; + + _zic_module_state *rec = _zic_state(module); + + if (! rec->decl_imported) + { + declarations = PyImport_ImportModule("zope.interface.declarations"); + if (declarations == NULL) { return NULL; } + + builtin_impl_specs = PyObject_GetAttrString( + declarations, "BuiltinImplementationSpecifications" + ); + if (builtin_impl_specs == NULL) { return NULL; } + + empty = PyObject_GetAttrString(declarations, "_empty"); + if (empty == NULL) { return NULL; } + + fallback = PyObject_GetAttrString( + declarations, "implementedByFallback"); + if (fallback == NULL) { return NULL; } + + implements = PyObject_GetAttrString(declarations, "Implements"); + if (implements == NULL) { return NULL; } + + if (! PyType_Check(implements)) + { + PyErr_SetString( + PyExc_TypeError, + "zope.interface.declarations.Implements is not a type" + ); + return NULL; + } + + Py_DECREF(declarations); + + rec->builtin_impl_specs = builtin_impl_specs; + rec->empty = empty; + rec->fallback = fallback; + rec->implements_class = (PyTypeObject*)implements; + rec->decl_imported = 1; + } + return rec; +} + static char implementedBy___doc__[] = ( "Interfaces implemented by a class or factory.\n" "Raises TypeError if argument is neither a class nor a callable." From 7b092d9de55d3d81d55cdc4fafc521d38e75258e Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 09:05:07 -0400 Subject: [PATCH 08/39] chore: reformat to Mozilla style w/ indent == 4 Using 'https://formatter.org/'. --- .../_zope_interface_coptimizations.c | 2540 ++++++++--------- 1 file changed, 1261 insertions(+), 1279 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index becbdb6e..9efa5ff8 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -33,299 +33,274 @@ #define PyNative_FromString PyUnicode_FromString -static PyObject *str__dict__; -static PyObject *str__implemented__; -static PyObject *strextends; -static PyObject *str__provides__; -static PyObject *str__class__; -static PyObject *str__providedBy__; -static PyObject *str__conform__; -static PyObject *str_call_conform; -static PyObject *str_uncached_lookup; -static PyObject *str_uncached_lookupAll; -static PyObject *str_uncached_subscriptions; -static PyObject *str_registry; -static PyObject *strro; -static PyObject *str_generation; -static PyObject *strchanged; -static PyObject *str__self__; -static PyObject *str__module__; -static PyObject *str__name__; -static PyObject *str__adapt__; -static PyObject *str_CALL_CUSTOM_ADAPT; +static PyObject* str__dict__; +static PyObject* str__implemented__; +static PyObject* strextends; +static PyObject* str__provides__; +static PyObject* str__class__; +static PyObject* str__providedBy__; +static PyObject* str__conform__; +static PyObject* str_call_conform; +static PyObject* str_uncached_lookup; +static PyObject* str_uncached_lookupAll; +static PyObject* str_uncached_subscriptions; +static PyObject* str_registry; +static PyObject* strro; +static PyObject* str_generation; +static PyObject* strchanged; +static PyObject* str__self__; +static PyObject* str__module__; +static PyObject* str__name__; +static PyObject* str__adapt__; +static PyObject* str_CALL_CUSTOM_ADAPT; /* Moving these statics to module state. */ -static PyObject *adapter_hooks; -static PyObject *BuiltinImplementationSpecifications; -static PyObject *empty; -static PyObject *fallback; -static PyTypeObject *Implements; +static PyObject* adapter_hooks; +static PyObject* BuiltinImplementationSpecifications; +static PyObject* empty; +static PyObject* fallback; +static PyTypeObject* Implements; static int imported_declarations = 0; static int import_declarations(void) { - PyObject *declarations, *i; + PyObject *declarations, *i; - declarations = PyImport_ImportModule("zope.interface.declarations"); - if (declarations == NULL) - return -1; - - BuiltinImplementationSpecifications = PyObject_GetAttrString( - declarations, "BuiltinImplementationSpecifications"); - if (BuiltinImplementationSpecifications == NULL) - return -1; - - empty = PyObject_GetAttrString(declarations, "_empty"); - if (empty == NULL) - return -1; + declarations = PyImport_ImportModule("zope.interface.declarations"); + if (declarations == NULL) + return -1; - fallback = PyObject_GetAttrString(declarations, "implementedByFallback"); - if (fallback == NULL) - return -1; + BuiltinImplementationSpecifications = PyObject_GetAttrString( + declarations, "BuiltinImplementationSpecifications"); + if (BuiltinImplementationSpecifications == NULL) + return -1; + empty = PyObject_GetAttrString(declarations, "_empty"); + if (empty == NULL) + return -1; + fallback = PyObject_GetAttrString(declarations, "implementedByFallback"); + if (fallback == NULL) + return -1; - i = PyObject_GetAttrString(declarations, "Implements"); - if (i == NULL) - return -1; + i = PyObject_GetAttrString(declarations, "Implements"); + if (i == NULL) + return -1; - if (! PyType_Check(i)) - { - PyErr_SetString(PyExc_TypeError, - "zope.interface.declarations.Implements is not a type"); - return -1; + if (!PyType_Check(i)) { + PyErr_SetString(PyExc_TypeError, + "zope.interface.declarations.Implements is not a type"); + return -1; } - Implements = (PyTypeObject *)i; + Implements = (PyTypeObject*)i; - Py_DECREF(declarations); + Py_DECREF(declarations); - imported_declarations = 1; - return 0; + imported_declarations = 1; + return 0; } +static PyTypeObject SpecificationBaseType; /* Forward */ -static PyTypeObject SpecificationBaseType; /* Forward */ - -static PyObject * -implementedByFallback(PyObject *cls) +static PyObject* +implementedByFallback(PyObject* cls) { - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; + if (imported_declarations == 0 && import_declarations() < 0) + return NULL; - return PyObject_CallFunctionObjArgs(fallback, cls, NULL); + return PyObject_CallFunctionObjArgs(fallback, cls, NULL); } -static PyObject * -implementedBy(PyObject *ignored, PyObject *cls) +static PyObject* +implementedBy(PyObject* ignored, PyObject* cls) { - /* Fast retrieval of implements spec, if possible, to optimize - common case. Use fallback code if we get stuck. - */ + /* Fast retrieval of implements spec, if possible, to optimize + common case. Use fallback code if we get stuck. + */ - PyObject *dict = NULL, *spec; + PyObject *dict = NULL, *spec; - if (PyObject_TypeCheck(cls, &PySuper_Type)) - { - // Let merging be handled by Python. - return implementedByFallback(cls); - } + if (PyObject_TypeCheck(cls, &PySuper_Type)) { + // Let merging be handled by Python. + return implementedByFallback(cls); + } - if (PyType_Check(cls)) - { - dict = TYPE(cls)->tp_dict; - Py_XINCREF(dict); + if (PyType_Check(cls)) { + dict = TYPE(cls)->tp_dict; + Py_XINCREF(dict); } - if (dict == NULL) - dict = PyObject_GetAttr(cls, str__dict__); + if (dict == NULL) + dict = PyObject_GetAttr(cls, str__dict__); - if (dict == NULL) - { - /* Probably a security proxied class, use more expensive fallback code */ - PyErr_Clear(); - return implementedByFallback(cls); + if (dict == NULL) { + /* Probably a security proxied class, use more expensive fallback code + */ + PyErr_Clear(); + return implementedByFallback(cls); } - spec = PyObject_GetItem(dict, str__implemented__); - Py_DECREF(dict); - if (spec) - { - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; + spec = PyObject_GetItem(dict, str__implemented__); + Py_DECREF(dict); + if (spec) { + if (imported_declarations == 0 && import_declarations() < 0) + return NULL; - if (PyObject_TypeCheck(spec, Implements)) - return spec; + if (PyObject_TypeCheck(spec, Implements)) + return spec; - /* Old-style declaration, use more expensive fallback code */ - Py_DECREF(spec); - return implementedByFallback(cls); + /* Old-style declaration, use more expensive fallback code */ + Py_DECREF(spec); + return implementedByFallback(cls); } - PyErr_Clear(); + PyErr_Clear(); - /* Maybe we have a builtin */ - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; + /* Maybe we have a builtin */ + if (imported_declarations == 0 && import_declarations() < 0) + return NULL; - spec = PyDict_GetItem(BuiltinImplementationSpecifications, cls); - if (spec != NULL) - { - Py_INCREF(spec); - return spec; + spec = PyDict_GetItem(BuiltinImplementationSpecifications, cls); + if (spec != NULL) { + Py_INCREF(spec); + return spec; } - /* We're stuck, use fallback */ - return implementedByFallback(cls); + /* We're stuck, use fallback */ + return implementedByFallback(cls); } -static PyObject * -getObjectSpecification(PyObject *ignored, PyObject *ob) -{ - PyObject *cls, *result; - - result = PyObject_GetAttr(ob, str__provides__); - if (!result) - { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - { - /* Propagate non AttributeError exceptions. */ - return NULL; - } - PyErr_Clear(); - } - else - { - int is_instance = -1; - is_instance = PyObject_IsInstance(result, (PyObject*)&SpecificationBaseType); - if (is_instance < 0) - { - /* Propagate all errors */ - return NULL; - } - if (is_instance) - { - return result; - } - } - - /* We do a getattr here so as not to be defeated by proxies */ - cls = PyObject_GetAttr(ob, str__class__); - if (cls == NULL) - { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - { - /* Propagate non-AttributeErrors */ - return NULL; - } - PyErr_Clear(); - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; - - Py_INCREF(empty); - return empty; - } - result = implementedBy(NULL, cls); - Py_DECREF(cls); - - return result; -} +static PyObject* +getObjectSpecification(PyObject* ignored, PyObject* ob) +{ + PyObject *cls, *result; + + result = PyObject_GetAttr(ob, str__provides__); + if (!result) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + /* Propagate non AttributeError exceptions. */ + return NULL; + } + PyErr_Clear(); + } else { + int is_instance = -1; + is_instance = + PyObject_IsInstance(result, (PyObject*)&SpecificationBaseType); + if (is_instance < 0) { + /* Propagate all errors */ + return NULL; + } + if (is_instance) { + return result; + } + } + + /* We do a getattr here so as not to be defeated by proxies */ + cls = PyObject_GetAttr(ob, str__class__); + if (cls == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + /* Propagate non-AttributeErrors */ + return NULL; + } + PyErr_Clear(); + if (imported_declarations == 0 && import_declarations() < 0) + return NULL; + + Py_INCREF(empty); + return empty; + } + result = implementedBy(NULL, cls); + Py_DECREF(cls); -static PyObject * -providedBy(PyObject *ignored, PyObject *ob) -{ - PyObject *result, *cls, *cp; - int is_instance = -1; - result = NULL; - - is_instance = PyObject_IsInstance(ob, (PyObject*)&PySuper_Type); - if (is_instance < 0) - { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - { - /* Propagate non-AttributeErrors */ - return NULL; - } - PyErr_Clear(); - } - if (is_instance) - { - return implementedBy(NULL, ob); - } - - result = PyObject_GetAttr(ob, str__providedBy__); - - if (result == NULL) - { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - { - return NULL; - } - - PyErr_Clear(); - return getObjectSpecification(NULL, ob); - } - - - /* We want to make sure we have a spec. We can't do a type check - because we may have a proxy, so we'll just try to get the - only attribute. - */ - if (PyObject_TypeCheck(result, &SpecificationBaseType) - || - PyObject_HasAttr(result, strextends) - ) return result; +} - /* - The object's class doesn't understand descriptors. - Sigh. We need to get an object descriptor, but we have to be - careful. We want to use the instance's __provides__,l if - there is one, but only if it didn't come from the class. - */ - Py_DECREF(result); +static PyObject* +providedBy(PyObject* ignored, PyObject* ob) +{ + PyObject *result, *cls, *cp; + int is_instance = -1; + result = NULL; + + is_instance = PyObject_IsInstance(ob, (PyObject*)&PySuper_Type); + if (is_instance < 0) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + /* Propagate non-AttributeErrors */ + return NULL; + } + PyErr_Clear(); + } + if (is_instance) { + return implementedBy(NULL, ob); + } - cls = PyObject_GetAttr(ob, str__class__); - if (cls == NULL) - return NULL; + result = PyObject_GetAttr(ob, str__providedBy__); + + if (result == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + return NULL; + } + + PyErr_Clear(); + return getObjectSpecification(NULL, ob); + } + + /* We want to make sure we have a spec. We can't do a type check + because we may have a proxy, so we'll just try to get the + only attribute. + */ + if (PyObject_TypeCheck(result, &SpecificationBaseType) || + PyObject_HasAttr(result, strextends)) + return result; + + /* + The object's class doesn't understand descriptors. + Sigh. We need to get an object descriptor, but we have to be + careful. We want to use the instance's __provides__,l if + there is one, but only if it didn't come from the class. + */ + Py_DECREF(result); - result = PyObject_GetAttr(ob, str__provides__); - if (result == NULL) - { - /* No __provides__, so just fall back to implementedBy */ - PyErr_Clear(); - result = implementedBy(NULL, cls); - Py_DECREF(cls); - return result; + cls = PyObject_GetAttr(ob, str__class__); + if (cls == NULL) + return NULL; + + result = PyObject_GetAttr(ob, str__provides__); + if (result == NULL) { + /* No __provides__, so just fall back to implementedBy */ + PyErr_Clear(); + result = implementedBy(NULL, cls); + Py_DECREF(cls); + return result; } - cp = PyObject_GetAttr(cls, str__provides__); - if (cp == NULL) - { - /* The the class has no provides, assume we're done: */ - PyErr_Clear(); - Py_DECREF(cls); - return result; + cp = PyObject_GetAttr(cls, str__provides__); + if (cp == NULL) { + /* The the class has no provides, assume we're done: */ + PyErr_Clear(); + Py_DECREF(cls); + return result; } - if (cp == result) - { - /* - Oops, we got the provides from the class. This means - the object doesn't have it's own. We should use implementedBy - */ - Py_DECREF(result); - result = implementedBy(NULL, cls); + if (cp == result) { + /* + Oops, we got the provides from the class. This means + the object doesn't have it's own. We should use implementedBy + */ + Py_DECREF(result); + result = implementedBy(NULL, cls); } - Py_DECREF(cls); - Py_DECREF(cp); + Py_DECREF(cls); + Py_DECREF(cp); - return result; + return result; } -typedef struct { +typedef struct +{ PyObject_HEAD PyObject* weakreflist; /* @@ -380,7 +355,7 @@ Spec_dealloc(Spec* self) { /* PyType_GenericAlloc that you get when you don't specify a tp_alloc always tracks the object. */ - PyObject_GC_UnTrack((PyObject *)self); + PyObject_GC_UnTrack((PyObject*)self); if (self->weakreflist != NULL) { PyObject_ClearWeakRefs(OBJECT(self)); } @@ -388,226 +363,222 @@ Spec_dealloc(Spec* self) Py_TYPE(self)->tp_free(OBJECT(self)); } -static PyObject * -Spec_extends(Spec *self, PyObject *other) +static PyObject* +Spec_extends(Spec* self, PyObject* other) { - PyObject *implied; + PyObject* implied; - implied = self->_implied; - if (implied == NULL) { - return NULL; - } + implied = self->_implied; + if (implied == NULL) { + return NULL; + } - if (PyDict_GetItem(implied, other) != NULL) - Py_RETURN_TRUE; - Py_RETURN_FALSE; + if (PyDict_GetItem(implied, other) != NULL) + Py_RETURN_TRUE; + Py_RETURN_FALSE; } static char Spec_extends__doc__[] = -"Test whether a specification is or extends another" -; + "Test whether a specification is or extends another"; static char Spec_providedBy__doc__[] = -"Test whether an interface is implemented by the specification" -; + "Test whether an interface is implemented by the specification"; -static PyObject * -Spec_call(Spec *self, PyObject *args, PyObject *kw) +static PyObject* +Spec_call(Spec* self, PyObject* args, PyObject* kw) { - PyObject *spec; + PyObject* spec; - if (! PyArg_ParseTuple(args, "O", &spec)) - return NULL; - return Spec_extends(self, spec); + if (!PyArg_ParseTuple(args, "O", &spec)) + return NULL; + return Spec_extends(self, spec); } -static PyObject * -Spec_providedBy(PyObject *self, PyObject *ob) +static PyObject* +Spec_providedBy(PyObject* self, PyObject* ob) { - PyObject *decl, *item; + PyObject *decl, *item; - decl = providedBy(NULL, ob); - if (decl == NULL) - return NULL; + decl = providedBy(NULL, ob); + if (decl == NULL) + return NULL; - if (PyObject_TypeCheck(decl, &SpecificationBaseType)) - item = Spec_extends((Spec*)decl, self); - else - /* decl is probably a security proxy. We have to go the long way - around. - */ - item = PyObject_CallFunctionObjArgs(decl, self, NULL); + if (PyObject_TypeCheck(decl, &SpecificationBaseType)) + item = Spec_extends((Spec*)decl, self); + else + /* decl is probably a security proxy. We have to go the long way + around. + */ + item = PyObject_CallFunctionObjArgs(decl, self, NULL); - Py_DECREF(decl); - return item; + Py_DECREF(decl); + return item; } - static char Spec_implementedBy__doc__[] = -"Test whether the specification is implemented by a class or factory.\n" -"Raise TypeError if argument is neither a class nor a callable." -; + "Test whether the specification is implemented by a class or factory.\n" + "Raise TypeError if argument is neither a class nor a callable."; -static PyObject * -Spec_implementedBy(PyObject *self, PyObject *cls) +static PyObject* +Spec_implementedBy(PyObject* self, PyObject* cls) { - PyObject *decl, *item; + PyObject *decl, *item; - decl = implementedBy(NULL, cls); - if (decl == NULL) - return NULL; + decl = implementedBy(NULL, cls); + if (decl == NULL) + return NULL; - if (PyObject_TypeCheck(decl, &SpecificationBaseType)) - item = Spec_extends((Spec*)decl, self); - else - item = PyObject_CallFunctionObjArgs(decl, self, NULL); + if (PyObject_TypeCheck(decl, &SpecificationBaseType)) + item = Spec_extends((Spec*)decl, self); + else + item = PyObject_CallFunctionObjArgs(decl, self, NULL); - Py_DECREF(decl); - return item; + Py_DECREF(decl); + return item; } static struct PyMethodDef Spec_methods[] = { - {"providedBy", - (PyCFunction)Spec_providedBy, METH_O, - Spec_providedBy__doc__}, - {"implementedBy", - (PyCFunction)Spec_implementedBy, METH_O, - Spec_implementedBy__doc__}, - {"isOrExtends", (PyCFunction)Spec_extends, METH_O, - Spec_extends__doc__}, - - {NULL, NULL} /* sentinel */ + { "providedBy", + (PyCFunction)Spec_providedBy, + METH_O, + Spec_providedBy__doc__ }, + { "implementedBy", + (PyCFunction)Spec_implementedBy, + METH_O, + Spec_implementedBy__doc__ }, + { "isOrExtends", (PyCFunction)Spec_extends, METH_O, Spec_extends__doc__ }, + + { NULL, NULL } /* sentinel */ }; static PyMemberDef Spec_members[] = { - {"_implied", T_OBJECT_EX, offsetof(Spec, _implied), 0, ""}, - {"_dependents", T_OBJECT_EX, offsetof(Spec, _dependents), 0, ""}, - {"_bases", T_OBJECT_EX, offsetof(Spec, _bases), 0, ""}, - {"_v_attrs", T_OBJECT_EX, offsetof(Spec, _v_attrs), 0, ""}, - {"__iro__", T_OBJECT_EX, offsetof(Spec, __iro__), 0, ""}, - {"__sro__", T_OBJECT_EX, offsetof(Spec, __sro__), 0, ""}, - {NULL}, + { "_implied", T_OBJECT_EX, offsetof(Spec, _implied), 0, "" }, + { "_dependents", T_OBJECT_EX, offsetof(Spec, _dependents), 0, "" }, + { "_bases", T_OBJECT_EX, offsetof(Spec, _bases), 0, "" }, + { "_v_attrs", T_OBJECT_EX, offsetof(Spec, _v_attrs), 0, "" }, + { "__iro__", T_OBJECT_EX, offsetof(Spec, __iro__), 0, "" }, + { "__sro__", T_OBJECT_EX, offsetof(Spec, __sro__), 0, "" }, + { NULL }, }; - static PyTypeObject SpecificationBaseType = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_interface_coptimizations." - "SpecificationBase", - /* tp_basicsize */ sizeof(Spec), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)Spec_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)0, - /* tp_call */ (ternaryfunc)Spec_call, - /* tp_str */ (reprfunc)0, - /* tp_getattro */ (getattrofunc)0, - /* tp_setattro */ (setattrofunc)0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - "Base type for Specification objects", - /* tp_traverse */ (traverseproc)Spec_traverse, - /* tp_clear */ (inquiry)Spec_clear, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ offsetof(Spec, weakreflist), - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ Spec_methods, - /* tp_members */ Spec_members, + PyVarObject_HEAD_INIT(NULL, 0) + /* tp_name */ "_interface_coptimizations." + "SpecificationBase", + /* tp_basicsize */ sizeof(Spec), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor)Spec_dealloc, + /* tp_print */ (printfunc)0, + /* tp_getattr */ (getattrfunc)0, + /* tp_setattr */ (setattrfunc)0, + /* tp_compare */ 0, + /* tp_repr */ (reprfunc)0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ (hashfunc)0, + /* tp_call */ (ternaryfunc)Spec_call, + /* tp_str */ (reprfunc)0, + /* tp_getattro */ (getattrofunc)0, + /* tp_setattro */ (setattrofunc)0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + "Base type for Specification objects", + /* tp_traverse */ (traverseproc)Spec_traverse, + /* tp_clear */ (inquiry)Spec_clear, + /* tp_richcompare */ (richcmpfunc)0, + /* tp_weaklistoffset */ offsetof(Spec, weakreflist), + /* tp_iter */ (getiterfunc)0, + /* tp_iternext */ (iternextfunc)0, + /* tp_methods */ Spec_methods, + /* tp_members */ Spec_members, }; -static PyObject * -OSD_descr_get(PyObject *self, PyObject *inst, PyObject *cls) +static PyObject* +OSD_descr_get(PyObject* self, PyObject* inst, PyObject* cls) { - PyObject *provides; + PyObject* provides; - if (inst == NULL) - return getObjectSpecification(NULL, cls); + if (inst == NULL) + return getObjectSpecification(NULL, cls); - provides = PyObject_GetAttr(inst, str__provides__); - /* Return __provides__ if we got it, or return NULL and propagate non-AttributeError. */ - if (provides != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError)) - return provides; + provides = PyObject_GetAttr(inst, str__provides__); + /* Return __provides__ if we got it, or return NULL and propagate + * non-AttributeError. */ + if (provides != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError)) + return provides; - PyErr_Clear(); - return implementedBy(NULL, cls); + PyErr_Clear(); + return implementedBy(NULL, cls); } static PyTypeObject OSDType = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_interface_coptimizations." - "ObjectSpecificationDescriptor", - /* tp_basicsize */ 0, - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)0, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)0, - /* tp_call */ (ternaryfunc)0, - /* tp_str */ (reprfunc)0, - /* tp_getattro */ (getattrofunc)0, - /* tp_setattro */ (setattrofunc)0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_BASETYPE , - "Object Specification Descriptor", - /* tp_traverse */ (traverseproc)0, - /* tp_clear */ (inquiry)0, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ 0, - /* tp_members */ 0, - /* tp_getset */ 0, - /* tp_base */ 0, - /* tp_dict */ 0, /* internal use */ - /* tp_descr_get */ (descrgetfunc)OSD_descr_get, + PyVarObject_HEAD_INIT(NULL, 0) + /* tp_name */ "_interface_coptimizations." + "ObjectSpecificationDescriptor", + /* tp_basicsize */ 0, + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor)0, + /* tp_print */ (printfunc)0, + /* tp_getattr */ (getattrfunc)0, + /* tp_setattr */ (setattrfunc)0, + /* tp_compare */ 0, + /* tp_repr */ (reprfunc)0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ (hashfunc)0, + /* tp_call */ (ternaryfunc)0, + /* tp_str */ (reprfunc)0, + /* tp_getattro */ (getattrofunc)0, + /* tp_setattro */ (setattrofunc)0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + "Object Specification Descriptor", + /* tp_traverse */ (traverseproc)0, + /* tp_clear */ (inquiry)0, + /* tp_richcompare */ (richcmpfunc)0, + /* tp_weaklistoffset */ (long)0, + /* tp_iter */ (getiterfunc)0, + /* tp_iternext */ (iternextfunc)0, + /* tp_methods */ 0, + /* tp_members */ 0, + /* tp_getset */ 0, + /* tp_base */ 0, + /* tp_dict */ 0, /* internal use */ + /* tp_descr_get */ (descrgetfunc)OSD_descr_get, }; -typedef struct { +typedef struct +{ Spec spec; /* These members are handled generically, as for Spec members. */ PyObject* _cls; PyObject* _implements; } CPB; -static PyObject * -CPB_descr_get(CPB *self, PyObject *inst, PyObject *cls) +static PyObject* +CPB_descr_get(CPB* self, PyObject* inst, PyObject* cls) { - PyObject *implements; + PyObject* implements; - if (self->_cls == NULL) - return NULL; + if (self->_cls == NULL) + return NULL; - if (cls == self->_cls) - { - if (inst == NULL) - { - Py_INCREF(self); - return OBJECT(self); + if (cls == self->_cls) { + if (inst == NULL) { + Py_INCREF(self); + return OBJECT(self); } - implements = self->_implements; - Py_XINCREF(implements); - return implements; + implements = self->_implements; + Py_XINCREF(implements); + return implements; } - PyErr_SetObject(PyExc_AttributeError, str__provides__); - return NULL; + PyErr_SetObject(PyExc_AttributeError, str__provides__); + return NULL; } static int @@ -630,57 +601,62 @@ CPB_clear(CPB* self) static void CPB_dealloc(CPB* self) { - PyObject_GC_UnTrack((PyObject *)self); + PyObject_GC_UnTrack((PyObject*)self); CPB_clear(self); Spec_dealloc((Spec*)self); } static PyMemberDef CPB_members[] = { - {"_cls", T_OBJECT_EX, offsetof(CPB, _cls), 0, "Defining class."}, - {"_implements", T_OBJECT_EX, offsetof(CPB, _implements), 0, "Result of implementedBy."}, - {NULL} + { "_cls", T_OBJECT_EX, offsetof(CPB, _cls), 0, "Defining class." }, + { "_implements", + T_OBJECT_EX, + offsetof(CPB, _implements), + 0, + "Result of implementedBy." }, + { NULL } }; static PyTypeObject CPBType = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_interface_coptimizations." - "ClassProvidesBase", - /* tp_basicsize */ sizeof(CPB), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)CPB_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)0, - /* tp_call */ (ternaryfunc)0, - /* tp_str */ (reprfunc)0, - /* tp_getattro */ (getattrofunc)0, - /* tp_setattro */ (setattrofunc)0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - "C Base class for ClassProvides", - /* tp_traverse */ (traverseproc)CPB_traverse, - /* tp_clear */ (inquiry)CPB_clear, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ 0, - /* tp_members */ CPB_members, - /* tp_getset */ 0, - /* tp_base */ &SpecificationBaseType, - /* tp_dict */ 0, /* internal use */ - /* tp_descr_get */ (descrgetfunc)CPB_descr_get, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ 0, - /* tp_alloc */ 0, - /* tp_new */ 0, + PyVarObject_HEAD_INIT(NULL, 0) + /* tp_name */ "_interface_coptimizations." + "ClassProvidesBase", + /* tp_basicsize */ sizeof(CPB), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor)CPB_dealloc, + /* tp_print */ (printfunc)0, + /* tp_getattr */ (getattrfunc)0, + /* tp_setattr */ (setattrfunc)0, + /* tp_compare */ 0, + /* tp_repr */ (reprfunc)0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ (hashfunc)0, + /* tp_call */ (ternaryfunc)0, + /* tp_str */ (reprfunc)0, + /* tp_getattro */ (getattrofunc)0, + /* tp_setattro */ (setattrofunc)0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + "C Base class for ClassProvides", + /* tp_traverse */ (traverseproc)CPB_traverse, + /* tp_clear */ (inquiry)CPB_clear, + /* tp_richcompare */ (richcmpfunc)0, + /* tp_weaklistoffset */ (long)0, + /* tp_iter */ (getiterfunc)0, + /* tp_iternext */ (iternextfunc)0, + /* tp_methods */ 0, + /* tp_members */ CPB_members, + /* tp_getset */ 0, + /* tp_base */ &SpecificationBaseType, + /* tp_dict */ 0, /* internal use */ + /* tp_descr_get */ (descrgetfunc)CPB_descr_get, + /* tp_descr_set */ 0, + /* tp_dictoffset */ 0, + /* tp_init */ 0, + /* tp_alloc */ 0, + /* tp_new */ 0, }; /* ==================================================================== */ @@ -700,76 +676,70 @@ static PyTypeObject CPBType = { */ -static PyObject * -__adapt__(PyObject *self, PyObject *obj) +static PyObject* +__adapt__(PyObject* self, PyObject* obj) { - PyObject *decl, *args, *adapter; - int implements, i, l; + PyObject *decl, *args, *adapter; + int implements, i, l; - decl = providedBy(NULL, obj); - if (decl == NULL) - return NULL; + decl = providedBy(NULL, obj); + if (decl == NULL) + return NULL; - if (PyObject_TypeCheck(decl, &SpecificationBaseType)) - { - PyObject *implied; + if (PyObject_TypeCheck(decl, &SpecificationBaseType)) { + PyObject* implied; - implied = ((Spec*)decl)->_implied; - if (implied == NULL) - { - Py_DECREF(decl); - return NULL; + implied = ((Spec*)decl)->_implied; + if (implied == NULL) { + Py_DECREF(decl); + return NULL; } - implements = PyDict_GetItem(implied, self) != NULL; - Py_DECREF(decl); - } - else - { - /* decl is probably a security proxy. We have to go the long way - around. - */ - PyObject *r; - r = PyObject_CallFunctionObjArgs(decl, self, NULL); - Py_DECREF(decl); - if (r == NULL) - return NULL; - implements = PyObject_IsTrue(r); - Py_DECREF(r); + implements = PyDict_GetItem(implied, self) != NULL; + Py_DECREF(decl); + } else { + /* decl is probably a security proxy. We have to go the long way + around. + */ + PyObject* r; + r = PyObject_CallFunctionObjArgs(decl, self, NULL); + Py_DECREF(decl); + if (r == NULL) + return NULL; + implements = PyObject_IsTrue(r); + Py_DECREF(r); } - if (implements) - { - Py_INCREF(obj); - return obj; + if (implements) { + Py_INCREF(obj); + return obj; } - l = PyList_GET_SIZE(adapter_hooks); - args = PyTuple_New(2); - if (args == NULL) - return NULL; - Py_INCREF(self); - PyTuple_SET_ITEM(args, 0, self); - Py_INCREF(obj); - PyTuple_SET_ITEM(args, 1, obj); - for (i = 0; i < l; i++) - { - adapter = PyObject_CallObject(PyList_GET_ITEM(adapter_hooks, i), args); - if (adapter == NULL || adapter != Py_None) - { - Py_DECREF(args); - return adapter; + l = PyList_GET_SIZE(adapter_hooks); + args = PyTuple_New(2); + if (args == NULL) + return NULL; + Py_INCREF(self); + PyTuple_SET_ITEM(args, 0, self); + Py_INCREF(obj); + PyTuple_SET_ITEM(args, 1, obj); + for (i = 0; i < l; i++) { + adapter = PyObject_CallObject(PyList_GET_ITEM(adapter_hooks, i), args); + if (adapter == NULL || adapter != Py_None) { + Py_DECREF(args); + return adapter; } - Py_DECREF(adapter); + Py_DECREF(adapter); } - Py_DECREF(args); + Py_DECREF(args); - Py_INCREF(Py_None); - return Py_None; + Py_INCREF(Py_None); + return Py_None; } -typedef struct { +typedef struct +{ Spec spec; PyObject* __name__; PyObject* __module__; @@ -777,9 +747,11 @@ typedef struct { } IB; static struct PyMethodDef ib_methods[] = { - {"__adapt__", (PyCFunction)__adapt__, METH_O, - "Adapt an object to the receiver"}, - {NULL, NULL} /* sentinel */ + { "__adapt__", + (PyCFunction)__adapt__, + METH_O, + "Adapt an object to the receiver" }, + { NULL, NULL } /* sentinel */ }; /* @@ -803,84 +775,71 @@ static struct PyMethodDef ib_methods[] = { raise TypeError("Could not adapt", obj, self) */ -static PyObject * -IB_call(PyObject *self, PyObject *args, PyObject *kwargs) +static PyObject* +IB_call(PyObject* self, PyObject* args, PyObject* kwargs) { - PyObject *conform, *obj, *alternate, *adapter; - static char *kwlist[] = {"obj", "alternate", NULL}; - conform = obj = alternate = adapter = NULL; + PyObject *conform, *obj, *alternate, *adapter; + static char* kwlist[] = { "obj", "alternate", NULL }; + conform = obj = alternate = adapter = NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "O|O", kwlist, &obj, &alternate)) + return NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist, - &obj, &alternate)) - return NULL; + conform = PyObject_GetAttr(obj, str__conform__); + if (conform == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + /* Propagate non-AttributeErrors */ + return NULL; + } + PyErr_Clear(); - conform = PyObject_GetAttr(obj, str__conform__); - if (conform == NULL) - { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - { - /* Propagate non-AttributeErrors */ - return NULL; - } - PyErr_Clear(); - - Py_INCREF(Py_None); - conform = Py_None; - } - - if (conform != Py_None) - { - adapter = PyObject_CallMethodObjArgs(self, str_call_conform, - conform, NULL); - Py_DECREF(conform); - if (adapter == NULL || adapter != Py_None) - return adapter; - Py_DECREF(adapter); - } - else - { - Py_DECREF(conform); - } - - /* We differ from the Python code here. For speed, instead of always calling - self.__adapt__(), we check to see if the type has defined it. Checking in - the dict for __adapt__ isn't sufficient because there's no cheap way to - tell if it's the __adapt__ that InterfaceBase itself defines (our type - will *never* be InterfaceBase, we're always subclassed by - InterfaceClass). Instead, we cooperate with InterfaceClass in Python to - set a flag in a new subclass when this is necessary. */ - if (PyDict_GetItem(self->ob_type->tp_dict, str_CALL_CUSTOM_ADAPT)) - { - /* Doesn't matter what the value is. Simply being present is enough. */ - adapter = PyObject_CallMethodObjArgs(self, str__adapt__, obj, NULL); - } - else - { - adapter = __adapt__(self, obj); - } - - if (adapter == NULL || adapter != Py_None) - { - return adapter; - } - Py_DECREF(adapter); - - if (alternate != NULL) - { - Py_INCREF(alternate); - return alternate; - } - - adapter = Py_BuildValue("sOO", "Could not adapt", obj, self); - if (adapter != NULL) - { - PyErr_SetObject(PyExc_TypeError, adapter); - Py_DECREF(adapter); - } - return NULL; -} + Py_INCREF(Py_None); + conform = Py_None; + } + + if (conform != Py_None) { + adapter = + PyObject_CallMethodObjArgs(self, str_call_conform, conform, NULL); + Py_DECREF(conform); + if (adapter == NULL || adapter != Py_None) + return adapter; + Py_DECREF(adapter); + } else { + Py_DECREF(conform); + } + + /* We differ from the Python code here. For speed, instead of always calling + self.__adapt__(), we check to see if the type has defined it. Checking in + the dict for __adapt__ isn't sufficient because there's no cheap way to + tell if it's the __adapt__ that InterfaceBase itself defines (our type + will *never* be InterfaceBase, we're always subclassed by + InterfaceClass). Instead, we cooperate with InterfaceClass in Python to + set a flag in a new subclass when this is necessary. */ + if (PyDict_GetItem(self->ob_type->tp_dict, str_CALL_CUSTOM_ADAPT)) { + /* Doesn't matter what the value is. Simply being present is enough. */ + adapter = PyObject_CallMethodObjArgs(self, str__adapt__, obj, NULL); + } else { + adapter = __adapt__(self, obj); + } + + if (adapter == NULL || adapter != Py_None) { + return adapter; + } + Py_DECREF(adapter); + + if (alternate != NULL) { + Py_INCREF(alternate); + return alternate; + } + adapter = Py_BuildValue("sOO", "Could not adapt", obj, self); + if (adapter != NULL) { + PyErr_SetObject(PyExc_TypeError, adapter); + Py_DECREF(adapter); + } + return NULL; +} static int IB_traverse(IB* self, visitproc visit, void* arg) @@ -901,18 +860,18 @@ IB_clear(IB* self) static void IB_dealloc(IB* self) { - PyObject_GC_UnTrack((PyObject *)self); + PyObject_GC_UnTrack((PyObject*)self); IB_clear(self); Spec_dealloc((Spec*)self); } static PyMemberDef IB_members[] = { - {"__name__", T_OBJECT_EX, offsetof(IB, __name__), 0, ""}, - // The redundancy between __module__ and __ibmodule__ is because - // __module__ is often shadowed by subclasses. - {"__module__", T_OBJECT_EX, offsetof(IB, __module__), READONLY, ""}, - {"__ibmodule__", T_OBJECT_EX, offsetof(IB, __module__), 0, ""}, - {NULL} + { "__name__", T_OBJECT_EX, offsetof(IB, __name__), 0, "" }, + // The redundancy between __module__ and __ibmodule__ is because + // __module__ is often shadowed by subclasses. + { "__module__", T_OBJECT_EX, offsetof(IB, __module__), READONLY, "" }, + { "__ibmodule__", T_OBJECT_EX, offsetof(IB, __module__), 0, "" }, + { NULL } }; static Py_hash_t @@ -956,25 +915,25 @@ IB_richcompare(IB* self, PyObject* other, int op) oresult = othername = othermod = NULL; if (OBJECT(self) == other) { - switch(op) { - case Py_EQ: - case Py_LE: - case Py_GE: - Py_RETURN_TRUE; - break; - case Py_NE: - Py_RETURN_FALSE; + switch (op) { + case Py_EQ: + case Py_LE: + case Py_GE: + Py_RETURN_TRUE; + break; + case Py_NE: + Py_RETURN_FALSE; } } if (other == Py_None) { - switch(op) { - case Py_LT: - case Py_LE: - case Py_NE: - Py_RETURN_TRUE; - default: - Py_RETURN_FALSE; + switch (op) { + case Py_LT: + case Py_LE: + case Py_NE: + Py_RETURN_TRUE; + default: + Py_RETURN_FALSE; } } @@ -984,14 +943,14 @@ IB_richcompare(IB* self, PyObject* other, int op) otherib = (IB*)other; othername = otherib->__name__; othermod = otherib->__module__; - } - else { + } else { othername = PyObject_GetAttrString(other, "__name__"); if (othername) { othermod = PyObject_GetAttrString(other, "__module__"); } if (!othername || !othermod) { - if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_AttributeError)) { + if (PyErr_Occurred() && + PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); oresult = Py_NotImplemented; } @@ -1009,8 +968,7 @@ IB_richcompare(IB* self, PyObject* other, int op) result = PyObject_RichCompareBool(self->__name__, othername, Py_EQ); if (result == 0) { result = PyObject_RichCompareBool(self->__name__, othername, op); - } - else if (result == 1) { + } else if (result == 1) { result = PyObject_RichCompareBool(self->__module__, othermod, op); } // If either comparison failed, we have an error set. @@ -1021,7 +979,6 @@ IB_richcompare(IB* self, PyObject* other, int op) oresult = result ? Py_True : Py_False; - cleanup: Py_XINCREF(oresult); @@ -1030,18 +987,17 @@ IB_richcompare(IB* self, PyObject* other, int op) Py_XDECREF(othermod); } return oresult; - } static int IB_init(IB* self, PyObject* args, PyObject* kwargs) { - static char *kwlist[] = {"__name__", "__module__", NULL}; + static char* kwlist[] = { "__name__", "__module__", NULL }; PyObject* module = NULL; PyObject* name = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OO:InterfaceBase.__init__", kwlist, - &name, &module)) { + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "|OO:InterfaceBase.__init__", kwlist, &name, &module)) { return -1; } IB_clear(self); @@ -1052,46 +1008,45 @@ IB_init(IB* self, PyObject* args, PyObject* kwargs) return 0; } - static PyTypeObject InterfaceBaseType = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_zope_interface_coptimizations." - "InterfaceBase", - /* tp_basicsize */ sizeof(IB), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)IB_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)IB_hash, - /* tp_call */ (ternaryfunc)IB_call, - /* tp_str */ (reprfunc)0, - /* tp_getattro */ (getattrofunc)0, - /* tp_setattro */ (setattrofunc)0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - /* tp_doc */ "Interface base type providing __call__ and __adapt__", - /* tp_traverse */ (traverseproc)IB_traverse, - /* tp_clear */ (inquiry)IB_clear, - /* tp_richcompare */ (richcmpfunc)IB_richcompare, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ ib_methods, - /* tp_members */ IB_members, - /* tp_getset */ 0, - /* tp_base */ &SpecificationBaseType, - /* tp_dict */ 0, - /* tp_descr_get */ 0, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ (initproc)IB_init, + PyVarObject_HEAD_INIT(NULL, 0) + /* tp_name */ "_zope_interface_coptimizations." + "InterfaceBase", + /* tp_basicsize */ sizeof(IB), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor)IB_dealloc, + /* tp_print */ (printfunc)0, + /* tp_getattr */ (getattrfunc)0, + /* tp_setattr */ (setattrfunc)0, + /* tp_compare */ 0, + /* tp_repr */ (reprfunc)0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ (hashfunc)IB_hash, + /* tp_call */ (ternaryfunc)IB_call, + /* tp_str */ (reprfunc)0, + /* tp_getattro */ (getattrofunc)0, + /* tp_setattro */ (setattrofunc)0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + /* tp_doc */ "Interface base type providing __call__ and __adapt__", + /* tp_traverse */ (traverseproc)IB_traverse, + /* tp_clear */ (inquiry)IB_clear, + /* tp_richcompare */ (richcmpfunc)IB_richcompare, + /* tp_weaklistoffset */ (long)0, + /* tp_iter */ (getiterfunc)0, + /* tp_iternext */ (iternextfunc)0, + /* tp_methods */ ib_methods, + /* tp_members */ IB_members, + /* tp_getset */ 0, + /* tp_base */ &SpecificationBaseType, + /* tp_dict */ 0, + /* tp_descr_get */ 0, + /* tp_descr_set */ 0, + /* tp_dictoffset */ 0, + /* tp_init */ (initproc)IB_init, }; /* =================== End: __call__ and __adapt__ ==================== */ @@ -1100,63 +1055,65 @@ static PyTypeObject InterfaceBaseType = { /* ==================================================================== */ /* ========================== Begin: Lookup Bases ===================== */ -typedef struct { - PyObject_HEAD - PyObject *_cache; - PyObject *_mcache; - PyObject *_scache; +typedef struct +{ + PyObject_HEAD + PyObject* _cache; + PyObject* _mcache; + PyObject* _scache; } lookup; -typedef struct { - PyObject_HEAD - PyObject *_cache; - PyObject *_mcache; - PyObject *_scache; - PyObject *_verify_ro; - PyObject *_verify_generations; +typedef struct +{ + PyObject_HEAD + PyObject* _cache; + PyObject* _mcache; + PyObject* _scache; + PyObject* _verify_ro; + PyObject* _verify_generations; } verify; static int -lookup_traverse(lookup *self, visitproc visit, void *arg) +lookup_traverse(lookup* self, visitproc visit, void* arg) { - int vret; + int vret; - if (self->_cache) { - vret = visit(self->_cache, arg); - if (vret != 0) - return vret; - } + if (self->_cache) { + vret = visit(self->_cache, arg); + if (vret != 0) + return vret; + } - if (self->_mcache) { - vret = visit(self->_mcache, arg); - if (vret != 0) - return vret; - } + if (self->_mcache) { + vret = visit(self->_mcache, arg); + if (vret != 0) + return vret; + } - if (self->_scache) { - vret = visit(self->_scache, arg); - if (vret != 0) - return vret; - } + if (self->_scache) { + vret = visit(self->_scache, arg); + if (vret != 0) + return vret; + } - return 0; + return 0; } static int -lookup_clear(lookup *self) +lookup_clear(lookup* self) { - Py_CLEAR(self->_cache); - Py_CLEAR(self->_mcache); - Py_CLEAR(self->_scache); - return 0; + Py_CLEAR(self->_cache); + Py_CLEAR(self->_mcache); + Py_CLEAR(self->_scache); + return 0; } static void -lookup_dealloc(lookup *self) +lookup_dealloc(lookup* self) { - PyObject_GC_UnTrack((PyObject *)self); - lookup_clear(self); - Py_TYPE(self)->tp_free((PyObject*)self); + PyObject_GC_UnTrack((PyObject*)self); + lookup_clear(self); + Py_TYPE(self)->tp_free((PyObject*)self); } /* @@ -1165,17 +1122,20 @@ lookup_dealloc(lookup *self) self._mcache.clear() self._scache.clear() */ -static PyObject * -lookup_changed(lookup *self, PyObject *ignored) +static PyObject* +lookup_changed(lookup* self, PyObject* ignored) { - lookup_clear(self); - Py_INCREF(Py_None); - return Py_None; + lookup_clear(self); + Py_INCREF(Py_None); + return Py_None; } -#define ASSURE_DICT(N) if (N == NULL) { N = PyDict_New(); \ - if (N == NULL) return NULL; \ - } +#define ASSURE_DICT(N) \ + if (N == NULL) { \ + N = PyDict_New(); \ + if (N == NULL) \ + return NULL; \ + } /* def _getcache(self, provided, name): @@ -1191,44 +1151,42 @@ lookup_changed(lookup *self, PyObject *ignored) cache = c return cache */ -static PyObject * -_subcache(PyObject *cache, PyObject *key) +static PyObject* +_subcache(PyObject* cache, PyObject* key) { - PyObject *subcache; + PyObject* subcache; - subcache = PyDict_GetItem(cache, key); - if (subcache == NULL) - { - int status; + subcache = PyDict_GetItem(cache, key); + if (subcache == NULL) { + int status; - subcache = PyDict_New(); - if (subcache == NULL) - return NULL; - status = PyDict_SetItem(cache, key, subcache); - Py_DECREF(subcache); - if (status < 0) - return NULL; + subcache = PyDict_New(); + if (subcache == NULL) + return NULL; + status = PyDict_SetItem(cache, key, subcache); + Py_DECREF(subcache); + if (status < 0) + return NULL; } - return subcache; + return subcache; } -static PyObject * -_getcache(lookup *self, PyObject *provided, PyObject *name) +static PyObject* +_getcache(lookup* self, PyObject* provided, PyObject* name) { - PyObject *cache; + PyObject* cache; - ASSURE_DICT(self->_cache); - cache = _subcache(self->_cache, provided); - if (cache == NULL) - return NULL; + ASSURE_DICT(self->_cache); + cache = _subcache(self->_cache, provided); + if (cache == NULL) + return NULL; - if (name != NULL && PyObject_IsTrue(name)) - cache = _subcache(cache, name); + if (name != NULL && PyObject_IsTrue(name)) + cache = _subcache(cache, name); - return cache; + return cache; } - /* def lookup(self, required, provided, name=u'', default=None): cache = self._getcache(provided, name) @@ -1250,86 +1208,84 @@ _getcache(lookup *self, PyObject *provided, PyObject *name) return result */ -static PyObject * -_lookup(lookup *self, - PyObject *required, PyObject *provided, PyObject *name, - PyObject *default_) -{ - PyObject *result, *key, *cache; - result = key = cache = NULL; - if ( name && !PyUnicode_Check(name) ) - { - PyErr_SetString(PyExc_ValueError, - "name is not a string or unicode"); - return NULL; - } +static PyObject* +_lookup(lookup* self, + PyObject* required, + PyObject* provided, + PyObject* name, + PyObject* default_) +{ + PyObject *result, *key, *cache; + result = key = cache = NULL; + if (name && !PyUnicode_Check(name)) { + PyErr_SetString(PyExc_ValueError, "name is not a string or unicode"); + return NULL; + } - /* If `required` is a lazy sequence, it could have arbitrary side-effects, - such as clearing our caches. So we must not retrieve the cache until - after resolving it. */ - required = PySequence_Tuple(required); - if (required == NULL) - return NULL; + /* If `required` is a lazy sequence, it could have arbitrary side-effects, + such as clearing our caches. So we must not retrieve the cache until + after resolving it. */ + required = PySequence_Tuple(required); + if (required == NULL) + return NULL; + cache = _getcache(self, provided, name); + if (cache == NULL) + return NULL; - cache = _getcache(self, provided, name); - if (cache == NULL) - return NULL; + if (PyTuple_GET_SIZE(required) == 1) + key = PyTuple_GET_ITEM(required, 0); + else + key = required; - if (PyTuple_GET_SIZE(required) == 1) - key = PyTuple_GET_ITEM(required, 0); - else - key = required; - - result = PyDict_GetItem(cache, key); - if (result == NULL) - { - int status; - - result = PyObject_CallMethodObjArgs(OBJECT(self), str_uncached_lookup, - required, provided, name, NULL); - if (result == NULL) - { - Py_DECREF(required); - return NULL; + result = PyDict_GetItem(cache, key); + if (result == NULL) { + int status; + + result = PyObject_CallMethodObjArgs( + OBJECT(self), str_uncached_lookup, required, provided, name, NULL); + if (result == NULL) { + Py_DECREF(required); + return NULL; } - status = PyDict_SetItem(cache, key, result); - Py_DECREF(required); - if (status < 0) - { - Py_DECREF(result); - return NULL; + status = PyDict_SetItem(cache, key, result); + Py_DECREF(required); + if (status < 0) { + Py_DECREF(result); + return NULL; } - } - else - { - Py_INCREF(result); - Py_DECREF(required); + } else { + Py_INCREF(result); + Py_DECREF(required); } - if (result == Py_None && default_ != NULL) - { - Py_DECREF(Py_None); - Py_INCREF(default_); - return default_; + if (result == Py_None && default_ != NULL) { + Py_DECREF(Py_None); + Py_INCREF(default_); + return default_; } - return result; + return result; } -static PyObject * -lookup_lookup(lookup *self, PyObject *args, PyObject *kwds) +static PyObject* +lookup_lookup(lookup* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", "name", "default", NULL}; - PyObject *required, *provided, *name=NULL, *default_=NULL; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO:LookupBase.lookup", kwlist, - &required, &provided, &name, &default_)) - return NULL; + static char* kwlist[] = { "required", "provided", "name", "default", NULL }; + PyObject *required, *provided, *name = NULL, *default_ = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, + kwds, + "OO|OO:LookupBase.lookup", + kwlist, + &required, + &provided, + &name, + &default_)) + return NULL; - return _lookup(self, required, provided, name, default_); + return _lookup(self, required, provided, name, default_); } - /* def lookup1(self, required, provided, name=u'', default=None): cache = self._getcache(provided, name) @@ -1342,59 +1298,61 @@ lookup_lookup(lookup *self, PyObject *args, PyObject *kwds) return result */ -static PyObject * -_lookup1(lookup *self, - PyObject *required, PyObject *provided, PyObject *name, - PyObject *default_) +static PyObject* +_lookup1(lookup* self, + PyObject* required, + PyObject* provided, + PyObject* name, + PyObject* default_) { - PyObject *result, *cache; + PyObject *result, *cache; - if ( name && !PyUnicode_Check(name) ) - { - PyErr_SetString(PyExc_ValueError, - "name is not a string or unicode"); - return NULL; - } + if (name && !PyUnicode_Check(name)) { + PyErr_SetString(PyExc_ValueError, "name is not a string or unicode"); + return NULL; + } - cache = _getcache(self, provided, name); - if (cache == NULL) - return NULL; + cache = _getcache(self, provided, name); + if (cache == NULL) + return NULL; - result = PyDict_GetItem(cache, required); - if (result == NULL) - { - PyObject *tup; + result = PyDict_GetItem(cache, required); + if (result == NULL) { + PyObject* tup; - tup = PyTuple_New(1); - if (tup == NULL) - return NULL; - Py_INCREF(required); - PyTuple_SET_ITEM(tup, 0, required); - result = _lookup(self, tup, provided, name, default_); - Py_DECREF(tup); - } - else - { - if (result == Py_None && default_ != NULL) - { - result = default_; + tup = PyTuple_New(1); + if (tup == NULL) + return NULL; + Py_INCREF(required); + PyTuple_SET_ITEM(tup, 0, required); + result = _lookup(self, tup, provided, name, default_); + Py_DECREF(tup); + } else { + if (result == Py_None && default_ != NULL) { + result = default_; } - Py_INCREF(result); + Py_INCREF(result); } - return result; + return result; } -static PyObject * -lookup_lookup1(lookup *self, PyObject *args, PyObject *kwds) +static PyObject* +lookup_lookup1(lookup* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", "name", "default", NULL}; - PyObject *required, *provided, *name=NULL, *default_=NULL; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO:LookupBase.lookup1", kwlist, - &required, &provided, &name, &default_)) - return NULL; + static char* kwlist[] = { "required", "provided", "name", "default", NULL }; + PyObject *required, *provided, *name = NULL, *default_ = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, + kwds, + "OO|OO:LookupBase.lookup1", + kwlist, + &required, + &provided, + &name, + &default_)) + return NULL; - return _lookup1(self, required, provided, name, default_); + return _lookup1(self, required, provided, name, default_); } /* @@ -1414,82 +1372,91 @@ lookup_lookup1(lookup *self, PyObject *args, PyObject *kwds) return default */ -static PyObject * -_adapter_hook(lookup *self, - PyObject *provided, PyObject *object, PyObject *name, - PyObject *default_) +static PyObject* +_adapter_hook(lookup* self, + PyObject* provided, + PyObject* object, + PyObject* name, + PyObject* default_) { - PyObject *required, *factory, *result; + PyObject *required, *factory, *result; - if ( name && !PyUnicode_Check(name) ) - { - PyErr_SetString(PyExc_ValueError, - "name is not a string or unicode"); - return NULL; - } + if (name && !PyUnicode_Check(name)) { + PyErr_SetString(PyExc_ValueError, "name is not a string or unicode"); + return NULL; + } - required = providedBy(NULL, object); - if (required == NULL) - return NULL; + required = providedBy(NULL, object); + if (required == NULL) + return NULL; - factory = _lookup1(self, required, provided, name, Py_None); - Py_DECREF(required); - if (factory == NULL) - return NULL; + factory = _lookup1(self, required, provided, name, Py_None); + Py_DECREF(required); + if (factory == NULL) + return NULL; - if (factory != Py_None) - { - if (PyObject_TypeCheck(object, &PySuper_Type)) { - PyObject* self = PyObject_GetAttr(object, str__self__); - if (self == NULL) - { - Py_DECREF(factory); - return NULL; - } - // Borrow the reference to self - Py_DECREF(self); - object = self; - } - result = PyObject_CallFunctionObjArgs(factory, object, NULL); - Py_DECREF(factory); - if (result == NULL || result != Py_None) - return result; - } - else - result = factory; /* None */ + if (factory != Py_None) { + if (PyObject_TypeCheck(object, &PySuper_Type)) { + PyObject* self = PyObject_GetAttr(object, str__self__); + if (self == NULL) { + Py_DECREF(factory); + return NULL; + } + // Borrow the reference to self + Py_DECREF(self); + object = self; + } + result = PyObject_CallFunctionObjArgs(factory, object, NULL); + Py_DECREF(factory); + if (result == NULL || result != Py_None) + return result; + } else + result = factory; /* None */ - if (default_ == NULL || default_ == result) /* No default specified, */ - return result; /* Return None. result is owned None */ + if (default_ == NULL || default_ == result) /* No default specified, */ + return result; /* Return None. result is owned None */ - Py_DECREF(result); - Py_INCREF(default_); + Py_DECREF(result); + Py_INCREF(default_); - return default_; + return default_; } -static PyObject * -lookup_adapter_hook(lookup *self, PyObject *args, PyObject *kwds) +static PyObject* +lookup_adapter_hook(lookup* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"provided", "object", "name", "default", NULL}; - PyObject *object, *provided, *name=NULL, *default_=NULL; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO:LookupBase.adapter_hook", kwlist, - &provided, &object, &name, &default_)) - return NULL; + static char* kwlist[] = { "provided", "object", "name", "default", NULL }; + PyObject *object, *provided, *name = NULL, *default_ = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, + kwds, + "OO|OO:LookupBase.adapter_hook", + kwlist, + &provided, + &object, + &name, + &default_)) + return NULL; - return _adapter_hook(self, provided, object, name, default_); + return _adapter_hook(self, provided, object, name, default_); } -static PyObject * -lookup_queryAdapter(lookup *self, PyObject *args, PyObject *kwds) +static PyObject* +lookup_queryAdapter(lookup* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"object", "provided", "name", "default", NULL}; - PyObject *object, *provided, *name=NULL, *default_=NULL; - - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO:LookupBase.queryAdapter", kwlist, - &object, &provided, &name, &default_)) - return NULL; + static char* kwlist[] = { "object", "provided", "name", "default", NULL }; + PyObject *object, *provided, *name = NULL, *default_ = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, + kwds, + "OO|OO:LookupBase.queryAdapter", + kwlist, + &object, + &provided, + &name, + &default_)) + return NULL; - return _adapter_hook(self, provided, object, name, default_); + return _adapter_hook(self, provided, object, name, default_); } /* @@ -1507,60 +1474,55 @@ lookup_queryAdapter(lookup *self, PyObject *args, PyObject *kwds) return result */ -static PyObject * -_lookupAll(lookup *self, PyObject *required, PyObject *provided) +static PyObject* +_lookupAll(lookup* self, PyObject* required, PyObject* provided) { - PyObject *cache, *result; + PyObject *cache, *result; - /* resolve before getting cache. See note in _lookup. */ - required = PySequence_Tuple(required); - if (required == NULL) - return NULL; + /* resolve before getting cache. See note in _lookup. */ + required = PySequence_Tuple(required); + if (required == NULL) + return NULL; - ASSURE_DICT(self->_mcache); - cache = _subcache(self->_mcache, provided); - if (cache == NULL) - return NULL; + ASSURE_DICT(self->_mcache); + cache = _subcache(self->_mcache, provided); + if (cache == NULL) + return NULL; - result = PyDict_GetItem(cache, required); - if (result == NULL) - { - int status; - - result = PyObject_CallMethodObjArgs(OBJECT(self), str_uncached_lookupAll, - required, provided, NULL); - if (result == NULL) - { - Py_DECREF(required); - return NULL; + result = PyDict_GetItem(cache, required); + if (result == NULL) { + int status; + + result = PyObject_CallMethodObjArgs( + OBJECT(self), str_uncached_lookupAll, required, provided, NULL); + if (result == NULL) { + Py_DECREF(required); + return NULL; } - status = PyDict_SetItem(cache, required, result); - Py_DECREF(required); - if (status < 0) - { - Py_DECREF(result); - return NULL; + status = PyDict_SetItem(cache, required, result); + Py_DECREF(required); + if (status < 0) { + Py_DECREF(result); + return NULL; } - } - else - { - Py_INCREF(result); - Py_DECREF(required); + } else { + Py_INCREF(result); + Py_DECREF(required); } - return result; + return result; } -static PyObject * -lookup_lookupAll(lookup *self, PyObject *args, PyObject *kwds) +static PyObject* +lookup_lookupAll(lookup* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", NULL}; - PyObject *required, *provided; + static char* kwlist[] = { "required", "provided", NULL }; + PyObject *required, *provided; - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO:LookupBase.lookupAll", kwlist, - &required, &provided)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO:LookupBase.lookupAll", kwlist, &required, &provided)) + return NULL; - return _lookupAll(self, required, provided); + return _lookupAll(self, required, provided); } /* @@ -1578,147 +1540,154 @@ lookup_lookupAll(lookup *self, PyObject *args, PyObject *kwds) return result */ -static PyObject * -_subscriptions(lookup *self, PyObject *required, PyObject *provided) +static PyObject* +_subscriptions(lookup* self, PyObject* required, PyObject* provided) { - PyObject *cache, *result; + PyObject *cache, *result; - /* resolve before getting cache. See note in _lookup. */ - required = PySequence_Tuple(required); - if (required == NULL) - return NULL; + /* resolve before getting cache. See note in _lookup. */ + required = PySequence_Tuple(required); + if (required == NULL) + return NULL; - ASSURE_DICT(self->_scache); - cache = _subcache(self->_scache, provided); - if (cache == NULL) - return NULL; + ASSURE_DICT(self->_scache); + cache = _subcache(self->_scache, provided); + if (cache == NULL) + return NULL; + + result = PyDict_GetItem(cache, required); + if (result == NULL) { + int status; - result = PyDict_GetItem(cache, required); - if (result == NULL) - { - int status; - - result = PyObject_CallMethodObjArgs( - OBJECT(self), str_uncached_subscriptions, - required, provided, NULL); - if (result == NULL) - { - Py_DECREF(required); - return NULL; + result = PyObject_CallMethodObjArgs( + OBJECT(self), str_uncached_subscriptions, required, provided, NULL); + if (result == NULL) { + Py_DECREF(required); + return NULL; } - status = PyDict_SetItem(cache, required, result); - Py_DECREF(required); - if (status < 0) - { - Py_DECREF(result); - return NULL; + status = PyDict_SetItem(cache, required, result); + Py_DECREF(required); + if (status < 0) { + Py_DECREF(result); + return NULL; } - } - else - { - Py_INCREF(result); - Py_DECREF(required); + } else { + Py_INCREF(result); + Py_DECREF(required); } - return result; + return result; } -static PyObject * -lookup_subscriptions(lookup *self, PyObject *args, PyObject *kwds) +static PyObject* +lookup_subscriptions(lookup* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", NULL}; - PyObject *required, *provided; + static char* kwlist[] = { "required", "provided", NULL }; + PyObject *required, *provided; - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, - &required, &provided)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO", kwlist, &required, &provided)) + return NULL; - return _subscriptions(self, required, provided); + return _subscriptions(self, required, provided); } static struct PyMethodDef lookup_methods[] = { - {"changed", (PyCFunction)lookup_changed, METH_O, ""}, - {"lookup", (PyCFunction)lookup_lookup, METH_KEYWORDS | METH_VARARGS, ""}, - {"lookup1", (PyCFunction)lookup_lookup1, METH_KEYWORDS | METH_VARARGS, ""}, - {"queryAdapter", (PyCFunction)lookup_queryAdapter, METH_KEYWORDS | METH_VARARGS, ""}, - {"adapter_hook", (PyCFunction)lookup_adapter_hook, METH_KEYWORDS | METH_VARARGS, ""}, - {"lookupAll", (PyCFunction)lookup_lookupAll, METH_KEYWORDS | METH_VARARGS, ""}, - {"subscriptions", (PyCFunction)lookup_subscriptions, METH_KEYWORDS | METH_VARARGS, ""}, - {NULL, NULL} /* sentinel */ + { "changed", (PyCFunction)lookup_changed, METH_O, "" }, + { "lookup", (PyCFunction)lookup_lookup, METH_KEYWORDS | METH_VARARGS, "" }, + { "lookup1", + (PyCFunction)lookup_lookup1, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "queryAdapter", + (PyCFunction)lookup_queryAdapter, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "adapter_hook", + (PyCFunction)lookup_adapter_hook, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "lookupAll", + (PyCFunction)lookup_lookupAll, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "subscriptions", + (PyCFunction)lookup_subscriptions, + METH_KEYWORDS | METH_VARARGS, + "" }, + { NULL, NULL } /* sentinel */ }; static PyTypeObject LookupBase = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_zope_interface_coptimizations." - "LookupBase", - /* tp_basicsize */ sizeof(lookup), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)&lookup_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)0, - /* tp_call */ (ternaryfunc)0, - /* tp_str */ (reprfunc)0, - /* tp_getattro */ (getattrofunc)0, - /* tp_setattro */ (setattrofunc)0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, - /* tp_doc */ "", - /* tp_traverse */ (traverseproc)lookup_traverse, - /* tp_clear */ (inquiry)lookup_clear, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ lookup_methods, + PyVarObject_HEAD_INIT(NULL, 0) + /* tp_name */ "_zope_interface_coptimizations." + "LookupBase", + /* tp_basicsize */ sizeof(lookup), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor)&lookup_dealloc, + /* tp_print */ (printfunc)0, + /* tp_getattr */ (getattrfunc)0, + /* tp_setattr */ (setattrfunc)0, + /* tp_compare */ 0, + /* tp_repr */ (reprfunc)0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ (hashfunc)0, + /* tp_call */ (ternaryfunc)0, + /* tp_str */ (reprfunc)0, + /* tp_getattro */ (getattrofunc)0, + /* tp_setattro */ (setattrofunc)0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + /* tp_doc */ "", + /* tp_traverse */ (traverseproc)lookup_traverse, + /* tp_clear */ (inquiry)lookup_clear, + /* tp_richcompare */ (richcmpfunc)0, + /* tp_weaklistoffset */ (long)0, + /* tp_iter */ (getiterfunc)0, + /* tp_iternext */ (iternextfunc)0, + /* tp_methods */ lookup_methods, }; static int -verifying_traverse(verify *self, visitproc visit, void *arg) +verifying_traverse(verify* self, visitproc visit, void* arg) { - int vret; - - vret = lookup_traverse((lookup *)self, visit, arg); - if (vret != 0) - return vret; + int vret; - if (self->_verify_ro) { - vret = visit(self->_verify_ro, arg); - if (vret != 0) - return vret; - } - if (self->_verify_generations) { - vret = visit(self->_verify_generations, arg); + vret = lookup_traverse((lookup*)self, visit, arg); if (vret != 0) - return vret; - } + return vret; - return 0; + if (self->_verify_ro) { + vret = visit(self->_verify_ro, arg); + if (vret != 0) + return vret; + } + if (self->_verify_generations) { + vret = visit(self->_verify_generations, arg); + if (vret != 0) + return vret; + } + + return 0; } static int -verifying_clear(verify *self) +verifying_clear(verify* self) { - lookup_clear((lookup *)self); - Py_CLEAR(self->_verify_generations); - Py_CLEAR(self->_verify_ro); - return 0; + lookup_clear((lookup*)self); + Py_CLEAR(self->_verify_generations); + Py_CLEAR(self->_verify_ro); + return 0; } - static void -verifying_dealloc(verify *self) +verifying_dealloc(verify* self) { - PyObject_GC_UnTrack((PyObject *)self); - verifying_clear(self); - Py_TYPE(self)->tp_free((PyObject*)self); + PyObject_GC_UnTrack((PyObject*)self); + verifying_clear(self); + Py_TYPE(self)->tp_free((PyObject*)self); } /* @@ -1727,65 +1696,62 @@ verifying_dealloc(verify *self) self._verify_ro = self._registry.ro[1:] self._verify_generations = [r._generation for r in self._verify_ro] */ -static PyObject * -_generations_tuple(PyObject *ro) -{ - int i, l; - PyObject *generations; - - l = PyTuple_GET_SIZE(ro); - generations = PyTuple_New(l); - for (i=0; i < l; i++) - { - PyObject *generation; - - generation = PyObject_GetAttr(PyTuple_GET_ITEM(ro, i), str_generation); - if (generation == NULL) - { - Py_DECREF(generations); - return NULL; +static PyObject* +_generations_tuple(PyObject* ro) +{ + int i, l; + PyObject* generations; + + l = PyTuple_GET_SIZE(ro); + generations = PyTuple_New(l); + for (i = 0; i < l; i++) { + PyObject* generation; + + generation = PyObject_GetAttr(PyTuple_GET_ITEM(ro, i), str_generation); + if (generation == NULL) { + Py_DECREF(generations); + return NULL; } - PyTuple_SET_ITEM(generations, i, generation); + PyTuple_SET_ITEM(generations, i, generation); } - return generations; + return generations; } -static PyObject * -verifying_changed(verify *self, PyObject *ignored) +static PyObject* +verifying_changed(verify* self, PyObject* ignored) { - PyObject *t, *ro; + PyObject *t, *ro; - verifying_clear(self); + verifying_clear(self); - t = PyObject_GetAttr(OBJECT(self), str_registry); - if (t == NULL) - return NULL; - ro = PyObject_GetAttr(t, strro); - Py_DECREF(t); - if (ro == NULL) - return NULL; + t = PyObject_GetAttr(OBJECT(self), str_registry); + if (t == NULL) + return NULL; + ro = PyObject_GetAttr(t, strro); + Py_DECREF(t); + if (ro == NULL) + return NULL; - t = PyObject_CallFunctionObjArgs(OBJECT(&PyTuple_Type), ro, NULL); - Py_DECREF(ro); - if (t == NULL) - return NULL; + t = PyObject_CallFunctionObjArgs(OBJECT(&PyTuple_Type), ro, NULL); + Py_DECREF(ro); + if (t == NULL) + return NULL; - ro = PyTuple_GetSlice(t, 1, PyTuple_GET_SIZE(t)); - Py_DECREF(t); - if (ro == NULL) - return NULL; + ro = PyTuple_GetSlice(t, 1, PyTuple_GET_SIZE(t)); + Py_DECREF(t); + if (ro == NULL) + return NULL; - self->_verify_generations = _generations_tuple(ro); - if (self->_verify_generations == NULL) - { - Py_DECREF(ro); - return NULL; + self->_verify_generations = _generations_tuple(ro); + if (self->_verify_generations == NULL) { + Py_DECREF(ro); + return NULL; } - self->_verify_ro = ro; + self->_verify_ro = ro; - Py_INCREF(Py_None); - return Py_None; + Py_INCREF(Py_None); + return Py_None; } /* @@ -1795,180 +1761,196 @@ verifying_changed(verify *self, PyObject *ignored) self.changed(None) */ static int -_verify(verify *self) +_verify(verify* self) { - PyObject *changed_result; + PyObject* changed_result; - if (self->_verify_ro != NULL && self->_verify_generations != NULL) - { - PyObject *generations; - int changed; + if (self->_verify_ro != NULL && self->_verify_generations != NULL) { + PyObject* generations; + int changed; - generations = _generations_tuple(self->_verify_ro); - if (generations == NULL) - return -1; + generations = _generations_tuple(self->_verify_ro); + if (generations == NULL) + return -1; - changed = PyObject_RichCompareBool(self->_verify_generations, - generations, Py_NE); - Py_DECREF(generations); - if (changed == -1) - return -1; + changed = PyObject_RichCompareBool( + self->_verify_generations, generations, Py_NE); + Py_DECREF(generations); + if (changed == -1) + return -1; - if (changed == 0) - return 0; + if (changed == 0) + return 0; } - changed_result = PyObject_CallMethodObjArgs(OBJECT(self), strchanged, - Py_None, NULL); - if (changed_result == NULL) - return -1; + changed_result = + PyObject_CallMethodObjArgs(OBJECT(self), strchanged, Py_None, NULL); + if (changed_result == NULL) + return -1; - Py_DECREF(changed_result); - return 0; + Py_DECREF(changed_result); + return 0; } -static PyObject * -verifying_lookup(verify *self, PyObject *args, PyObject *kwds) +static PyObject* +verifying_lookup(verify* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", "name", "default", NULL}; - PyObject *required, *provided, *name=NULL, *default_=NULL; + static char* kwlist[] = { "required", "provided", "name", "default", NULL }; + PyObject *required, *provided, *name = NULL, *default_ = NULL; - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist, - &required, &provided, &name, &default_)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO|OO", kwlist, &required, &provided, &name, &default_)) + return NULL; - if (_verify(self) < 0) - return NULL; + if (_verify(self) < 0) + return NULL; - return _lookup((lookup *)self, required, provided, name, default_); + return _lookup((lookup*)self, required, provided, name, default_); } -static PyObject * -verifying_lookup1(verify *self, PyObject *args, PyObject *kwds) +static PyObject* +verifying_lookup1(verify* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", "name", "default", NULL}; - PyObject *required, *provided, *name=NULL, *default_=NULL; + static char* kwlist[] = { "required", "provided", "name", "default", NULL }; + PyObject *required, *provided, *name = NULL, *default_ = NULL; - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist, - &required, &provided, &name, &default_)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO|OO", kwlist, &required, &provided, &name, &default_)) + return NULL; - if (_verify(self) < 0) - return NULL; + if (_verify(self) < 0) + return NULL; - return _lookup1((lookup *)self, required, provided, name, default_); + return _lookup1((lookup*)self, required, provided, name, default_); } -static PyObject * -verifying_adapter_hook(verify *self, PyObject *args, PyObject *kwds) +static PyObject* +verifying_adapter_hook(verify* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"provided", "object", "name", "default", NULL}; - PyObject *object, *provided, *name=NULL, *default_=NULL; + static char* kwlist[] = { "provided", "object", "name", "default", NULL }; + PyObject *object, *provided, *name = NULL, *default_ = NULL; - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist, - &provided, &object, &name, &default_)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO|OO", kwlist, &provided, &object, &name, &default_)) + return NULL; - if (_verify(self) < 0) - return NULL; + if (_verify(self) < 0) + return NULL; - return _adapter_hook((lookup *)self, provided, object, name, default_); + return _adapter_hook((lookup*)self, provided, object, name, default_); } -static PyObject * -verifying_queryAdapter(verify *self, PyObject *args, PyObject *kwds) +static PyObject* +verifying_queryAdapter(verify* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"object", "provided", "name", "default", NULL}; - PyObject *object, *provided, *name=NULL, *default_=NULL; + static char* kwlist[] = { "object", "provided", "name", "default", NULL }; + PyObject *object, *provided, *name = NULL, *default_ = NULL; - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO|OO", kwlist, - &object, &provided, &name, &default_)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO|OO", kwlist, &object, &provided, &name, &default_)) + return NULL; - if (_verify(self) < 0) - return NULL; + if (_verify(self) < 0) + return NULL; - return _adapter_hook((lookup *)self, provided, object, name, default_); + return _adapter_hook((lookup*)self, provided, object, name, default_); } -static PyObject * -verifying_lookupAll(verify *self, PyObject *args, PyObject *kwds) +static PyObject* +verifying_lookupAll(verify* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", NULL}; - PyObject *required, *provided; + static char* kwlist[] = { "required", "provided", NULL }; + PyObject *required, *provided; - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, - &required, &provided)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO", kwlist, &required, &provided)) + return NULL; - if (_verify(self) < 0) - return NULL; + if (_verify(self) < 0) + return NULL; - return _lookupAll((lookup *)self, required, provided); + return _lookupAll((lookup*)self, required, provided); } -static PyObject * -verifying_subscriptions(verify *self, PyObject *args, PyObject *kwds) +static PyObject* +verifying_subscriptions(verify* self, PyObject* args, PyObject* kwds) { - static char *kwlist[] = {"required", "provided", NULL}; - PyObject *required, *provided; + static char* kwlist[] = { "required", "provided", NULL }; + PyObject *required, *provided; - if (! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, - &required, &provided)) - return NULL; + if (!PyArg_ParseTupleAndKeywords( + args, kwds, "OO", kwlist, &required, &provided)) + return NULL; - if (_verify(self) < 0) - return NULL; + if (_verify(self) < 0) + return NULL; - return _subscriptions((lookup *)self, required, provided); + return _subscriptions((lookup*)self, required, provided); } static struct PyMethodDef verifying_methods[] = { - {"changed", (PyCFunction)verifying_changed, METH_O, ""}, - {"lookup", (PyCFunction)verifying_lookup, METH_KEYWORDS | METH_VARARGS, ""}, - {"lookup1", (PyCFunction)verifying_lookup1, METH_KEYWORDS | METH_VARARGS, ""}, - {"queryAdapter", (PyCFunction)verifying_queryAdapter, METH_KEYWORDS | METH_VARARGS, ""}, - {"adapter_hook", (PyCFunction)verifying_adapter_hook, METH_KEYWORDS | METH_VARARGS, ""}, - {"lookupAll", (PyCFunction)verifying_lookupAll, METH_KEYWORDS | METH_VARARGS, ""}, - {"subscriptions", (PyCFunction)verifying_subscriptions, METH_KEYWORDS | METH_VARARGS, ""}, - {NULL, NULL} /* sentinel */ + { "changed", (PyCFunction)verifying_changed, METH_O, "" }, + { "lookup", + (PyCFunction)verifying_lookup, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "lookup1", + (PyCFunction)verifying_lookup1, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "queryAdapter", + (PyCFunction)verifying_queryAdapter, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "adapter_hook", + (PyCFunction)verifying_adapter_hook, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "lookupAll", + (PyCFunction)verifying_lookupAll, + METH_KEYWORDS | METH_VARARGS, + "" }, + { "subscriptions", + (PyCFunction)verifying_subscriptions, + METH_KEYWORDS | METH_VARARGS, + "" }, + { NULL, NULL } /* sentinel */ }; static PyTypeObject VerifyingBase = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_zope_interface_coptimizations." - "VerifyingBase", - /* tp_basicsize */ sizeof(verify), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)&verifying_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)0, - /* tp_call */ (ternaryfunc)0, - /* tp_str */ (reprfunc)0, - /* tp_getattro */ (getattrofunc)0, - /* tp_setattro */ (setattrofunc)0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT - | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, - /* tp_doc */ "", - /* tp_traverse */ (traverseproc)verifying_traverse, - /* tp_clear */ (inquiry)verifying_clear, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ verifying_methods, - /* tp_members */ 0, - /* tp_getset */ 0, - /* tp_base */ &LookupBase, + PyVarObject_HEAD_INIT(NULL, 0) + /* tp_name */ "_zope_interface_coptimizations." + "VerifyingBase", + /* tp_basicsize */ sizeof(verify), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor)&verifying_dealloc, + /* tp_print */ (printfunc)0, + /* tp_getattr */ (getattrfunc)0, + /* tp_setattr */ (setattrfunc)0, + /* tp_compare */ 0, + /* tp_repr */ (reprfunc)0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ (hashfunc)0, + /* tp_call */ (ternaryfunc)0, + /* tp_str */ (reprfunc)0, + /* tp_getattro */ (getattrofunc)0, + /* tp_setattro */ (setattrofunc)0, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, + /* tp_doc */ "", + /* tp_traverse */ (traverseproc)verifying_traverse, + /* tp_clear */ (inquiry)verifying_clear, + /* tp_richcompare */ (richcmpfunc)0, + /* tp_weaklistoffset */ (long)0, + /* tp_iter */ (getiterfunc)0, + /* tp_iternext */ (iternextfunc)0, + /* tp_methods */ verifying_methods, + /* tp_members */ 0, + /* tp_getset */ 0, + /* tp_base */ &LookupBase, }; /* ========================== End: Lookup Bases ======================= */ @@ -1977,25 +1959,26 @@ static PyTypeObject VerifyingBase = { /* * Module state struct: holds all data formerly kept as static globals. */ -typedef struct { +typedef struct +{ /* our globals (exposed to Python) */ - PyTypeObject* specification_base_class; - PyTypeObject* object_specification_descriptor_class; - PyTypeObject* class_provides_base_class; - PyTypeObject* interface_base_class; - PyTypeObject* lookup_base_class; - PyTypeObject* verifying_base_class; - PyObject* adapter_hooks; + PyTypeObject* specification_base_class; + PyTypeObject* object_specification_descriptor_class; + PyTypeObject* class_provides_base_class; + PyTypeObject* interface_base_class; + PyTypeObject* lookup_base_class; + PyTypeObject* verifying_base_class; + PyObject* adapter_hooks; /* members importe from 'zope.interface.declarations' */ - PyObject* empty; - PyObject* fallback; - PyObject* builtin_impl_specs; - PyTypeObject* implements_class; + PyObject* empty; + PyObject* fallback; + PyObject* builtin_impl_specs; + PyTypeObject* implements_class; /* flag: have we importe the next set of members yet from * 'zope.interface.declarations? */ - int decl_imported; + int decl_imported; } _zic_module_state; /* @@ -2047,9 +2030,9 @@ _zic_state_traverse(PyObject* module, visitproc visit, void* arg) } static int -_zic_state_clear(PyObject *module) +_zic_state_clear(PyObject* module) { - _zic_module_state *rec = _zic_state(module); + _zic_module_state* rec = _zic_state(module); Py_CLEAR(rec->specification_base_class); Py_CLEAR(rec->object_specification_descriptor_class); @@ -2070,40 +2053,46 @@ _zic_state_clear(PyObject *module) static _zic_module_state* _zic_state_load_declarations(PyObject* module) { - PyObject *declarations; - PyObject *builtin_impl_specs; - PyObject *empty; - PyObject *fallback; - PyObject *implements; + PyObject* declarations; + PyObject* builtin_impl_specs; + PyObject* empty; + PyObject* fallback; + PyObject* implements; - _zic_module_state *rec = _zic_state(module); + _zic_module_state* rec = _zic_state(module); - if (! rec->decl_imported) - { + if (!rec->decl_imported) { declarations = PyImport_ImportModule("zope.interface.declarations"); - if (declarations == NULL) { return NULL; } + if (declarations == NULL) { + return NULL; + } builtin_impl_specs = PyObject_GetAttrString( - declarations, "BuiltinImplementationSpecifications" - ); - if (builtin_impl_specs == NULL) { return NULL; } + declarations, "BuiltinImplementationSpecifications"); + if (builtin_impl_specs == NULL) { + return NULL; + } empty = PyObject_GetAttrString(declarations, "_empty"); - if (empty == NULL) { return NULL; } + if (empty == NULL) { + return NULL; + } - fallback = PyObject_GetAttrString( - declarations, "implementedByFallback"); - if (fallback == NULL) { return NULL; } + fallback = + PyObject_GetAttrString(declarations, "implementedByFallback"); + if (fallback == NULL) { + return NULL; + } implements = PyObject_GetAttrString(declarations, "Implements"); - if (implements == NULL) { return NULL; } + if (implements == NULL) { + return NULL; + } - if (! PyType_Check(implements)) - { + if (!PyType_Check(implements)) { PyErr_SetString( - PyExc_TypeError, - "zope.interface.declarations.Implements is not a type" - ); + PyExc_TypeError, + "zope.interface.declarations.Implements is not a type"); return NULL; } @@ -2118,54 +2107,48 @@ _zic_state_load_declarations(PyObject* module) return rec; } -static char implementedBy___doc__[] = ( - "Interfaces implemented by a class or factory.\n" - "Raises TypeError if argument is neither a class nor a callable." -); -static char getObjectSpecification___doc__[] = ( - "Get an object's interfaces (internal api)" -); -static char providedBy___doc__[] = ( - "Get an object's interfaces" -); +static char implementedBy___doc__[] = + ("Interfaces implemented by a class or factory.\n" + "Raises TypeError if argument is neither a class nor a callable."); +static char getObjectSpecification___doc__[] = + ("Get an object's interfaces (internal api)"); +static char providedBy___doc__[] = ("Get an object's interfaces"); static struct PyMethodDef m_methods[] = { - {"implementedBy", - (PyCFunction)implementedBy, METH_O, - implementedBy___doc__ - }, - {"getObjectSpecification", - (PyCFunction)getObjectSpecification, METH_O, - getObjectSpecification___doc__ - }, - {"providedBy", - (PyCFunction)providedBy, METH_O, - providedBy___doc__ - }, - - {NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */ + { "implementedBy", + (PyCFunction)implementedBy, + METH_O, + implementedBy___doc__ }, + { "getObjectSpecification", + (PyCFunction)getObjectSpecification, + METH_O, + getObjectSpecification___doc__ }, + { "providedBy", (PyCFunction)providedBy, METH_O, providedBy___doc__ }, + + { NULL, (PyCFunction)NULL, 0, NULL } /* sentinel */ }; static char module_doc[] = "C optimizations for zope.interface\n\n"; static struct PyModuleDef _zic_module = { PyModuleDef_HEAD_INIT, - .m_name="_zope_interface_coptimizations", - .m_doc=module_doc, - .m_size=sizeof(_zic_module_state), - .m_methods=m_methods, + .m_name = "_zope_interface_coptimizations", + .m_doc = module_doc, + .m_size = sizeof(_zic_module_state), + .m_methods = m_methods, /*.m_slots=m_slots,*/ - .m_traverse=_zic_state_traverse, - .m_clear=_zic_state_clear, + .m_traverse = _zic_state_traverse, + .m_clear = _zic_state_clear, }; -static PyObject * +static PyObject* init(void) { - PyObject *module; + PyObject* module; -#define DEFINE_STRING(S) \ - if(! (str ## S = PyUnicode_FromString(# S))) return NULL +#define DEFINE_STRING(S) \ + if (!(str##S = PyUnicode_FromString(#S))) \ + return NULL DEFINE_STRING(__dict__); DEFINE_STRING(__implemented__); @@ -2204,7 +2187,7 @@ init(void) * created the new module instance). */ - _zic_module_state *rec = _zic_state_init(module); + _zic_module_state* rec = _zic_state_init(module); rec->adapter_hooks = PyList_New(0); if (rec->adapter_hooks == NULL) @@ -2253,9 +2236,8 @@ init(void) if (PyModule_AddType(module, rec->specification_base_class) < 0) return NULL; - if (PyModule_AddType( - module, rec->object_specification_descriptor_class - ) < 0) + if (PyModule_AddType(module, rec->object_specification_descriptor_class) < + 0) return NULL; if (PyModule_AddType(module, rec->class_provides_base_class) < 0) From fc38083e3f063dc838e2a28900d1df53bb830595 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 09:25:25 -0400 Subject: [PATCH 09/39] refactor: use 'PyObject_GetAttrString' Drop statics previously used to call 'PyObject_GetAttr'. --- .../_zope_interface_coptimizations.c | 74 ++++++++----------- 1 file changed, 29 insertions(+), 45 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 9efa5ff8..1702d284 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -33,25 +33,20 @@ #define PyNative_FromString PyUnicode_FromString -static PyObject* str__dict__; +/* Static strings, used to invoke PyObject_CallMethodObjArgs */ +static PyObject *str_call_conform; +static PyObject *str_uncached_lookup; +static PyObject *str_uncached_lookupAll; +static PyObject *str_uncached_subscriptions; +static PyObject *strchanged; +static PyObject *str__adapt__; + +/* Static strings, used to invoke PyObject_GetItem + * + * Note that replacing the call with PyDict_GetItemString and the + * literal value can result in a segfault! + */ static PyObject* str__implemented__; -static PyObject* strextends; -static PyObject* str__provides__; -static PyObject* str__class__; -static PyObject* str__providedBy__; -static PyObject* str__conform__; -static PyObject* str_call_conform; -static PyObject* str_uncached_lookup; -static PyObject* str_uncached_lookupAll; -static PyObject* str_uncached_subscriptions; -static PyObject* str_registry; -static PyObject* strro; -static PyObject* str_generation; -static PyObject* strchanged; -static PyObject* str__self__; -static PyObject* str__module__; -static PyObject* str__name__; -static PyObject* str__adapt__; static PyObject* str_CALL_CUSTOM_ADAPT; /* Moving these statics to module state. */ @@ -133,7 +128,7 @@ implementedBy(PyObject* ignored, PyObject* cls) } if (dict == NULL) - dict = PyObject_GetAttr(cls, str__dict__); + dict = PyObject_GetAttrString(cls, "__dict__"); if (dict == NULL) { /* Probably a security proxied class, use more expensive fallback code @@ -177,7 +172,7 @@ getObjectSpecification(PyObject* ignored, PyObject* ob) { PyObject *cls, *result; - result = PyObject_GetAttr(ob, str__provides__); + result = PyObject_GetAttrString(ob, "__provides__"); if (!result) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { /* Propagate non AttributeError exceptions. */ @@ -198,7 +193,7 @@ getObjectSpecification(PyObject* ignored, PyObject* ob) } /* We do a getattr here so as not to be defeated by proxies */ - cls = PyObject_GetAttr(ob, str__class__); + cls = PyObject_GetAttrString(ob, "__class__"); if (cls == NULL) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { /* Propagate non-AttributeErrors */ @@ -236,7 +231,7 @@ providedBy(PyObject* ignored, PyObject* ob) return implementedBy(NULL, ob); } - result = PyObject_GetAttr(ob, str__providedBy__); + result = PyObject_GetAttrString(ob, "__providedBy__"); if (result == NULL) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { @@ -252,7 +247,7 @@ providedBy(PyObject* ignored, PyObject* ob) only attribute. */ if (PyObject_TypeCheck(result, &SpecificationBaseType) || - PyObject_HasAttr(result, strextends)) + PyObject_HasAttrString(result, "extends")) return result; /* @@ -263,11 +258,11 @@ providedBy(PyObject* ignored, PyObject* ob) */ Py_DECREF(result); - cls = PyObject_GetAttr(ob, str__class__); + cls = PyObject_GetAttrString(ob, "__class__"); if (cls == NULL) return NULL; - result = PyObject_GetAttr(ob, str__provides__); + result = PyObject_GetAttrString(ob, "__provides__"); if (result == NULL) { /* No __provides__, so just fall back to implementedBy */ PyErr_Clear(); @@ -276,7 +271,7 @@ providedBy(PyObject* ignored, PyObject* ob) return result; } - cp = PyObject_GetAttr(cls, str__provides__); + cp = PyObject_GetAttrString(cls, "__provides__"); if (cp == NULL) { /* The the class has no provides, assume we're done: */ PyErr_Clear(); @@ -503,7 +498,7 @@ OSD_descr_get(PyObject* self, PyObject* inst, PyObject* cls) if (inst == NULL) return getObjectSpecification(NULL, cls); - provides = PyObject_GetAttr(inst, str__provides__); + provides = PyObject_GetAttrString(inst, "__provides__"); /* Return __provides__ if we got it, or return NULL and propagate * non-AttributeError. */ if (provides != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError)) @@ -577,7 +572,7 @@ CPB_descr_get(CPB* self, PyObject* inst, PyObject* cls) return implements; } - PyErr_SetObject(PyExc_AttributeError, str__provides__); + PyErr_SetString(PyExc_AttributeError, "__provides__"); return NULL; } @@ -786,7 +781,7 @@ IB_call(PyObject* self, PyObject* args, PyObject* kwargs) args, kwargs, "O|O", kwlist, &obj, &alternate)) return NULL; - conform = PyObject_GetAttr(obj, str__conform__); + conform = PyObject_GetAttrString(obj, "__conform__"); if (conform == NULL) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { /* Propagate non-AttributeErrors */ @@ -1397,7 +1392,7 @@ _adapter_hook(lookup* self, if (factory != Py_None) { if (PyObject_TypeCheck(object, &PySuper_Type)) { - PyObject* self = PyObject_GetAttr(object, str__self__); + PyObject* self = PyObject_GetAttrString(object, "__self__"); if (self == NULL) { Py_DECREF(factory); return NULL; @@ -1707,7 +1702,8 @@ _generations_tuple(PyObject* ro) for (i = 0; i < l; i++) { PyObject* generation; - generation = PyObject_GetAttr(PyTuple_GET_ITEM(ro, i), str_generation); + generation = PyObject_GetAttrString( + PyTuple_GET_ITEM(ro, i), "_generation"); if (generation == NULL) { Py_DECREF(generations); return NULL; @@ -1724,10 +1720,10 @@ verifying_changed(verify* self, PyObject* ignored) verifying_clear(self); - t = PyObject_GetAttr(OBJECT(self), str_registry); + t = PyObject_GetAttrString(OBJECT(self), "_registry"); if (t == NULL) return NULL; - ro = PyObject_GetAttr(t, strro); + ro = PyObject_GetAttrString(t, "ro"); Py_DECREF(t); if (ro == NULL) return NULL; @@ -2150,24 +2146,12 @@ init(void) if (!(str##S = PyUnicode_FromString(#S))) \ return NULL - DEFINE_STRING(__dict__); DEFINE_STRING(__implemented__); - DEFINE_STRING(__provides__); - DEFINE_STRING(__class__); - DEFINE_STRING(__providedBy__); - DEFINE_STRING(extends); - DEFINE_STRING(__conform__); DEFINE_STRING(_call_conform); DEFINE_STRING(_uncached_lookup); DEFINE_STRING(_uncached_lookupAll); DEFINE_STRING(_uncached_subscriptions); - DEFINE_STRING(_registry); - DEFINE_STRING(_generation); - DEFINE_STRING(ro); DEFINE_STRING(changed); - DEFINE_STRING(__self__); - DEFINE_STRING(__name__); - DEFINE_STRING(__module__); DEFINE_STRING(__adapt__); DEFINE_STRING(_CALL_CUSTOM_ADAPT); #undef DEFINE_STRING From 4f5814d01b6411b1c7424f22e807c8623df38edc Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 09:29:02 -0400 Subject: [PATCH 10/39] refactor: move docstring decls to just before their functions --- .../_zope_interface_coptimizations.c | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 1702d284..c73b9e22 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -108,6 +108,10 @@ implementedByFallback(PyObject* cls) return PyObject_CallFunctionObjArgs(fallback, cls, NULL); } +static char implementedBy___doc__[] = + ("Interfaces implemented by a class or factory.\n" + "Raises TypeError if argument is neither a class nor a callable."); + static PyObject* implementedBy(PyObject* ignored, PyObject* cls) { @@ -167,6 +171,9 @@ implementedBy(PyObject* ignored, PyObject* cls) return implementedByFallback(cls); } +static char getObjectSpecification___doc__[] = + ("Get an object's interfaces (internal api)"); + static PyObject* getObjectSpecification(PyObject* ignored, PyObject* ob) { @@ -212,6 +219,8 @@ getObjectSpecification(PyObject* ignored, PyObject* ob) return result; } +static char providedBy___doc__[] = ("Get an object's interfaces"); + static PyObject* providedBy(PyObject* ignored, PyObject* ob) { @@ -358,6 +367,9 @@ Spec_dealloc(Spec* self) Py_TYPE(self)->tp_free(OBJECT(self)); } +static char Spec_extends__doc__[] = + "Test whether a specification is or extends another"; + static PyObject* Spec_extends(Spec* self, PyObject* other) { @@ -373,12 +385,6 @@ Spec_extends(Spec* self, PyObject* other) Py_RETURN_FALSE; } -static char Spec_extends__doc__[] = - "Test whether a specification is or extends another"; - -static char Spec_providedBy__doc__[] = - "Test whether an interface is implemented by the specification"; - static PyObject* Spec_call(Spec* self, PyObject* args, PyObject* kw) { @@ -389,6 +395,9 @@ Spec_call(Spec* self, PyObject* args, PyObject* kw) return Spec_extends(self, spec); } +static char Spec_providedBy__doc__[] = + "Test whether an interface is implemented by the specification"; + static PyObject* Spec_providedBy(PyObject* self, PyObject* ob) { @@ -2103,13 +2112,6 @@ _zic_state_load_declarations(PyObject* module) return rec; } -static char implementedBy___doc__[] = - ("Interfaces implemented by a class or factory.\n" - "Raises TypeError if argument is neither a class nor a callable."); -static char getObjectSpecification___doc__[] = - ("Get an object's interfaces (internal api)"); -static char providedBy___doc__[] = ("Get an object's interfaces"); - static struct PyMethodDef m_methods[] = { { "implementedBy", (PyCFunction)implementedBy, From 6fc0d08d7409d54c0ebd822c9781312f26ecae0a Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 10:19:17 -0400 Subject: [PATCH 11/39] chore: restore compat w/ Python < 3.10 The 'PyModule_AddType' API was added in that release. --- .../_zope_interface_coptimizations.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index c73b9e22..14887df0 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -2219,23 +2219,30 @@ init(void) rec->verifying_base_class = &VerifyingBase; /* Add types to our dict FBO python; also the adapter hooks */ - if (PyModule_AddType(module, rec->specification_base_class) < 0) + if (PyModule_AddObject(module, + "SpecificationBase", OBJECT(rec->specification_base_class)) < 0) return NULL; - if (PyModule_AddType(module, rec->object_specification_descriptor_class) < + if (PyModule_AddObject(module, + "ObjectSpecificationDescriptor", + OBJECT(rec->object_specification_descriptor_class)) < 0) return NULL; - if (PyModule_AddType(module, rec->class_provides_base_class) < 0) + if (PyModule_AddObject(module, + "ClassProvidesBase", OBJECT(rec->class_provides_base_class)) < 0) return NULL; - if (PyModule_AddType(module, rec->interface_base_class) < 0) + if (PyModule_AddObject(module, + "InterfaceBase", OBJECT(rec->interface_base_class)) < 0) return NULL; - if (PyModule_AddType(module, rec->lookup_base_class) < 0) + if (PyModule_AddObject(module, + "LookupBase", OBJECT(rec->lookup_base_class)) < 0) return NULL; - if (PyModule_AddType(module, rec->verifying_base_class) < 0) + if (PyModule_AddObject(module, + "VerifyingBase", OBJECT(rec->verifying_base_class)) < 0) return NULL; if (PyModule_AddObject(module, "adapter_hooks", adapter_hooks) < 0) From 6e1387efe7c48b46749f132371da3348cfd91f07 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 10:20:01 -0400 Subject: [PATCH 12/39] refactor: convert PyType decls to use named members --- .../_zope_interface_coptimizations.c | 272 +++++------------- 1 file changed, 72 insertions(+), 200 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 14887df0..e1cec58e 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -465,38 +465,21 @@ static PyMemberDef Spec_members[] = { { NULL }, }; +static char Spec__doc__[] = "Base type for Specification objects"; + static PyTypeObject SpecificationBaseType = { PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_interface_coptimizations." - "SpecificationBase", - /* tp_basicsize */ sizeof(Spec), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)Spec_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)0, - /* tp_call */ (ternaryfunc)Spec_call, - /* tp_str */ (reprfunc)0, - /* tp_getattro */ (getattrofunc)0, - /* tp_setattro */ (setattrofunc)0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC, - "Base type for Specification objects", - /* tp_traverse */ (traverseproc)Spec_traverse, - /* tp_clear */ (inquiry)Spec_clear, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ offsetof(Spec, weakreflist), - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ Spec_methods, - /* tp_members */ Spec_members, + .tp_name="_interface_coptimizations.SpecificationBase", + .tp_doc=Spec__doc__, + .tp_basicsize=sizeof(Spec), + .tp_flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .tp_weaklistoffset=offsetof(Spec, weakreflist), + .tp_methods=Spec_methods, + .tp_members=Spec_members, + .tp_call=(ternaryfunc)Spec_call, + .tp_traverse=(traverseproc)Spec_traverse, + .tp_clear=(inquiry)Spec_clear, + .tp_dealloc=(destructor)Spec_dealloc, }; static PyObject* @@ -517,41 +500,14 @@ OSD_descr_get(PyObject* self, PyObject* inst, PyObject* cls) return implementedBy(NULL, cls); } +static char OSD__doc__[] = "Object Specification Descriptor"; + static PyTypeObject OSDType = { PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_interface_coptimizations." - "ObjectSpecificationDescriptor", - /* tp_basicsize */ 0, - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)0, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)0, - /* tp_call */ (ternaryfunc)0, - /* tp_str */ (reprfunc)0, - /* tp_getattro */ (getattrofunc)0, - /* tp_setattro */ (setattrofunc)0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - "Object Specification Descriptor", - /* tp_traverse */ (traverseproc)0, - /* tp_clear */ (inquiry)0, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ 0, - /* tp_members */ 0, - /* tp_getset */ 0, - /* tp_base */ 0, - /* tp_dict */ 0, /* internal use */ - /* tp_descr_get */ (descrgetfunc)OSD_descr_get, + .tp_name="_interface_coptimizations.ObjectSpecificationDescriptor", + .tp_doc=OSD__doc__, + .tp_flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_descr_get=(descrgetfunc)OSD_descr_get, }; typedef struct @@ -620,47 +576,20 @@ static PyMemberDef CPB_members[] = { { NULL } }; +static char CPB__doc__[] = "C Base class for ClassProvides"; + static PyTypeObject CPBType = { PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_interface_coptimizations." - "ClassProvidesBase", - /* tp_basicsize */ sizeof(CPB), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)CPB_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)0, - /* tp_call */ (ternaryfunc)0, - /* tp_str */ (reprfunc)0, - /* tp_getattro */ (getattrofunc)0, - /* tp_setattro */ (setattrofunc)0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC, - "C Base class for ClassProvides", - /* tp_traverse */ (traverseproc)CPB_traverse, - /* tp_clear */ (inquiry)CPB_clear, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ 0, - /* tp_members */ CPB_members, - /* tp_getset */ 0, - /* tp_base */ &SpecificationBaseType, - /* tp_dict */ 0, /* internal use */ - /* tp_descr_get */ (descrgetfunc)CPB_descr_get, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ 0, - /* tp_alloc */ 0, - /* tp_new */ 0, + .tp_name="_interface_coptimizations.ClassProvidesBase", + .tp_doc=CPB__doc__, + .tp_basicsize=sizeof(CPB), + .tp_flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .tp_base=&SpecificationBaseType, + .tp_members=CPB_members, + .tp_descr_get=(descrgetfunc)CPB_descr_get, + .tp_clear=(inquiry)CPB_clear, + .tp_traverse=(traverseproc)CPB_traverse, + .tp_dealloc=(destructor)CPB_dealloc, }; /* ==================================================================== */ @@ -1012,45 +941,26 @@ IB_init(IB* self, PyObject* args, PyObject* kwargs) return 0; } +static char IB__doc__[] = ( + "Interface base type providing __call__ and __adapt__" +); + static PyTypeObject InterfaceBaseType = { PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_zope_interface_coptimizations." - "InterfaceBase", - /* tp_basicsize */ sizeof(IB), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)IB_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)IB_hash, - /* tp_call */ (ternaryfunc)IB_call, - /* tp_str */ (reprfunc)0, - /* tp_getattro */ (getattrofunc)0, - /* tp_setattro */ (setattrofunc)0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC, - /* tp_doc */ "Interface base type providing __call__ and __adapt__", - /* tp_traverse */ (traverseproc)IB_traverse, - /* tp_clear */ (inquiry)IB_clear, - /* tp_richcompare */ (richcmpfunc)IB_richcompare, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ ib_methods, - /* tp_members */ IB_members, - /* tp_getset */ 0, - /* tp_base */ &SpecificationBaseType, - /* tp_dict */ 0, - /* tp_descr_get */ 0, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ (initproc)IB_init, + .tp_name="_zope_interface_coptimizations.InterfaceBase", + .tp_doc=IB__doc__, + .tp_basicsize=sizeof(IB), + .tp_flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .tp_base=&SpecificationBaseType, + .tp_methods=ib_methods, + .tp_members=IB_members, + .tp_init=(initproc)IB_init, + .tp_richcompare=(richcmpfunc)IB_richcompare, + .tp_hash=(hashfunc)IB_hash, + .tp_call=(ternaryfunc)IB_call, + .tp_traverse=(traverseproc)IB_traverse, + .tp_clear=(inquiry)IB_clear, + .tp_dealloc=(destructor)IB_dealloc, }; /* =================== End: __call__ and __adapt__ ==================== */ @@ -1621,37 +1531,18 @@ static struct PyMethodDef lookup_methods[] = { { NULL, NULL } /* sentinel */ }; +static char LookupBase__doc__[] = "Base class for adapter registries"; + static PyTypeObject LookupBase = { PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_zope_interface_coptimizations." - "LookupBase", - /* tp_basicsize */ sizeof(lookup), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)&lookup_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)0, - /* tp_call */ (ternaryfunc)0, - /* tp_str */ (reprfunc)0, - /* tp_getattro */ (getattrofunc)0, - /* tp_setattro */ (setattrofunc)0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC, - /* tp_doc */ "", - /* tp_traverse */ (traverseproc)lookup_traverse, - /* tp_clear */ (inquiry)lookup_clear, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ lookup_methods, + .tp_name="_zope_interface_coptimizations.LookupBase", + .tp_doc=LookupBase__doc__, + .tp_basicsize=sizeof(lookup), + .tp_flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .tp_methods=lookup_methods, + .tp_traverse=(traverseproc)lookup_traverse, + .tp_clear=(inquiry)lookup_clear, + .tp_dealloc=(destructor)&lookup_dealloc, }; static int @@ -1922,40 +1813,21 @@ static struct PyMethodDef verifying_methods[] = { { NULL, NULL } /* sentinel */ }; +static char VerifyingBase__doc__[] = ( +"Base class for verifying adapter registries." +); + static PyTypeObject VerifyingBase = { PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_zope_interface_coptimizations." - "VerifyingBase", - /* tp_basicsize */ sizeof(verify), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)&verifying_dealloc, - /* tp_print */ (printfunc)0, - /* tp_getattr */ (getattrfunc)0, - /* tp_setattr */ (setattrfunc)0, - /* tp_compare */ 0, - /* tp_repr */ (reprfunc)0, - /* tp_as_number */ 0, - /* tp_as_sequence */ 0, - /* tp_as_mapping */ 0, - /* tp_hash */ (hashfunc)0, - /* tp_call */ (ternaryfunc)0, - /* tp_str */ (reprfunc)0, - /* tp_getattro */ (getattrofunc)0, - /* tp_setattro */ (setattrofunc)0, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC, - /* tp_doc */ "", - /* tp_traverse */ (traverseproc)verifying_traverse, - /* tp_clear */ (inquiry)verifying_clear, - /* tp_richcompare */ (richcmpfunc)0, - /* tp_weaklistoffset */ (long)0, - /* tp_iter */ (getiterfunc)0, - /* tp_iternext */ (iternextfunc)0, - /* tp_methods */ verifying_methods, - /* tp_members */ 0, - /* tp_getset */ 0, - /* tp_base */ &LookupBase, + .tp_name="_zope_interface_coptimizations.VerifyingBase", + .tp_doc=VerifyingBase__doc__, + .tp_basicsize=sizeof(verify), + .tp_flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + .tp_base=&LookupBase, + .tp_methods=verifying_methods, + .tp_traverse=(traverseproc)verifying_traverse, + .tp_clear=(inquiry)verifying_clear, + .tp_dealloc=(destructor)&verifying_dealloc, }; /* ========================== End: Lookup Bases ======================= */ From 2c4d70c2a72ed1d39b247d9915713d2a6877c1ce Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 10:24:25 -0400 Subject: [PATCH 13/39] refactor: use 'PyDict_GetItemString' And remove the static used to call 'PyDict_GetItem'. --- src/zope/interface/_zope_interface_coptimizations.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index e1cec58e..809d1c50 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -47,7 +47,6 @@ static PyObject *str__adapt__; * literal value can result in a segfault! */ static PyObject* str__implemented__; -static PyObject* str_CALL_CUSTOM_ADAPT; /* Moving these statics to module state. */ static PyObject* adapter_hooks; @@ -749,7 +748,7 @@ IB_call(PyObject* self, PyObject* args, PyObject* kwargs) will *never* be InterfaceBase, we're always subclassed by InterfaceClass). Instead, we cooperate with InterfaceClass in Python to set a flag in a new subclass when this is necessary. */ - if (PyDict_GetItem(self->ob_type->tp_dict, str_CALL_CUSTOM_ADAPT)) { + if (PyDict_GetItemString(self->ob_type->tp_dict, "_CALL_CUSTOM_ADAPT")) { /* Doesn't matter what the value is. Simply being present is enough. */ adapter = PyObject_CallMethodObjArgs(self, str__adapt__, obj, NULL); } else { @@ -2027,7 +2026,6 @@ init(void) DEFINE_STRING(_uncached_subscriptions); DEFINE_STRING(changed); DEFINE_STRING(__adapt__); - DEFINE_STRING(_CALL_CUSTOM_ADAPT); #undef DEFINE_STRING /* From 011a705e51e315b942a41593311cccad0e260099 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 10:42:48 -0400 Subject: [PATCH 14/39] chore: note reason for avoiding 'PyDict_GetString' --- src/zope/interface/_zope_interface_coptimizations.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 809d1c50..312b6f7e 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -43,8 +43,8 @@ static PyObject *str__adapt__; /* Static strings, used to invoke PyObject_GetItem * - * Note that replacing the call with PyDict_GetItemString and the - * literal value can result in a segfault! + * We cannot use PyDict_GetItemString, because the '__dict__' we get + * from our types can be a 'types.mappingproxy', which causes a segfault. */ static PyObject* str__implemented__; From 5638a90e3c0f21bf8320d0cf476993974e3db4ad Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 11:09:30 -0400 Subject: [PATCH 15/39] refactor: always pass the module to the module-scope functions Note that those functions are still ignoring that value: this is prep for the next step, where they will use the '_zic_module_state' machinery --- .../_zope_interface_coptimizations.c | 105 +++++++++++++----- 1 file changed, 75 insertions(+), 30 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 312b6f7e..c9a68050 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -47,6 +47,10 @@ static PyObject *str__adapt__; * from our types can be a 'types.mappingproxy', which causes a segfault. */ static PyObject* str__implemented__; +/* + * Utility: fetch the module for the current type, using the module spec. + */ +static PyObject* _get_module(PyTypeObject *typeobj); /* forward */ /* Moving these statics to module state. */ static PyObject* adapter_hooks; @@ -99,7 +103,7 @@ import_declarations(void) static PyTypeObject SpecificationBaseType; /* Forward */ static PyObject* -implementedByFallback(PyObject* cls) +implementedByFallback(PyObject* module, PyObject* cls) { if (imported_declarations == 0 && import_declarations() < 0) return NULL; @@ -112,7 +116,7 @@ static char implementedBy___doc__[] = "Raises TypeError if argument is neither a class nor a callable."); static PyObject* -implementedBy(PyObject* ignored, PyObject* cls) +implementedBy(PyObject* module, PyObject* cls) { /* Fast retrieval of implements spec, if possible, to optimize common case. Use fallback code if we get stuck. @@ -122,7 +126,7 @@ implementedBy(PyObject* ignored, PyObject* cls) if (PyObject_TypeCheck(cls, &PySuper_Type)) { // Let merging be handled by Python. - return implementedByFallback(cls); + return implementedByFallback(module, cls); } if (PyType_Check(cls)) { @@ -137,7 +141,7 @@ implementedBy(PyObject* ignored, PyObject* cls) /* Probably a security proxied class, use more expensive fallback code */ PyErr_Clear(); - return implementedByFallback(cls); + return implementedByFallback(module, cls); } spec = PyObject_GetItem(dict, str__implemented__); @@ -151,7 +155,7 @@ implementedBy(PyObject* ignored, PyObject* cls) /* Old-style declaration, use more expensive fallback code */ Py_DECREF(spec); - return implementedByFallback(cls); + return implementedByFallback(module, cls); } PyErr_Clear(); @@ -167,16 +171,17 @@ implementedBy(PyObject* ignored, PyObject* cls) } /* We're stuck, use fallback */ - return implementedByFallback(cls); + return implementedByFallback(module, cls); } static char getObjectSpecification___doc__[] = ("Get an object's interfaces (internal api)"); static PyObject* -getObjectSpecification(PyObject* ignored, PyObject* ob) +getObjectSpecification(PyObject* module, PyObject* ob) { - PyObject *cls, *result; + PyObject *cls; + PyObject *result; result = PyObject_GetAttrString(ob, "__provides__"); if (!result) { @@ -212,7 +217,7 @@ getObjectSpecification(PyObject* ignored, PyObject* ob) Py_INCREF(empty); return empty; } - result = implementedBy(NULL, cls); + result = implementedBy(module, cls); Py_DECREF(cls); return result; @@ -221,11 +226,12 @@ getObjectSpecification(PyObject* ignored, PyObject* ob) static char providedBy___doc__[] = ("Get an object's interfaces"); static PyObject* -providedBy(PyObject* ignored, PyObject* ob) +providedBy(PyObject* module, PyObject* ob) { - PyObject *result, *cls, *cp; + PyObject *result = NULL; + PyObject *cls; + PyObject *cp; int is_instance = -1; - result = NULL; is_instance = PyObject_IsInstance(ob, (PyObject*)&PySuper_Type); if (is_instance < 0) { @@ -236,7 +242,7 @@ providedBy(PyObject* ignored, PyObject* ob) PyErr_Clear(); } if (is_instance) { - return implementedBy(NULL, ob); + return implementedBy(module, ob); } result = PyObject_GetAttrString(ob, "__providedBy__"); @@ -247,7 +253,7 @@ providedBy(PyObject* ignored, PyObject* ob) } PyErr_Clear(); - return getObjectSpecification(NULL, ob); + return getObjectSpecification(module, ob); } /* We want to make sure we have a spec. We can't do a type check @@ -274,7 +280,7 @@ providedBy(PyObject* ignored, PyObject* ob) if (result == NULL) { /* No __provides__, so just fall back to implementedBy */ PyErr_Clear(); - result = implementedBy(NULL, cls); + result = implementedBy(module, cls); Py_DECREF(cls); return result; } @@ -293,7 +299,7 @@ providedBy(PyObject* ignored, PyObject* ob) the object doesn't have it's own. We should use implementedBy */ Py_DECREF(result); - result = implementedBy(NULL, cls); + result = implementedBy(module, cls); } Py_DECREF(cls); @@ -400,9 +406,13 @@ static char Spec_providedBy__doc__[] = static PyObject* Spec_providedBy(PyObject* self, PyObject* ob) { - PyObject *decl, *item; + PyObject *decl; + PyObject *item; + PyObject *module; + + module = _get_module(Py_TYPE(self)); - decl = providedBy(NULL, ob); + decl = providedBy(module, ob); if (decl == NULL) return NULL; @@ -425,9 +435,13 @@ static char Spec_implementedBy__doc__[] = static PyObject* Spec_implementedBy(PyObject* self, PyObject* cls) { - PyObject *decl, *item; + PyObject *decl; + PyObject *item; + PyObject *module; - decl = implementedBy(NULL, cls); + module = _get_module(Py_TYPE(self)); + + decl = implementedBy(module, cls); if (decl == NULL) return NULL; @@ -485,9 +499,12 @@ static PyObject* OSD_descr_get(PyObject* self, PyObject* inst, PyObject* cls) { PyObject* provides; + PyObject *module; + + module = _get_module(Py_TYPE(self)); if (inst == NULL) - return getObjectSpecification(NULL, cls); + return getObjectSpecification(module, cls); provides = PyObject_GetAttrString(inst, "__provides__"); /* Return __provides__ if we got it, or return NULL and propagate @@ -496,7 +513,8 @@ OSD_descr_get(PyObject* self, PyObject* inst, PyObject* cls) return provides; PyErr_Clear(); - return implementedBy(NULL, cls); + + return implementedBy(module, cls); } static char OSD__doc__[] = "Object Specification Descriptor"; @@ -611,10 +629,17 @@ static PyTypeObject CPBType = { static PyObject* __adapt__(PyObject* self, PyObject* obj) { - PyObject *decl, *args, *adapter; - int implements, i, l; + PyObject *decl; + PyObject *args; + PyObject *adapter; + PyObject *module; + int implements; + int i; + int l; + + module = _get_module(Py_TYPE(self)); - decl = providedBy(NULL, obj); + decl = providedBy(module, obj); if (decl == NULL) return NULL; @@ -1292,14 +1317,19 @@ _adapter_hook(lookup* self, PyObject* name, PyObject* default_) { - PyObject *required, *factory, *result; + PyObject *required; + PyObject *factory; + PyObject *result; + PyObject *module; + + module = _get_module(Py_TYPE(self)); if (name && !PyUnicode_Check(name)) { PyErr_SetString(PyExc_ValueError, "name is not a string or unicode"); return NULL; } - required = providedBy(NULL, object); + required = providedBy(module, object); if (required == NULL) return NULL; @@ -1829,9 +1859,6 @@ static PyTypeObject VerifyingBase = { .tp_dealloc=(destructor)&verifying_dealloc, }; -/* ========================== End: Lookup Bases ======================= */ -/* ==================================================================== */ - /* * Module state struct: holds all data formerly kept as static globals. */ @@ -2010,6 +2037,24 @@ static struct PyModuleDef _zic_module = { .m_clear = _zic_state_clear, }; +/* + * Provide access to the current module given the type. + * + * At the moment, this just returns the static, but we can adjust this + * to do the lookup using 'PyType_GetModuleByDef' (for slot methods) + * or via the '*defining_class' arg passed to the yet-to-be-refactored + * normal methods declared using 'PyCMethod' calling convention. + */ +static PyObject* +_get_module(PyTypeObject *typeobj) +{ + if (PyType_Check(typeobj)) { + return OBJECT(&_zic_module); + } + PyErr_SetString(PyExc_TypeError, "_get_module: called w/ non-type"); + return NULL; +} + static PyObject* init(void) { From f7b28891e09c8f83cd00d2d9f59ff01e179d4e9f Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 11:28:05 -0400 Subject: [PATCH 16/39] refactor: move module-scope functions to end Leave forward decls behind FBO type methods. This step is in preparation for using the '_zic_module_state', rather than the global statics. --- .../_zope_interface_coptimizations.c | 418 +++++++++--------- 1 file changed, 212 insertions(+), 206 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index c9a68050..142edd51 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -33,6 +33,11 @@ #define PyNative_FromString PyUnicode_FromString +/* Public module-scope functions, forward declared here FBO type methods. */ +static PyObject *implementedBy(PyObject* module, PyObject *cls); +static PyObject *getObjectSpecification(PyObject *module, PyObject *ob); +static PyObject *providedBy(PyObject *module, PyObject *ob); + /* Static strings, used to invoke PyObject_CallMethodObjArgs */ static PyObject *str_call_conform; static PyObject *str_uncached_lookup; @@ -102,212 +107,6 @@ import_declarations(void) static PyTypeObject SpecificationBaseType; /* Forward */ -static PyObject* -implementedByFallback(PyObject* module, PyObject* cls) -{ - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; - - return PyObject_CallFunctionObjArgs(fallback, cls, NULL); -} - -static char implementedBy___doc__[] = - ("Interfaces implemented by a class or factory.\n" - "Raises TypeError if argument is neither a class nor a callable."); - -static PyObject* -implementedBy(PyObject* module, PyObject* cls) -{ - /* Fast retrieval of implements spec, if possible, to optimize - common case. Use fallback code if we get stuck. - */ - - PyObject *dict = NULL, *spec; - - if (PyObject_TypeCheck(cls, &PySuper_Type)) { - // Let merging be handled by Python. - return implementedByFallback(module, cls); - } - - if (PyType_Check(cls)) { - dict = TYPE(cls)->tp_dict; - Py_XINCREF(dict); - } - - if (dict == NULL) - dict = PyObject_GetAttrString(cls, "__dict__"); - - if (dict == NULL) { - /* Probably a security proxied class, use more expensive fallback code - */ - PyErr_Clear(); - return implementedByFallback(module, cls); - } - - spec = PyObject_GetItem(dict, str__implemented__); - Py_DECREF(dict); - if (spec) { - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; - - if (PyObject_TypeCheck(spec, Implements)) - return spec; - - /* Old-style declaration, use more expensive fallback code */ - Py_DECREF(spec); - return implementedByFallback(module, cls); - } - - PyErr_Clear(); - - /* Maybe we have a builtin */ - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; - - spec = PyDict_GetItem(BuiltinImplementationSpecifications, cls); - if (spec != NULL) { - Py_INCREF(spec); - return spec; - } - - /* We're stuck, use fallback */ - return implementedByFallback(module, cls); -} - -static char getObjectSpecification___doc__[] = - ("Get an object's interfaces (internal api)"); - -static PyObject* -getObjectSpecification(PyObject* module, PyObject* ob) -{ - PyObject *cls; - PyObject *result; - - result = PyObject_GetAttrString(ob, "__provides__"); - if (!result) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { - /* Propagate non AttributeError exceptions. */ - return NULL; - } - PyErr_Clear(); - } else { - int is_instance = -1; - is_instance = - PyObject_IsInstance(result, (PyObject*)&SpecificationBaseType); - if (is_instance < 0) { - /* Propagate all errors */ - return NULL; - } - if (is_instance) { - return result; - } - } - - /* We do a getattr here so as not to be defeated by proxies */ - cls = PyObject_GetAttrString(ob, "__class__"); - if (cls == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { - /* Propagate non-AttributeErrors */ - return NULL; - } - PyErr_Clear(); - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; - - Py_INCREF(empty); - return empty; - } - result = implementedBy(module, cls); - Py_DECREF(cls); - - return result; -} - -static char providedBy___doc__[] = ("Get an object's interfaces"); - -static PyObject* -providedBy(PyObject* module, PyObject* ob) -{ - PyObject *result = NULL; - PyObject *cls; - PyObject *cp; - int is_instance = -1; - - is_instance = PyObject_IsInstance(ob, (PyObject*)&PySuper_Type); - if (is_instance < 0) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { - /* Propagate non-AttributeErrors */ - return NULL; - } - PyErr_Clear(); - } - if (is_instance) { - return implementedBy(module, ob); - } - - result = PyObject_GetAttrString(ob, "__providedBy__"); - - if (result == NULL) { - if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { - return NULL; - } - - PyErr_Clear(); - return getObjectSpecification(module, ob); - } - - /* We want to make sure we have a spec. We can't do a type check - because we may have a proxy, so we'll just try to get the - only attribute. - */ - if (PyObject_TypeCheck(result, &SpecificationBaseType) || - PyObject_HasAttrString(result, "extends")) - return result; - - /* - The object's class doesn't understand descriptors. - Sigh. We need to get an object descriptor, but we have to be - careful. We want to use the instance's __provides__,l if - there is one, but only if it didn't come from the class. - */ - Py_DECREF(result); - - cls = PyObject_GetAttrString(ob, "__class__"); - if (cls == NULL) - return NULL; - - result = PyObject_GetAttrString(ob, "__provides__"); - if (result == NULL) { - /* No __provides__, so just fall back to implementedBy */ - PyErr_Clear(); - result = implementedBy(module, cls); - Py_DECREF(cls); - return result; - } - - cp = PyObject_GetAttrString(cls, "__provides__"); - if (cp == NULL) { - /* The the class has no provides, assume we're done: */ - PyErr_Clear(); - Py_DECREF(cls); - return result; - } - - if (cp == result) { - /* - Oops, we got the provides from the class. This means - the object doesn't have it's own. We should use implementedBy - */ - Py_DECREF(result); - result = implementedBy(module, cls); - } - - Py_DECREF(cls); - Py_DECREF(cp); - - return result; -} - typedef struct { PyObject_HEAD @@ -2010,6 +1809,213 @@ _zic_state_load_declarations(PyObject* module) return rec; } +static PyObject* +implementedByFallback(PyObject* module, PyObject* cls) +{ + if (imported_declarations == 00 && import_declarations() < 0) + return NULL; + + return PyObject_CallFunctionObjArgs(fallback, cls, NULL); +} + +static char implementedBy___doc__[] = + ("Interfaces implemented by a class or factory.\n" + "Raises TypeError if argument is neither a class nor a callable."); + +static PyObject* +implementedBy(PyObject* module, PyObject* cls) +{ + /* Fast retrieval of implements spec, if possible, to optimize + common case. Use fallback code if we get stuck. + */ + + PyObject *dict = NULL; + PyObject *spec; + + if (PyObject_TypeCheck(cls, &PySuper_Type)) { + // Let merging be handled by Python. + return implementedByFallback(module, cls); + } + + if (PyType_Check(cls)) { + dict = TYPE(cls)->tp_dict; + Py_XINCREF(dict); + } + + if (dict == NULL) + dict = PyObject_GetAttrString(cls, "__dict__"); + + if (dict == NULL) { + /* Probably a security proxied class, use more expensive fallback code + */ + PyErr_Clear(); + return implementedByFallback(module, cls); + } + + spec = PyObject_GetItem(dict, str__implemented__); + Py_DECREF(dict); + if (spec) { + if (imported_declarations == 0 && import_declarations() < 0) + return NULL; + + if (PyObject_TypeCheck(spec, Implements)) + return spec; + + /* Old-style declaration, use more expensive fallback code */ + Py_DECREF(spec); + return implementedByFallback(module, cls); + } + + PyErr_Clear(); + + /* Maybe we have a builtin */ + if (imported_declarations == 0 && import_declarations() < 0) + return NULL; + + spec = PyDict_GetItem(BuiltinImplementationSpecifications, cls); + if (spec != NULL) { + Py_INCREF(spec); + return spec; + } + + /* We're stuck, use fallback */ + return implementedByFallback(module, cls); +} + +static char getObjectSpecification___doc__[] = + ("Get an object's interfaces (internal api)"); + +static PyObject* +getObjectSpecification(PyObject* module, PyObject* ob) +{ + PyObject *cls; + PyObject *result; + + result = PyObject_GetAttrString(ob, "__provides__"); + if (!result) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + /* Propagate non AttributeError exceptions. */ + return NULL; + } + PyErr_Clear(); + } else { + int is_instance = -1; + is_instance = + PyObject_IsInstance(result, (PyObject*)&SpecificationBaseType); + if (is_instance < 0) { + /* Propagate all errors */ + return NULL; + } + if (is_instance) { + return result; + } + } + + /* We do a getattr here so as not to be defeated by proxies */ + cls = PyObject_GetAttrString(ob, "__class__"); + if (cls == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + /* Propagate non-AttributeErrors */ + return NULL; + } + PyErr_Clear(); + if (imported_declarations == 0 && import_declarations() < 0) + return NULL; + + Py_INCREF(empty); + return empty; + } + result = implementedBy(module, cls); + Py_DECREF(cls); + + return result; +} + +static char providedBy___doc__[] = ("Get an object's interfaces"); + +static PyObject* +providedBy(PyObject* module, PyObject* ob) +{ + PyObject *result = NULL; + PyObject *cls; + PyObject *cp; + int is_instance = -1; + + is_instance = PyObject_IsInstance(ob, (PyObject*)&PySuper_Type); + if (is_instance < 0) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + /* Propagate non-AttributeErrors */ + return NULL; + } + PyErr_Clear(); + } + if (is_instance) { + return implementedBy(module, ob); + } + + result = PyObject_GetAttrString(ob, "__providedBy__"); + + if (result == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + return NULL; + } + + PyErr_Clear(); + return getObjectSpecification(module, ob); + } + + /* We want to make sure we have a spec. We can't do a type check + because we may have a proxy, so we'll just try to get the + only attribute. + */ + if (PyObject_TypeCheck(result, &SpecificationBaseType) || + PyObject_HasAttrString(result, "extends")) + return result; + + /* + The object's class doesn't understand descriptors. + Sigh. We need to get an object descriptor, but we have to be + careful. We want to use the instance's __provides__,l if + there is one, but only if it didn't come from the class. + */ + Py_DECREF(result); + + cls = PyObject_GetAttrString(ob, "__class__"); + if (cls == NULL) + return NULL; + + result = PyObject_GetAttrString(ob, "__provides__"); + if (result == NULL) { + /* No __provides__, so just fall back to implementedBy */ + PyErr_Clear(); + result = implementedBy(module, cls); + Py_DECREF(cls); + return result; + } + + cp = PyObject_GetAttrString(cls, "__provides__"); + if (cp == NULL) { + /* The the class has no provides, assume we're done: */ + PyErr_Clear(); + Py_DECREF(cls); + return result; + } + + if (cp == result) { + /* + Oops, we got the provides from the class. This means + the object doesn't have it's own. We should use implementedBy + */ + Py_DECREF(result); + result = implementedBy(module, cls); + } + + Py_DECREF(cls); + Py_DECREF(cp); + + return result; +} + static struct PyMethodDef m_methods[] = { { "implementedBy", (PyCFunction)implementedBy, From 2b331f9dc07b74179daec6c6c744fe1bea0cf701 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 12:53:46 -0400 Subject: [PATCH 17/39] fix: use API to get initialized module from spec This is a stopgap, for the statically-initialized module. It will be replaced by 'PyType_GetModuleByDef' once we have multi-phase init and heap types in place. --- src/zope/interface/_zope_interface_coptimizations.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 142edd51..3ee01a92 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -2055,7 +2055,7 @@ static PyObject* _get_module(PyTypeObject *typeobj) { if (PyType_Check(typeobj)) { - return OBJECT(&_zic_module); + return PyState_FindModule(&_zic_module); } PyErr_SetString(PyExc_TypeError, "_get_module: called w/ non-type"); return NULL; From 8b55439b60b1295b10c8aa4f47706f6f6a880bb6 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 13:00:26 -0400 Subject: [PATCH 18/39] refactor: remove statics loaded from 'z.i.declarations' Instead, look them up via module state versions. --- .../_zope_interface_coptimizations.c | 78 ++++--------------- 1 file changed, 17 insertions(+), 61 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 3ee01a92..d3b6ef62 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -59,51 +59,6 @@ static PyObject* _get_module(PyTypeObject *typeobj); /* forward */ /* Moving these statics to module state. */ static PyObject* adapter_hooks; -static PyObject* BuiltinImplementationSpecifications; -static PyObject* empty; -static PyObject* fallback; -static PyTypeObject* Implements; -static int imported_declarations = 0; - -static int -import_declarations(void) -{ - PyObject *declarations, *i; - - declarations = PyImport_ImportModule("zope.interface.declarations"); - if (declarations == NULL) - return -1; - - BuiltinImplementationSpecifications = PyObject_GetAttrString( - declarations, "BuiltinImplementationSpecifications"); - if (BuiltinImplementationSpecifications == NULL) - return -1; - - empty = PyObject_GetAttrString(declarations, "_empty"); - if (empty == NULL) - return -1; - - fallback = PyObject_GetAttrString(declarations, "implementedByFallback"); - if (fallback == NULL) - return -1; - - i = PyObject_GetAttrString(declarations, "Implements"); - if (i == NULL) - return -1; - - if (!PyType_Check(i)) { - PyErr_SetString(PyExc_TypeError, - "zope.interface.declarations.Implements is not a type"); - return -1; - } - - Implements = (PyTypeObject*)i; - - Py_DECREF(declarations); - - imported_declarations = 1; - return 0; -} static PyTypeObject SpecificationBaseType; /* Forward */ @@ -1809,13 +1764,15 @@ _zic_state_load_declarations(PyObject* module) return rec; } +static struct PyModuleDef _zic_module; + static PyObject* implementedByFallback(PyObject* module, PyObject* cls) { - if (imported_declarations == 00 && import_declarations() < 0) - return NULL; + _zic_module_state* rec = _zic_state_load_declarations(module); + if (rec == NULL) { return NULL; } - return PyObject_CallFunctionObjArgs(fallback, cls, NULL); + return PyObject_CallFunctionObjArgs(rec->fallback, cls, NULL); } static char implementedBy___doc__[] = @@ -1828,10 +1785,12 @@ implementedBy(PyObject* module, PyObject* cls) /* Fast retrieval of implements spec, if possible, to optimize common case. Use fallback code if we get stuck. */ - PyObject *dict = NULL; PyObject *spec; + _zic_module_state* rec = _zic_state_load_declarations(module); + if (rec == NULL) { return NULL; } + if (PyObject_TypeCheck(cls, &PySuper_Type)) { // Let merging be handled by Python. return implementedByFallback(module, cls); @@ -1855,10 +1814,8 @@ implementedBy(PyObject* module, PyObject* cls) spec = PyObject_GetItem(dict, str__implemented__); Py_DECREF(dict); if (spec) { - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; - if (PyObject_TypeCheck(spec, Implements)) + if (PyObject_TypeCheck(spec, rec->implements_class)) return spec; /* Old-style declaration, use more expensive fallback code */ @@ -1869,10 +1826,7 @@ implementedBy(PyObject* module, PyObject* cls) PyErr_Clear(); /* Maybe we have a builtin */ - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; - - spec = PyDict_GetItem(BuiltinImplementationSpecifications, cls); + spec = PyDict_GetItem(rec->builtin_impl_specs, cls); if (spec != NULL) { Py_INCREF(spec); return spec; @@ -1891,6 +1845,9 @@ getObjectSpecification(PyObject* module, PyObject* ob) PyObject *cls; PyObject *result; + _zic_module_state* rec = _zic_state_load_declarations(module); + if (rec == NULL) { return NULL; } + result = PyObject_GetAttrString(ob, "__provides__"); if (!result) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { @@ -1901,13 +1858,14 @@ getObjectSpecification(PyObject* module, PyObject* ob) } else { int is_instance = -1; is_instance = - PyObject_IsInstance(result, (PyObject*)&SpecificationBaseType); + PyObject_IsInstance(result, OBJECT(rec->specification_base_class)); if (is_instance < 0) { /* Propagate all errors */ return NULL; } if (is_instance) { return result; + } else { } } @@ -1919,11 +1877,9 @@ getObjectSpecification(PyObject* module, PyObject* ob) return NULL; } PyErr_Clear(); - if (imported_declarations == 0 && import_declarations() < 0) - return NULL; - Py_INCREF(empty); - return empty; + Py_INCREF(rec->empty); + return rec->empty; } result = implementedBy(module, cls); Py_DECREF(cls); From 02f56e04022de68f12147345c5bca57d6dd16a9d Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 13:10:23 -0400 Subject: [PATCH 19/39] chore: cleanups --- .../_zope_interface_coptimizations.c | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index d3b6ef62..b423ede6 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -257,14 +257,16 @@ OSD_descr_get(PyObject* self, PyObject* inst, PyObject* cls) module = _get_module(Py_TYPE(self)); - if (inst == NULL) + if (inst == NULL) { return getObjectSpecification(module, cls); + } provides = PyObject_GetAttrString(inst, "__provides__"); /* Return __provides__ if we got it, or return NULL and propagate * non-AttributeError. */ - if (provides != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError)) + if (provides != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError)) { return provides; + } PyErr_Clear(); @@ -1619,23 +1621,23 @@ static PyTypeObject VerifyingBase = { typedef struct { /* our globals (exposed to Python) */ - PyTypeObject* specification_base_class; - PyTypeObject* object_specification_descriptor_class; - PyTypeObject* class_provides_base_class; - PyTypeObject* interface_base_class; - PyTypeObject* lookup_base_class; - PyTypeObject* verifying_base_class; - PyObject* adapter_hooks; + PyTypeObject* specification_base_class; + PyTypeObject* object_specification_descriptor_class; + PyTypeObject* class_provides_base_class; + PyTypeObject* interface_base_class; + PyTypeObject* lookup_base_class; + PyTypeObject* verifying_base_class; + PyObject* adapter_hooks; /* members importe from 'zope.interface.declarations' */ - PyObject* empty; - PyObject* fallback; - PyObject* builtin_impl_specs; - PyTypeObject* implements_class; + PyObject* empty; + PyObject* fallback; + PyObject* builtin_impl_specs; + PyTypeObject* implements_class; /* flag: have we importe the next set of members yet from * 'zope.interface.declarations? */ - int decl_imported; + int decl_imported; } _zic_module_state; /* @@ -1865,7 +1867,6 @@ getObjectSpecification(PyObject* module, PyObject* ob) } if (is_instance) { return result; - } else { } } From c573b2742c6e99bc1024faec1c1c9de8a8d09938 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 13:16:06 -0400 Subject: [PATCH 20/39] refactor: remove global static 'adapter_hooks' Look it up instead from module state via type with a new helper, '_get_adapter_hooks'. --- .../_zope_interface_coptimizations.c | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index b423ede6..a292020f 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -56,9 +56,10 @@ static PyObject* str__implemented__; * Utility: fetch the module for the current type, using the module spec. */ static PyObject* _get_module(PyTypeObject *typeobj); /* forward */ - -/* Moving these statics to module state. */ -static PyObject* adapter_hooks; +/* + * Utility: fetch the adapter hooks for the current type's module. + */ +static PyObject* _get_adapter_hooks(PyTypeObject *typeobj); static PyTypeObject SpecificationBaseType; /* Forward */ @@ -389,6 +390,7 @@ __adapt__(PyObject* self, PyObject* obj) PyObject *args; PyObject *adapter; PyObject *module; + PyObject *adapter_hooks; int implements; int i; int l; @@ -428,14 +430,17 @@ __adapt__(PyObject* self, PyObject* obj) return obj; } - l = PyList_GET_SIZE(adapter_hooks); args = PyTuple_New(2); - if (args == NULL) - return NULL; + if (args == NULL) { return NULL; } + Py_INCREF(self); PyTuple_SET_ITEM(args, 0, self); + Py_INCREF(obj); PyTuple_SET_ITEM(args, 1, obj); + + adapter_hooks = _get_adapter_hooks(Py_TYPE(self)); + l = PyList_GET_SIZE(adapter_hooks); for (i = 0; i < l; i++) { adapter = PyObject_CallObject(PyList_GET_ITEM(adapter_hooks, i), args); if (adapter == NULL || adapter != Py_None) { @@ -2018,6 +2023,19 @@ _get_module(PyTypeObject *typeobj) return NULL; } +static PyObject* +_get_adapter_hooks(PyTypeObject *typeobj) +{ + PyObject* module; + _zic_module_state* rec; + + module = _get_module(typeobj); + if (module == NULL) { return NULL; } + + rec = _zic_state(module); + return rec->adapter_hooks; +} + static PyObject* init(void) { @@ -2057,11 +2075,6 @@ init(void) if (rec->adapter_hooks == NULL) return NULL; - /* temporary: initialize the global static until we can rewire - * the code using it to use module state. - */ - adapter_hooks = rec->adapter_hooks; - /* Initialize types: * Static types are only here until we complete the module state / * multi-phase initializtion bit. @@ -2123,7 +2136,7 @@ init(void) "VerifyingBase", OBJECT(rec->verifying_base_class)) < 0) return NULL; - if (PyModule_AddObject(module, "adapter_hooks", adapter_hooks) < 0) + if (PyModule_AddObject(module, "adapter_hooks", rec->adapter_hooks) < 0) return NULL; return module; From 80ed5e13a61b7dec7b3ffa7d4e88f27b99c08f8a Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 13:19:49 -0400 Subject: [PATCH 21/39] refactor: reorder statics above forwards Move actual explanatory comment for '_get_adapter_hooks' to its impl. --- .../_zope_interface_coptimizations.c | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index a292020f..d251b30d 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -33,11 +33,6 @@ #define PyNative_FromString PyUnicode_FromString -/* Public module-scope functions, forward declared here FBO type methods. */ -static PyObject *implementedBy(PyObject* module, PyObject *cls); -static PyObject *getObjectSpecification(PyObject *module, PyObject *ob); -static PyObject *providedBy(PyObject *module, PyObject *ob); - /* Static strings, used to invoke PyObject_CallMethodObjArgs */ static PyObject *str_call_conform; static PyObject *str_uncached_lookup; @@ -52,13 +47,16 @@ static PyObject *str__adapt__; * from our types can be a 'types.mappingproxy', which causes a segfault. */ static PyObject* str__implemented__; + +/* Public module-scope functions, forward-declared here FBO type methods. */ +static PyObject *implementedBy(PyObject* module, PyObject *cls); +static PyObject *getObjectSpecification(PyObject *module, PyObject *ob); +static PyObject *providedBy(PyObject *module, PyObject *ob); + /* - * Utility: fetch the module for the current type, using the module spec. - */ -static PyObject* _get_module(PyTypeObject *typeobj); /* forward */ -/* - * Utility: fetch the adapter hooks for the current type's module. + * Utility functions, forward-declared here FBO type methods. */ +static PyObject* _get_module(PyTypeObject *typeobj); static PyObject* _get_adapter_hooks(PyTypeObject *typeobj); static PyTypeObject SpecificationBaseType; /* Forward */ @@ -2023,6 +2021,9 @@ _get_module(PyTypeObject *typeobj) return NULL; } +/* + * Fetch the adapter hooks for the current type's module. + */ static PyObject* _get_adapter_hooks(PyTypeObject *typeobj) { From baf7991082f9e2428c6b25cd1888876f8ec0bd61 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 13:23:29 -0400 Subject: [PATCH 22/39] refactor: disuse static 'SpecificationBaseType' Look it up instead from from module state via the type with a new helper, '_get_specification_base_class'. --- .../_zope_interface_coptimizations.c | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index d251b30d..19548487 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -58,8 +58,7 @@ static PyObject *providedBy(PyObject *module, PyObject *ob); */ static PyObject* _get_module(PyTypeObject *typeobj); static PyObject* _get_adapter_hooks(PyTypeObject *typeobj); - -static PyTypeObject SpecificationBaseType; /* Forward */ +static PyTypeObject* _get_specifcation_base_class(PyTypeObject *typeobj); typedef struct { @@ -162,14 +161,16 @@ Spec_providedBy(PyObject* self, PyObject* ob) PyObject *decl; PyObject *item; PyObject *module; + PyTypeObject *specification_base_class; module = _get_module(Py_TYPE(self)); + specification_base_class = _get_specifcation_base_class(Py_TYPE(self)); decl = providedBy(module, ob); if (decl == NULL) return NULL; - if (PyObject_TypeCheck(decl, &SpecificationBaseType)) + if (PyObject_TypeCheck(decl, specification_base_class)) item = Spec_extends((Spec*)decl, self); else /* decl is probably a security proxy. We have to go the long way @@ -191,14 +192,16 @@ Spec_implementedBy(PyObject* self, PyObject* cls) PyObject *decl; PyObject *item; PyObject *module; + PyTypeObject *specification_base_class; module = _get_module(Py_TYPE(self)); + specification_base_class = _get_specifcation_base_class(Py_TYPE(self)); decl = implementedBy(module, cls); if (decl == NULL) return NULL; - if (PyObject_TypeCheck(decl, &SpecificationBaseType)) + if (PyObject_TypeCheck(decl, specification_base_class)) item = Spec_extends((Spec*)decl, self); else item = PyObject_CallFunctionObjArgs(decl, self, NULL); @@ -2037,6 +2040,22 @@ _get_adapter_hooks(PyTypeObject *typeobj) return rec->adapter_hooks; } +/* + * Fetch the 'SpecificationBase' class for the current type's module. + */ +static PyTypeObject* +_get_specifcation_base_class(PyTypeObject *typeobj) +{ + PyObject* module; + _zic_module_state* rec; + + module = _get_module(typeobj); + if (module == NULL) { return NULL; } + + rec = _zic_state(module); + return rec->specification_base_class; +} + static PyObject* init(void) { From 1c5e0ea246542e1964105ffde3e33006cfe40c69 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 13:33:20 -0400 Subject: [PATCH 23/39] refactor: move util funcs out of module init space --- .../_zope_interface_coptimizations.c | 101 +++++++++--------- 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 19548487..9285a148 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -1772,8 +1772,59 @@ _zic_state_load_declarations(PyObject* module) return rec; } +/* + * Provide access to the current module given the type. + * + * At the moment, this just returns the static, but we can adjust this + * to do the lookup using 'PyType_GetModuleByDef' (for slot methods) + * or via the '*defining_class' arg passed to the yet-to-be-refactored + * normal methods declared using 'PyCMethod' calling convention. + */ + static struct PyModuleDef _zic_module; +static PyObject* +_get_module(PyTypeObject *typeobj) +{ + if (PyType_Check(typeobj)) { + return PyState_FindModule(&_zic_module); + } + PyErr_SetString(PyExc_TypeError, "_get_module: called w/ non-type"); + return NULL; +} + +/* + * Fetch the adapter hooks for the current type's module. + */ +static PyObject* +_get_adapter_hooks(PyTypeObject *typeobj) +{ + PyObject* module; + _zic_module_state* rec; + + module = _get_module(typeobj); + if (module == NULL) { return NULL; } + + rec = _zic_state(module); + return rec->adapter_hooks; +} + +/* + * Fetch the 'SpecificationBase' class for the current type's module. + */ +static PyTypeObject* +_get_specifcation_base_class(PyTypeObject *typeobj) +{ + PyObject* module; + _zic_module_state* rec; + + module = _get_module(typeobj); + if (module == NULL) { return NULL; } + + rec = _zic_state(module); + return rec->specification_base_class; +} + static PyObject* implementedByFallback(PyObject* module, PyObject* cls) { @@ -2006,56 +2057,6 @@ static struct PyModuleDef _zic_module = { .m_clear = _zic_state_clear, }; -/* - * Provide access to the current module given the type. - * - * At the moment, this just returns the static, but we can adjust this - * to do the lookup using 'PyType_GetModuleByDef' (for slot methods) - * or via the '*defining_class' arg passed to the yet-to-be-refactored - * normal methods declared using 'PyCMethod' calling convention. - */ -static PyObject* -_get_module(PyTypeObject *typeobj) -{ - if (PyType_Check(typeobj)) { - return PyState_FindModule(&_zic_module); - } - PyErr_SetString(PyExc_TypeError, "_get_module: called w/ non-type"); - return NULL; -} - -/* - * Fetch the adapter hooks for the current type's module. - */ -static PyObject* -_get_adapter_hooks(PyTypeObject *typeobj) -{ - PyObject* module; - _zic_module_state* rec; - - module = _get_module(typeobj); - if (module == NULL) { return NULL; } - - rec = _zic_state(module); - return rec->adapter_hooks; -} - -/* - * Fetch the 'SpecificationBase' class for the current type's module. - */ -static PyTypeObject* -_get_specifcation_base_class(PyTypeObject *typeobj) -{ - PyObject* module; - _zic_module_state* rec; - - module = _get_module(typeobj); - if (module == NULL) { return NULL; } - - rec = _zic_state(module); - return rec->specification_base_class; -} - static PyObject* init(void) { From e3f947bffaa3eaae18f49b831cf02cdf81a264eb Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 15:25:28 -0400 Subject: [PATCH 24/39] refactor: multi-phase module init + heap types At least one bug remains (some interfaces return a 'member_descriptor' for their '__module__'). --- .../_zope_interface_coptimizations.c | 805 ++++++++++-------- 1 file changed, 459 insertions(+), 346 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 9285a148..275b7a5c 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -24,15 +24,19 @@ #define TYPE(O) ((PyTypeObject*)(O)) #define OBJECT(O) ((PyObject*)(O)) #define CLASSIC(O) ((PyClassObject*)(O)) -#ifndef PyVarObject_HEAD_INIT -#define PyVarObject_HEAD_INIT(a, b) PyObject_HEAD_INIT(a) b, -#endif #ifndef Py_TYPE #define Py_TYPE(o) ((o)->ob_type) #endif #define PyNative_FromString PyUnicode_FromString +#define ASSURE_DICT(N) \ + if (N == NULL) { \ + N = PyDict_New(); \ + if (N == NULL) \ + return NULL; \ + } + /* Static strings, used to invoke PyObject_CallMethodObjArgs */ static PyObject *str_call_conform; static PyObject *str_uncached_lookup; @@ -58,8 +62,12 @@ static PyObject *providedBy(PyObject *module, PyObject *ob); */ static PyObject* _get_module(PyTypeObject *typeobj); static PyObject* _get_adapter_hooks(PyTypeObject *typeobj); -static PyTypeObject* _get_specifcation_base_class(PyTypeObject *typeobj); +static PyTypeObject* _get_specification_base_class(PyTypeObject *typeobj); +static PyTypeObject* _get_interface_base_class(PyTypeObject *typeobj); +/* + * SpecificationBase class + */ typedef struct { PyObject_HEAD @@ -90,6 +98,10 @@ typedef struct static int Spec_traverse(Spec* self, visitproc visit, void* arg) { +/* Visit our 'tp_type' only on Python >= 3.9 */ +#if PY_VERSION_HEX > 0x03090000 + Py_VISIT(Py_TYPE(self)); +#endif Py_VISIT(self->_implied); Py_VISIT(self->_dependents); Py_VISIT(self->_bases); @@ -114,14 +126,14 @@ Spec_clear(Spec* self) static void Spec_dealloc(Spec* self) { - /* PyType_GenericAlloc that you get when you don't - specify a tp_alloc always tracks the object. */ PyObject_GC_UnTrack((PyObject*)self); + PyTypeObject* tp = Py_TYPE(self); if (self->weakreflist != NULL) { PyObject_ClearWeakRefs(OBJECT(self)); } Spec_clear(self); - Py_TYPE(self)->tp_free(OBJECT(self)); + tp->tp_free(OBJECT(self)); + Py_DECREF(tp); } static char Spec_extends__doc__[] = @@ -164,7 +176,7 @@ Spec_providedBy(PyObject* self, PyObject* ob) PyTypeObject *specification_base_class; module = _get_module(Py_TYPE(self)); - specification_base_class = _get_specifcation_base_class(Py_TYPE(self)); + specification_base_class = _get_specification_base_class(Py_TYPE(self)); decl = providedBy(module, ob); if (decl == NULL) @@ -195,7 +207,7 @@ Spec_implementedBy(PyObject* self, PyObject* cls) PyTypeObject *specification_base_class; module = _get_module(Py_TYPE(self)); - specification_base_class = _get_specifcation_base_class(Py_TYPE(self)); + specification_base_class = _get_specification_base_class(Py_TYPE(self)); decl = implementedBy(module, cls); if (decl == NULL) @@ -231,26 +243,60 @@ static PyMemberDef Spec_members[] = { { "_v_attrs", T_OBJECT_EX, offsetof(Spec, _v_attrs), 0, "" }, { "__iro__", T_OBJECT_EX, offsetof(Spec, __iro__), 0, "" }, { "__sro__", T_OBJECT_EX, offsetof(Spec, __sro__), 0, "" }, + {"__weaklistoffset__", Py_T_PYSSIZET, + offsetof(Spec, weakreflist), Py_READONLY}, { NULL }, }; static char Spec__doc__[] = "Base type for Specification objects"; -static PyTypeObject SpecificationBaseType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name="_interface_coptimizations.SpecificationBase", - .tp_doc=Spec__doc__, - .tp_basicsize=sizeof(Spec), - .tp_flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .tp_weaklistoffset=offsetof(Spec, weakreflist), - .tp_methods=Spec_methods, - .tp_members=Spec_members, - .tp_call=(ternaryfunc)Spec_call, - .tp_traverse=(traverseproc)Spec_traverse, - .tp_clear=(inquiry)Spec_clear, - .tp_dealloc=(destructor)Spec_dealloc, +/* + * Heap-based type: SpecificationBase + */ + +static PyType_Slot Spec_type_slots[] = { + {Py_tp_doc, Spec__doc__}, + {Py_tp_dealloc, Spec_dealloc}, + {Py_tp_call, Spec_call}, + {Py_tp_traverse, Spec_traverse}, + {Py_tp_clear, Spec_clear}, + {Py_tp_methods, Spec_methods}, + {Py_tp_members, Spec_members}, + {0, NULL} +}; + +static PyType_Spec Spec_type_spec = { + .name="zope.interface.interface.SpecificationBase", + .basicsize=sizeof(Spec), + .flags=Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + /* Only added in Python 3.11 */ + /* Py_TPFLAGS_MANAGED_WEAKREF | */ + Py_TPFLAGS_HAVE_GC, + .slots=Spec_type_slots }; +/* + * ObjectSpecificationDescriptor class + */ +static int +OSD_traverse(PyObject* self, visitproc visit, void* arg) +{ +#if PY_VERSION_HEX > 0x03090000 + Py_VISIT(Py_TYPE(self)); +#endif + return 0; +} + +static void +OSD_dealloc(PyObject* self) +{ + PyObject_GC_UnTrack(self); + PyTypeObject *tp = Py_TYPE(self); + tp->tp_free(OBJECT(self)); + Py_DECREF(tp); +} + static PyObject* OSD_descr_get(PyObject* self, PyObject* inst, PyObject* cls) { @@ -277,14 +323,30 @@ OSD_descr_get(PyObject* self, PyObject* inst, PyObject* cls) static char OSD__doc__[] = "Object Specification Descriptor"; -static PyTypeObject OSDType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name="_interface_coptimizations.ObjectSpecificationDescriptor", - .tp_doc=OSD__doc__, - .tp_flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_descr_get=(descrgetfunc)OSD_descr_get, +/* + * Heap type: ObjectSpecificationDescriptor + */ +static PyType_Slot OSD_type_slots[] = { + {Py_tp_doc, OSD__doc__}, + {Py_tp_descr_get, OSD_descr_get}, + {Py_tp_traverse, OSD_traverse}, + {Py_tp_dealloc, OSD_dealloc}, + {0, NULL} +}; + +static PyType_Spec OSD_type_spec = { + .name="_interface_coptimizations.ObjectSpecificationDescriptor", + .basicsize=0, + .flags=Py_TPFLAGS_DEFAULT | + /* Only added in Python 3.11 */ + /* Py_TPFLAGS_MANAGED_WEAKREF | */ + Py_TPFLAGS_HAVE_GC, + .slots=OSD_type_slots }; +/* + * ClassProviderBase class + */ typedef struct { Spec spec; @@ -293,29 +355,6 @@ typedef struct PyObject* _implements; } CPB; -static PyObject* -CPB_descr_get(CPB* self, PyObject* inst, PyObject* cls) -{ - PyObject* implements; - - if (self->_cls == NULL) - return NULL; - - if (cls == self->_cls) { - if (inst == NULL) { - Py_INCREF(self); - return OBJECT(self); - } - - implements = self->_implements; - Py_XINCREF(implements); - return implements; - } - - PyErr_SetString(PyExc_AttributeError, "__provides__"); - return NULL; -} - static int CPB_traverse(CPB* self, visitproc visit, void* arg) { @@ -338,7 +377,30 @@ CPB_dealloc(CPB* self) { PyObject_GC_UnTrack((PyObject*)self); CPB_clear(self); - Spec_dealloc((Spec*)self); + Spec_dealloc((Spec*)self); /* handles decrefing tp */ +} + +static PyObject* +CPB_descr_get(CPB* self, PyObject* inst, PyObject* cls) +{ + PyObject* implements; + + if (self->_cls == NULL) + return NULL; + + if (cls == self->_cls) { + if (inst == NULL) { + Py_INCREF(self); + return OBJECT(self); + } + + implements = self->_implements; + Py_XINCREF(implements); + return implements; + } + + PyErr_SetString(PyExc_AttributeError, "__provides__"); + return NULL; } static PyMemberDef CPB_members[] = { @@ -353,22 +415,86 @@ static PyMemberDef CPB_members[] = { static char CPB__doc__[] = "C Base class for ClassProvides"; -static PyTypeObject CPBType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name="_interface_coptimizations.ClassProvidesBase", - .tp_doc=CPB__doc__, - .tp_basicsize=sizeof(CPB), - .tp_flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .tp_base=&SpecificationBaseType, - .tp_members=CPB_members, - .tp_descr_get=(descrgetfunc)CPB_descr_get, - .tp_clear=(inquiry)CPB_clear, - .tp_traverse=(traverseproc)CPB_traverse, - .tp_dealloc=(destructor)CPB_dealloc, +/* + * Heap type: ClassProvidesBase + */ +static PyType_Slot CPB_type_slots[] = { + {Py_tp_doc, CPB__doc__}, + {Py_tp_dealloc, CPB_dealloc}, + {Py_tp_traverse, CPB_traverse}, + {Py_tp_clear, CPB_clear}, + {Py_tp_members, CPB_members}, + {Py_tp_descr_get, CPB_descr_get}, + /* tp_base cannot be set as a stot -- pass to PyType_FromModuleAndSpec */ + {0, NULL} +}; + +static PyType_Spec CPB_type_spec = { + .name="zope.interface.interface.ClassProvidesBase", + .basicsize=sizeof(CPB), + .flags=Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + /* Only added in Python 3.11 */ + /* Py_TPFLAGS_MANAGED_WEAKREF | */ + Py_TPFLAGS_HAVE_GC, + .slots=CPB_type_slots }; -/* ==================================================================== */ -/* ========== Begin: __call__ and __adapt__ =========================== */ + +/* + * InterfaceBase class + */ + +typedef struct +{ + Spec spec; + PyObject* __name__; + PyObject* __module__; + Py_hash_t _v_cached_hash; +} IB; + +static int +IB_traverse(IB* self, visitproc visit, void* arg) +{ + Py_VISIT(self->__name__); + Py_VISIT(self->__module__); + return Spec_traverse((Spec*)self, visit, arg); +} + +static int +IB_clear(IB* self) +{ + Py_CLEAR(self->__name__); + Py_CLEAR(self->__module__); + return Spec_clear((Spec*)self); +} + +static void +IB_dealloc(IB* self) +{ + PyObject_GC_UnTrack((PyObject*)self); + IB_clear(self); + Spec_dealloc((Spec*)self); /* handles decrefing tp */ +} + +static int +IB_init(IB* self, PyObject* args, PyObject* kwargs) +{ + static char* kwlist[] = { "__name__", "__module__", NULL }; + PyObject* module = NULL; + PyObject* name = NULL; + + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "|OO:InterfaceBase.__init__", kwlist, &name, &module)) { + return -1; + } + IB_clear(self); + self->__module__ = module ? module : Py_None; + Py_INCREF(self->__module__); + self->__name__ = name ? name : Py_None; + Py_INCREF(self->__name__); + return 0; +} /* def __adapt__(self, obj): @@ -384,14 +510,17 @@ static PyTypeObject CPBType = { */ +const char IB__adapt____doc__[] = "Adapt an object to the receiver"; + static PyObject* -__adapt__(PyObject* self, PyObject* obj) +IB__adapt__(PyObject* self, PyObject* obj) { PyObject *decl; PyObject *args; PyObject *adapter; PyObject *module; PyObject *adapter_hooks; + PyTypeObject *specification_base_class; int implements; int i; int l; @@ -402,7 +531,9 @@ __adapt__(PyObject* self, PyObject* obj) if (decl == NULL) return NULL; - if (PyObject_TypeCheck(decl, &SpecificationBaseType)) { + specification_base_class = _get_specification_base_class(Py_TYPE(self)); + + if (PyObject_TypeCheck(decl, specification_base_class)) { PyObject* implied; implied = ((Spec*)decl)->_implied; @@ -457,22 +588,6 @@ __adapt__(PyObject* self, PyObject* obj) return Py_None; } -typedef struct -{ - Spec spec; - PyObject* __name__; - PyObject* __module__; - Py_hash_t _v_cached_hash; -} IB; - -static struct PyMethodDef ib_methods[] = { - { "__adapt__", - (PyCFunction)__adapt__, - METH_O, - "Adapt an object to the receiver" }, - { NULL, NULL } /* sentinel */ -}; - /* def __call__(self, obj, alternate=_marker): try: @@ -495,7 +610,7 @@ static struct PyMethodDef ib_methods[] = { */ static PyObject* -IB_call(PyObject* self, PyObject* args, PyObject* kwargs) +IB__call__(PyObject* self, PyObject* args, PyObject* kwargs) { PyObject *conform, *obj, *alternate, *adapter; static char* kwlist[] = { "obj", "alternate", NULL }; @@ -539,7 +654,7 @@ IB_call(PyObject* self, PyObject* args, PyObject* kwargs) /* Doesn't matter what the value is. Simply being present is enough. */ adapter = PyObject_CallMethodObjArgs(self, str__adapt__, obj, NULL); } else { - adapter = __adapt__(self, obj); + adapter = IB__adapt__(self, obj); } if (adapter == NULL || adapter != Py_None) { @@ -560,39 +675,6 @@ IB_call(PyObject* self, PyObject* args, PyObject* kwargs) return NULL; } -static int -IB_traverse(IB* self, visitproc visit, void* arg) -{ - Py_VISIT(self->__name__); - Py_VISIT(self->__module__); - return Spec_traverse((Spec*)self, visit, arg); -} - -static int -IB_clear(IB* self) -{ - Py_CLEAR(self->__name__); - Py_CLEAR(self->__module__); - return Spec_clear((Spec*)self); -} - -static void -IB_dealloc(IB* self) -{ - PyObject_GC_UnTrack((PyObject*)self); - IB_clear(self); - Spec_dealloc((Spec*)self); -} - -static PyMemberDef IB_members[] = { - { "__name__", T_OBJECT_EX, offsetof(IB, __name__), 0, "" }, - // The redundancy between __module__ and __ibmodule__ is because - // __module__ is often shadowed by subclasses. - { "__module__", T_OBJECT_EX, offsetof(IB, __module__), READONLY, "" }, - { "__ibmodule__", T_OBJECT_EX, offsetof(IB, __module__), 0, "" }, - { NULL } -}; - static Py_hash_t IB_hash(IB* self) { @@ -619,14 +701,13 @@ IB_hash(IB* self) return self->_v_cached_hash; } -static PyTypeObject InterfaceBaseType; - static PyObject* IB_richcompare(IB* self, PyObject* other, int op) { PyObject* othername; PyObject* othermod; PyObject* oresult; + PyTypeObject* interface_base_class; IB* otherib; int result; @@ -656,7 +737,13 @@ IB_richcompare(IB* self, PyObject* other, int op) } } - if (PyObject_TypeCheck(other, &InterfaceBaseType)) { + interface_base_class = _get_interface_base_class(Py_TYPE(self)); + if (interface_base_class == NULL) { + oresult = Py_NotImplemented; + goto cleanup; + } + + if (PyObject_TypeCheck(other, interface_base_class)) { // This branch borrows references. No need to clean // up if otherib is not null. otherib = (IB*)other; @@ -708,53 +795,57 @@ IB_richcompare(IB* self, PyObject* other, int op) return oresult; } -static int -IB_init(IB* self, PyObject* args, PyObject* kwargs) -{ - static char* kwlist[] = { "__name__", "__module__", NULL }; - PyObject* module = NULL; - PyObject* name = NULL; +static PyMemberDef IB_members[] = { + { "__name__", T_OBJECT_EX, offsetof(IB, __name__), 0, "" }, + // The redundancy between __module__ and __ibmodule__ is because + // __module__ is often shadowed by subclasses. + { "__module__", T_OBJECT_EX, offsetof(IB, __module__), READONLY, "" }, + { "__ibmodule__", T_OBJECT_EX, offsetof(IB, __module__), 0, "" }, + { NULL } +}; - if (!PyArg_ParseTupleAndKeywords( - args, kwargs, "|OO:InterfaceBase.__init__", kwlist, &name, &module)) { - return -1; - } - IB_clear(self); - self->__module__ = module ? module : Py_None; - Py_INCREF(self->__module__); - self->__name__ = name ? name : Py_None; - Py_INCREF(self->__name__); - return 0; -} +static struct PyMethodDef IB_methods[] = { + { "__adapt__", (PyCFunction)IB__adapt__, METH_O, IB__adapt____doc__}, + { NULL, NULL } /* sentinel */ +}; static char IB__doc__[] = ( "Interface base type providing __call__ and __adapt__" ); -static PyTypeObject InterfaceBaseType = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name="_zope_interface_coptimizations.InterfaceBase", - .tp_doc=IB__doc__, - .tp_basicsize=sizeof(IB), - .tp_flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .tp_base=&SpecificationBaseType, - .tp_methods=ib_methods, - .tp_members=IB_members, - .tp_init=(initproc)IB_init, - .tp_richcompare=(richcmpfunc)IB_richcompare, - .tp_hash=(hashfunc)IB_hash, - .tp_call=(ternaryfunc)IB_call, - .tp_traverse=(traverseproc)IB_traverse, - .tp_clear=(inquiry)IB_clear, - .tp_dealloc=(destructor)IB_dealloc, +/* + * Heap type: InterfaceBase + */ +static PyType_Slot IB_type_slots[] = { + {Py_tp_doc, IB__doc__}, + {Py_tp_dealloc, IB_dealloc}, + {Py_tp_hash, IB_hash}, + {Py_tp_call, IB__call__}, + {Py_tp_traverse, IB_traverse}, + {Py_tp_clear, IB_clear}, + {Py_tp_richcompare, IB_richcompare}, + {Py_tp_methods, IB_methods}, + {Py_tp_members, IB_members}, + {Py_tp_init, IB_init}, + /* tp_base cannot be set as a stot -- pass to PyType_FromModuleAndSpec */ + {0, NULL} }; -/* =================== End: __call__ and __adapt__ ==================== */ -/* ==================================================================== */ +static PyType_Spec IB_type_spec = { + .name="zope.interface.interface.InterfaceBase", + .basicsize=sizeof(IB), + .flags=Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + /* Only added in Python 3.11 */ + /* Py_TPFLAGS_MANAGED_WEAKREF | */ + Py_TPFLAGS_HAVE_GC, + .slots=IB_type_slots +}; -/* ==================================================================== */ -/* ========================== Begin: Lookup Bases ===================== */ +/* + * LookupBase class + */ typedef struct { PyObject_HEAD @@ -763,39 +854,15 @@ typedef struct PyObject* _scache; } lookup; -typedef struct -{ - PyObject_HEAD - PyObject* _cache; - PyObject* _mcache; - PyObject* _scache; - PyObject* _verify_ro; - PyObject* _verify_generations; -} verify; - static int lookup_traverse(lookup* self, visitproc visit, void* arg) { - int vret; - - if (self->_cache) { - vret = visit(self->_cache, arg); - if (vret != 0) - return vret; - } - - if (self->_mcache) { - vret = visit(self->_mcache, arg); - if (vret != 0) - return vret; - } - - if (self->_scache) { - vret = visit(self->_scache, arg); - if (vret != 0) - return vret; - } - +#if PY_VERSION_HEX > 0x03090000 + Py_VISIT(Py_TYPE(self)); +#endif + Py_VISIT(self->_cache); + Py_VISIT(self->_mcache); + Py_VISIT(self->_scache); return 0; } @@ -812,8 +879,10 @@ static void lookup_dealloc(lookup* self) { PyObject_GC_UnTrack((PyObject*)self); + PyTypeObject* tp = Py_TYPE(self); lookup_clear(self); - Py_TYPE(self)->tp_free((PyObject*)self); + tp->tp_free((PyObject*)self); + Py_DECREF(tp); } /* @@ -830,13 +899,6 @@ lookup_changed(lookup* self, PyObject* ignored) return Py_None; } -#define ASSURE_DICT(N) \ - if (N == NULL) { \ - N = PyDict_New(); \ - if (N == NULL) \ - return NULL; \ - } - /* def _getcache(self, provided, name): cache = self._cache.get(provided) @@ -871,12 +933,14 @@ _subcache(PyObject* cache, PyObject* key) return subcache; } + static PyObject* _getcache(lookup* self, PyObject* provided, PyObject* name) { PyObject* cache; ASSURE_DICT(self->_cache); + cache = _subcache(self->_cache, provided); if (cache == NULL) return NULL; @@ -918,7 +982,7 @@ _lookup(lookup* self, PyObject *result, *key, *cache; result = key = cache = NULL; if (name && !PyUnicode_Check(name)) { - PyErr_SetString(PyExc_ValueError, "name is not a string or unicode"); + PyErr_SetString(PyExc_ValueError, "name is not a string"); return NULL; } @@ -967,6 +1031,7 @@ _lookup(lookup* self, return result; } + static PyObject* lookup_lookup(lookup* self, PyObject* args, PyObject* kwds) { @@ -1008,7 +1073,7 @@ _lookup1(lookup* self, PyObject *result, *cache; if (name && !PyUnicode_Check(name)) { - PyErr_SetString(PyExc_ValueError, "name is not a string or unicode"); + PyErr_SetString(PyExc_ValueError, "name is not a string"); return NULL; } @@ -1087,7 +1152,7 @@ _adapter_hook(lookup* self, module = _get_module(Py_TYPE(self)); if (name && !PyUnicode_Check(name)) { - PyErr_SetString(PyExc_ValueError, "name is not a string or unicode"); + PyErr_SetString(PyExc_ValueError, "name is not a string"); return NULL; } @@ -1126,6 +1191,7 @@ _adapter_hook(lookup* self, return default_; } + static PyObject* lookup_adapter_hook(lookup* self, PyObject* args, PyObject* kwds) { @@ -1190,6 +1256,7 @@ _lookupAll(lookup* self, PyObject* required, PyObject* provided) return NULL; ASSURE_DICT(self->_mcache); + cache = _subcache(self->_mcache, provided); if (cache == NULL) return NULL; @@ -1217,6 +1284,7 @@ _lookupAll(lookup* self, PyObject* required, PyObject* provided) return result; } + static PyObject* lookup_lookupAll(lookup* self, PyObject* args, PyObject* kwds) { @@ -1256,6 +1324,7 @@ _subscriptions(lookup* self, PyObject* required, PyObject* provided) return NULL; ASSURE_DICT(self->_scache); + cache = _subcache(self->_scache, provided); if (cache == NULL) return NULL; @@ -1283,6 +1352,7 @@ _subscriptions(lookup* self, PyObject* required, PyObject* provided) return result; } + static PyObject* lookup_subscriptions(lookup* self, PyObject* args, PyObject* kwds) { @@ -1324,56 +1394,60 @@ static struct PyMethodDef lookup_methods[] = { static char LookupBase__doc__[] = "Base class for adapter registries"; -static PyTypeObject LookupBase = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name="_zope_interface_coptimizations.LookupBase", - .tp_doc=LookupBase__doc__, - .tp_basicsize=sizeof(lookup), - .tp_flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .tp_methods=lookup_methods, - .tp_traverse=(traverseproc)lookup_traverse, - .tp_clear=(inquiry)lookup_clear, - .tp_dealloc=(destructor)&lookup_dealloc, -}; -static int -verifying_traverse(verify* self, visitproc visit, void* arg) -{ - int vret; +/* + * Heap type: LookupBase + */ +static PyType_Slot lookup_type_slots[] = { + {Py_tp_doc, LookupBase__doc__}, + {Py_tp_dealloc, lookup_dealloc}, + {Py_tp_traverse, lookup_traverse}, + {Py_tp_clear, lookup_clear}, + {Py_tp_methods, lookup_methods}, + {0, NULL} +}; - vret = lookup_traverse((lookup*)self, visit, arg); - if (vret != 0) - return vret; +static PyType_Spec lookup_type_spec = { + .name="_zope_interface_coptimizations.LookupBase", + .basicsize=sizeof(lookup), + .flags=Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_MANAGED_WEAKREF | + Py_TPFLAGS_HAVE_GC, + .slots=lookup_type_slots +}; - if (self->_verify_ro) { - vret = visit(self->_verify_ro, arg); - if (vret != 0) - return vret; - } - if (self->_verify_generations) { - vret = visit(self->_verify_generations, arg); - if (vret != 0) - return vret; - } +typedef struct +{ + lookup lookup; + PyObject* _verify_ro; + PyObject* _verify_generations; +} verify; - return 0; +static int +verify_traverse(verify* self, visitproc visit, void* arg) +{ + Py_VISIT(self->_verify_ro); + Py_VISIT(self->_verify_generations); + return lookup_traverse((lookup*)self, visit, arg); } static int -verifying_clear(verify* self) +verify_clear(verify* self) { - lookup_clear((lookup*)self); Py_CLEAR(self->_verify_generations); Py_CLEAR(self->_verify_ro); - return 0; + return lookup_clear((lookup*)self); } static void -verifying_dealloc(verify* self) +verify_dealloc(verify* self) { PyObject_GC_UnTrack((PyObject*)self); - verifying_clear(self); - Py_TYPE(self)->tp_free((PyObject*)self); + PyTypeObject *tp = Py_TYPE(self); + verify_clear(self); + tp->tp_free((PyObject*)self); + Py_DECREF(tp); } /* @@ -1405,11 +1479,11 @@ _generations_tuple(PyObject* ro) return generations; } static PyObject* -verifying_changed(verify* self, PyObject* ignored) +verify_changed(verify* self, PyObject* ignored) { PyObject *t, *ro; - verifying_clear(self); + verify_clear(self); t = PyObject_GetAttrString(OBJECT(self), "_registry"); if (t == NULL) @@ -1480,7 +1554,7 @@ _verify(verify* self) } static PyObject* -verifying_lookup(verify* self, PyObject* args, PyObject* kwds) +verify_lookup(verify* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "required", "provided", "name", "default", NULL }; PyObject *required, *provided, *name = NULL, *default_ = NULL; @@ -1496,7 +1570,7 @@ verifying_lookup(verify* self, PyObject* args, PyObject* kwds) } static PyObject* -verifying_lookup1(verify* self, PyObject* args, PyObject* kwds) +verify_lookup1(verify* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "required", "provided", "name", "default", NULL }; PyObject *required, *provided, *name = NULL, *default_ = NULL; @@ -1512,7 +1586,7 @@ verifying_lookup1(verify* self, PyObject* args, PyObject* kwds) } static PyObject* -verifying_adapter_hook(verify* self, PyObject* args, PyObject* kwds) +verify_adapter_hook(verify* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "provided", "object", "name", "default", NULL }; PyObject *object, *provided, *name = NULL, *default_ = NULL; @@ -1528,7 +1602,7 @@ verifying_adapter_hook(verify* self, PyObject* args, PyObject* kwds) } static PyObject* -verifying_queryAdapter(verify* self, PyObject* args, PyObject* kwds) +verify_queryAdapter(verify* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "object", "provided", "name", "default", NULL }; PyObject *object, *provided, *name = NULL, *default_ = NULL; @@ -1544,7 +1618,7 @@ verifying_queryAdapter(verify* self, PyObject* args, PyObject* kwds) } static PyObject* -verifying_lookupAll(verify* self, PyObject* args, PyObject* kwds) +verify_lookupAll(verify* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "required", "provided", NULL }; PyObject *required, *provided; @@ -1560,7 +1634,7 @@ verifying_lookupAll(verify* self, PyObject* args, PyObject* kwds) } static PyObject* -verifying_subscriptions(verify* self, PyObject* args, PyObject* kwds) +verify_subscriptions(verify* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "required", "provided", NULL }; PyObject *required, *provided; @@ -1575,30 +1649,30 @@ verifying_subscriptions(verify* self, PyObject* args, PyObject* kwds) return _subscriptions((lookup*)self, required, provided); } -static struct PyMethodDef verifying_methods[] = { - { "changed", (PyCFunction)verifying_changed, METH_O, "" }, +static struct PyMethodDef verify_methods[] = { + { "changed", (PyCFunction)verify_changed, METH_O, "" }, { "lookup", - (PyCFunction)verifying_lookup, + (PyCFunction)verify_lookup, METH_KEYWORDS | METH_VARARGS, "" }, { "lookup1", - (PyCFunction)verifying_lookup1, + (PyCFunction)verify_lookup1, METH_KEYWORDS | METH_VARARGS, "" }, { "queryAdapter", - (PyCFunction)verifying_queryAdapter, + (PyCFunction)verify_queryAdapter, METH_KEYWORDS | METH_VARARGS, "" }, { "adapter_hook", - (PyCFunction)verifying_adapter_hook, + (PyCFunction)verify_adapter_hook, METH_KEYWORDS | METH_VARARGS, "" }, { "lookupAll", - (PyCFunction)verifying_lookupAll, + (PyCFunction)verify_lookupAll, METH_KEYWORDS | METH_VARARGS, "" }, { "subscriptions", - (PyCFunction)verifying_subscriptions, + (PyCFunction)verify_subscriptions, METH_KEYWORDS | METH_VARARGS, "" }, { NULL, NULL } /* sentinel */ @@ -1608,19 +1682,30 @@ static char VerifyingBase__doc__[] = ( "Base class for verifying adapter registries." ); -static PyTypeObject VerifyingBase = { - PyVarObject_HEAD_INIT(NULL, 0) - .tp_name="_zope_interface_coptimizations.VerifyingBase", - .tp_doc=VerifyingBase__doc__, - .tp_basicsize=sizeof(verify), - .tp_flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, - .tp_base=&LookupBase, - .tp_methods=verifying_methods, - .tp_traverse=(traverseproc)verifying_traverse, - .tp_clear=(inquiry)verifying_clear, - .tp_dealloc=(destructor)&verifying_dealloc, +/* + * Heap type: VerifyingBase + */ +static PyType_Slot verify_type_slots[] = { + {Py_tp_doc, VerifyingBase__doc__}, + {Py_tp_dealloc, verify_dealloc}, + {Py_tp_traverse, verify_traverse}, + {Py_tp_clear, verify_clear}, + {Py_tp_methods, verify_methods}, + /* tp_base cannot be set as a stot -- pass to PyType_FromModuleAndSpec */ + {0, NULL} +}; + +static PyType_Spec verify_type_spec = { + .name="_zope_interface_coptimizations.VerifyingBase", + .basicsize=sizeof(verify), + .flags=Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_MANAGED_WEAKREF, + .slots=verify_type_slots }; + /* * Module state struct: holds all data formerly kept as static globals. */ @@ -1787,7 +1872,8 @@ static PyObject* _get_module(PyTypeObject *typeobj) { if (PyType_Check(typeobj)) { - return PyState_FindModule(&_zic_module); + /* Only added in Python 3.11 */ + return PyType_GetModuleByDef(typeobj, &_zic_module); } PyErr_SetString(PyExc_TypeError, "_get_module: called w/ non-type"); return NULL; @@ -1813,7 +1899,7 @@ _get_adapter_hooks(PyTypeObject *typeobj) * Fetch the 'SpecificationBase' class for the current type's module. */ static PyTypeObject* -_get_specifcation_base_class(PyTypeObject *typeobj) +_get_specification_base_class(PyTypeObject *typeobj) { PyObject* module; _zic_module_state* rec; @@ -1825,6 +1911,22 @@ _get_specifcation_base_class(PyTypeObject *typeobj) return rec->specification_base_class; } +/* + * Fetch the 'InterfaceBase' class for the current type's module. + */ +static PyTypeObject* +_get_interface_base_class(PyTypeObject *typeobj) +{ + PyObject* module; + _zic_module_state* rec; + + module = _get_module(typeobj); + if (module == NULL) { return NULL; } + + rec = _zic_state(module); + return rec->interface_base_class; +} + static PyObject* implementedByFallback(PyObject* module, PyObject* cls) { @@ -1953,6 +2055,7 @@ providedBy(PyObject* module, PyObject* ob) PyObject *result = NULL; PyObject *cls; PyObject *cp; + _zic_module_state *rec; int is_instance = -1; is_instance = PyObject_IsInstance(ob, (PyObject*)&PySuper_Type); @@ -1982,7 +2085,8 @@ providedBy(PyObject* module, PyObject* ob) because we may have a proxy, so we'll just try to get the only attribute. */ - if (PyObject_TypeCheck(result, &SpecificationBaseType) || + rec = _zic_state(module); + if (PyObject_TypeCheck(result, rec->specification_base_class) || PyObject_HasAttrString(result, "extends")) return result; @@ -2030,7 +2134,7 @@ providedBy(PyObject* module, PyObject* ob) return result; } -static struct PyMethodDef m_methods[] = { +static struct PyMethodDef _zic_module_methods[] = { { "implementedBy", (PyCFunction)implementedBy, METH_O, @@ -2044,123 +2148,132 @@ static struct PyMethodDef m_methods[] = { { NULL, (PyCFunction)NULL, 0, NULL } /* sentinel */ }; -static char module_doc[] = "C optimizations for zope.interface\n\n"; - -static struct PyModuleDef _zic_module = { - PyModuleDef_HEAD_INIT, - .m_name = "_zope_interface_coptimizations", - .m_doc = module_doc, - .m_size = sizeof(_zic_module_state), - .m_methods = m_methods, - /*.m_slots=m_slots,*/ - .m_traverse = _zic_state_traverse, - .m_clear = _zic_state_clear, -}; - -static PyObject* -init(void) -{ - PyObject* module; - -#define DEFINE_STRING(S) \ - if (!(str##S = PyUnicode_FromString(#S))) \ - return NULL - - DEFINE_STRING(__implemented__); - DEFINE_STRING(_call_conform); - DEFINE_STRING(_uncached_lookup); - DEFINE_STRING(_uncached_lookupAll); - DEFINE_STRING(_uncached_subscriptions); - DEFINE_STRING(changed); - DEFINE_STRING(__adapt__); -#undef DEFINE_STRING - - /* - * To be replaced by a call to PyModuleDef_Init(&_zic_module); - * the function will just return the initilized module def structure, - * allowing the interpreter to create a new module instance - */ - module = PyModule_Create(&_zic_module); - if (module == NULL) - return NULL; - - /* - * Below this point, the rest of the function will move to - * the 'mod_exec' phase (run only after the interpreter has - * created the new module instance). - */ +/* Handler for the 'execute' phase of multi-phase initialization + * + * See: https://docs.python.org/3/c-api/module.html#multi-phase-initialization + * and: https://peps.python.org/pep-0489/#module-execution-phase + */ +static int +_zic_module_exec(PyObject* module) +{ + PyObject *sb_class; + PyObject *osd_class; + PyObject *cpb_class; + PyObject *ib_class; + PyObject *lb_class; + PyObject *vb_class; _zic_module_state* rec = _zic_state_init(module); rec->adapter_hooks = PyList_New(0); if (rec->adapter_hooks == NULL) - return NULL; + return -1; /* Initialize types: - * Static types are only here until we complete the module state / - * multi-phase initializtion bit. */ - SpecificationBaseType.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&SpecificationBaseType) < 0) - return NULL; - rec->specification_base_class = &SpecificationBaseType; + sb_class = PyType_FromModuleAndSpec(module, &Spec_type_spec, NULL); + if (sb_class == NULL) { return -1; } + rec->specification_base_class = TYPE(sb_class); - OSDType.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&OSDType) < 0) - return NULL; - rec->object_specification_descriptor_class = &OSDType; + osd_class = PyType_FromModuleAndSpec(module, &OSD_type_spec, NULL); + if (osd_class == NULL) { return -1; } + rec->object_specification_descriptor_class = TYPE(osd_class); - CPBType.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&CPBType) < 0) - return NULL; - rec->class_provides_base_class = &CPBType; + cpb_class = PyType_FromModuleAndSpec(module, &CPB_type_spec, sb_class); + if (cpb_class == NULL) { return -1; } + rec->class_provides_base_class = TYPE(cpb_class); - InterfaceBaseType.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&InterfaceBaseType) < 0) - return NULL; - rec->interface_base_class = &InterfaceBaseType; + ib_class = PyType_FromModuleAndSpec(module, &IB_type_spec, sb_class); + if (ib_class == NULL) { return -1; } + rec->interface_base_class = TYPE(ib_class); - LookupBase.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&LookupBase) < 0) - return NULL; - rec->lookup_base_class = &LookupBase; + lb_class = PyType_FromModuleAndSpec(module, &lookup_type_spec, NULL); + if (lb_class == NULL) { return -1; } + rec->lookup_base_class = TYPE(lb_class); - VerifyingBase.tp_new = PyBaseObject_Type.tp_new; - if (PyType_Ready(&VerifyingBase) < 0) - return NULL; - rec->verifying_base_class = &VerifyingBase; + vb_class = PyType_FromModuleAndSpec(module, &verify_type_spec, lb_class); + if (vb_class == NULL) { return -1; } + rec->verifying_base_class = TYPE(vb_class); /* Add types to our dict FBO python; also the adapter hooks */ if (PyModule_AddObject(module, "SpecificationBase", OBJECT(rec->specification_base_class)) < 0) - return NULL; + return -1; if (PyModule_AddObject(module, "ObjectSpecificationDescriptor", OBJECT(rec->object_specification_descriptor_class)) < 0) - return NULL; + return -1; if (PyModule_AddObject(module, "ClassProvidesBase", OBJECT(rec->class_provides_base_class)) < 0) - return NULL; + return -1; if (PyModule_AddObject(module, "InterfaceBase", OBJECT(rec->interface_base_class)) < 0) - return NULL; + return -1; if (PyModule_AddObject(module, "LookupBase", OBJECT(rec->lookup_base_class)) < 0) - return NULL; + return -1; if (PyModule_AddObject(module, "VerifyingBase", OBJECT(rec->verifying_base_class)) < 0) - return NULL; + return -1; if (PyModule_AddObject(module, "adapter_hooks", rec->adapter_hooks) < 0) - return NULL; + return -1; + + return 0; +} + + +/* Slot definitions for multi-phase initialization + * + * See: https://docs.python.org/3/c-api/module.html#multi-phase-initialization + * and: https://peps.python.org/pep-0489 + */ +static PyModuleDef_Slot _zic_module_slots[] = { + {Py_mod_exec, _zic_module_exec}, + {0, NULL} +}; + +static char _zic_module__doc__[] = "C optimizations for zope.interface\n\n"; + +static struct PyModuleDef _zic_module = { + PyModuleDef_HEAD_INIT, + .m_name = "_zope_interface_coptimizations", + .m_doc = _zic_module__doc__, + .m_size = sizeof(_zic_module_state), + .m_methods = _zic_module_methods, + .m_slots=_zic_module_slots, + .m_traverse = _zic_state_traverse, + .m_clear = _zic_state_clear, +}; + +static PyObject* +init(void) +{ +#define DEFINE_STRING(S) \ + if (!(str##S = PyUnicode_FromString(#S))) \ + return NULL + + DEFINE_STRING(__implemented__); + DEFINE_STRING(_call_conform); + DEFINE_STRING(_uncached_lookup); + DEFINE_STRING(_uncached_lookupAll); + DEFINE_STRING(_uncached_subscriptions); + DEFINE_STRING(changed); + DEFINE_STRING(__adapt__); +#undef DEFINE_STRING - return module; + /* + * To be replaced by a call to PyModuleDef_Init(&_zic_module); + * the function will just return the initilized module def structure, + * allowing the interpreter to create a new module instance + */ + return PyModuleDef_Init(&_zic_module); } PyMODINIT_FUNC From 0e315d88af96b4839dfe6ac1252f6e12299fa528 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 15:35:15 -0400 Subject: [PATCH 25/39] chore: work around 'InterfaceBase.__module__' returning descriptor --- src/zope/interface/declarations.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/zope/interface/declarations.py b/src/zope/interface/declarations.py index 87e62520..8a6e3418 100644 --- a/src/zope/interface/declarations.py +++ b/src/zope/interface/declarations.py @@ -353,8 +353,13 @@ def _implements_name(ob): # equality and hashing is still based on identity. # It might be nice to use __qualname__ on Python 3, but that would produce # different values between Py2 and Py3. - return (getattr(ob, '__module__', '?') or '?') + \ - '.' + (getattr(ob, '__name__', '?') or '?') + + # Workaround: some C-based interfaces return a 'member_descriptor' for + # their '__module__'. + mod = getattr(ob, '__module__', None) + if not isinstance(mod, str): + mod = getattr(mod, '__name__', '?') + return mod + '.' + (getattr(ob, '__name__', '?') or '?') def _implementedBy_super(sup): From 4b3e9db743ecbf70ba31e3c9ba3c5f16e68536b7 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 15:52:11 -0400 Subject: [PATCH 26/39] refactor: use 'Py_TPFLAGS_MANAGED_WEAKREF' everywhere Drop vestiges of manual 'weakreflist' management. Rename type structs and methods for consistency. --- .../_zope_interface_coptimizations.c | 300 +++++++++--------- 1 file changed, 146 insertions(+), 154 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 275b7a5c..b1481cc2 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -71,7 +71,6 @@ static PyTypeObject* _get_interface_base_class(PyTypeObject *typeobj); typedef struct { PyObject_HEAD - PyObject* weakreflist; /* In the past, these fields were stored in the __dict__ and were technically allowed to contain any Python object, though @@ -89,14 +88,14 @@ typedef struct PyObject* _v_attrs; PyObject* __iro__; PyObject* __sro__; -} Spec; +} SB; /* We know what the fields are *supposed* to define, but they could have anything, so we need to traverse them. */ static int -Spec_traverse(Spec* self, visitproc visit, void* arg) +SB_traverse(SB* self, visitproc visit, void* arg) { /* Visit our 'tp_type' only on Python >= 3.9 */ #if PY_VERSION_HEX > 0x03090000 @@ -112,7 +111,7 @@ Spec_traverse(Spec* self, visitproc visit, void* arg) } static int -Spec_clear(Spec* self) +SB_clear(SB* self) { Py_CLEAR(self->_implied); Py_CLEAR(self->_dependents); @@ -124,23 +123,20 @@ Spec_clear(Spec* self) } static void -Spec_dealloc(Spec* self) +SB_dealloc(SB* self) { PyObject_GC_UnTrack((PyObject*)self); PyTypeObject* tp = Py_TYPE(self); - if (self->weakreflist != NULL) { - PyObject_ClearWeakRefs(OBJECT(self)); - } - Spec_clear(self); + SB_clear(self); tp->tp_free(OBJECT(self)); Py_DECREF(tp); } -static char Spec_extends__doc__[] = +static char SB_extends__doc__[] = "Test whether a specification is or extends another"; static PyObject* -Spec_extends(Spec* self, PyObject* other) +SB_extends(SB* self, PyObject* other) { PyObject* implied; @@ -155,20 +151,20 @@ Spec_extends(Spec* self, PyObject* other) } static PyObject* -Spec_call(Spec* self, PyObject* args, PyObject* kw) +SB__call__(SB* self, PyObject* args, PyObject* kw) { PyObject* spec; if (!PyArg_ParseTuple(args, "O", &spec)) return NULL; - return Spec_extends(self, spec); + return SB_extends(self, spec); } -static char Spec_providedBy__doc__[] = +static char SB_providedBy__doc__[] = "Test whether an interface is implemented by the specification"; static PyObject* -Spec_providedBy(PyObject* self, PyObject* ob) +SB_providedBy(PyObject* self, PyObject* ob) { PyObject *decl; PyObject *item; @@ -183,7 +179,7 @@ Spec_providedBy(PyObject* self, PyObject* ob) return NULL; if (PyObject_TypeCheck(decl, specification_base_class)) - item = Spec_extends((Spec*)decl, self); + item = SB_extends((SB*)decl, self); else /* decl is probably a security proxy. We have to go the long way around. @@ -194,12 +190,12 @@ Spec_providedBy(PyObject* self, PyObject* ob) return item; } -static char Spec_implementedBy__doc__[] = +static char SB_implementedBy__doc__[] = "Test whether the specification is implemented by a class or factory.\n" "Raise TypeError if argument is neither a class nor a callable."; static PyObject* -Spec_implementedBy(PyObject* self, PyObject* cls) +SB_implementedBy(PyObject* self, PyObject* cls) { PyObject *decl; PyObject *item; @@ -214,7 +210,7 @@ Spec_implementedBy(PyObject* self, PyObject* cls) return NULL; if (PyObject_TypeCheck(decl, specification_base_class)) - item = Spec_extends((Spec*)decl, self); + item = SB_extends((SB*)decl, self); else item = PyObject_CallFunctionObjArgs(decl, self, NULL); @@ -222,58 +218,57 @@ Spec_implementedBy(PyObject* self, PyObject* cls) return item; } -static struct PyMethodDef Spec_methods[] = { +static struct PyMethodDef SB_methods[] = { { "providedBy", - (PyCFunction)Spec_providedBy, + (PyCFunction)SB_providedBy, METH_O, - Spec_providedBy__doc__ }, + SB_providedBy__doc__ }, { "implementedBy", - (PyCFunction)Spec_implementedBy, + (PyCFunction)SB_implementedBy, + METH_O, + SB_implementedBy__doc__ }, + { "isOrExtends", + (PyCFunction)SB_extends, METH_O, - Spec_implementedBy__doc__ }, - { "isOrExtends", (PyCFunction)Spec_extends, METH_O, Spec_extends__doc__ }, + SB_extends__doc__ }, { NULL, NULL } /* sentinel */ }; -static PyMemberDef Spec_members[] = { - { "_implied", T_OBJECT_EX, offsetof(Spec, _implied), 0, "" }, - { "_dependents", T_OBJECT_EX, offsetof(Spec, _dependents), 0, "" }, - { "_bases", T_OBJECT_EX, offsetof(Spec, _bases), 0, "" }, - { "_v_attrs", T_OBJECT_EX, offsetof(Spec, _v_attrs), 0, "" }, - { "__iro__", T_OBJECT_EX, offsetof(Spec, __iro__), 0, "" }, - { "__sro__", T_OBJECT_EX, offsetof(Spec, __sro__), 0, "" }, - {"__weaklistoffset__", Py_T_PYSSIZET, - offsetof(Spec, weakreflist), Py_READONLY}, +static PyMemberDef SB_members[] = { + { "_implied", T_OBJECT_EX, offsetof(SB, _implied), 0, "" }, + { "_dependents", T_OBJECT_EX, offsetof(SB, _dependents), 0, "" }, + { "_bases", T_OBJECT_EX, offsetof(SB, _bases), 0, "" }, + { "_v_attrs", T_OBJECT_EX, offsetof(SB, _v_attrs), 0, "" }, + { "__iro__", T_OBJECT_EX, offsetof(SB, __iro__), 0, "" }, + { "__sro__", T_OBJECT_EX, offsetof(SB, __sro__), 0, "" }, { NULL }, }; -static char Spec__doc__[] = "Base type for Specification objects"; +static char SB__doc__[] = "Base type for Specification objects"; /* * Heap-based type: SpecificationBase */ - -static PyType_Slot Spec_type_slots[] = { - {Py_tp_doc, Spec__doc__}, - {Py_tp_dealloc, Spec_dealloc}, - {Py_tp_call, Spec_call}, - {Py_tp_traverse, Spec_traverse}, - {Py_tp_clear, Spec_clear}, - {Py_tp_methods, Spec_methods}, - {Py_tp_members, Spec_members}, +static PyType_Slot SB_type_slots[] = { + {Py_tp_doc, SB__doc__}, + {Py_tp_dealloc, SB_dealloc}, + {Py_tp_call, SB__call__}, + {Py_tp_traverse, SB_traverse}, + {Py_tp_clear, SB_clear}, + {Py_tp_methods, SB_methods}, + {Py_tp_members, SB_members}, {0, NULL} }; -static PyType_Spec Spec_type_spec = { +static PyType_Spec SB_type_spec = { .name="zope.interface.interface.SpecificationBase", - .basicsize=sizeof(Spec), + .basicsize=sizeof(SB), .flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - /* Only added in Python 3.11 */ - /* Py_TPFLAGS_MANAGED_WEAKREF | */ + Py_TPFLAGS_MANAGED_WEAKREF | Py_TPFLAGS_HAVE_GC, - .slots=Spec_type_slots + .slots=SB_type_slots }; /* @@ -338,8 +333,7 @@ static PyType_Spec OSD_type_spec = { .name="_interface_coptimizations.ObjectSpecificationDescriptor", .basicsize=0, .flags=Py_TPFLAGS_DEFAULT | - /* Only added in Python 3.11 */ - /* Py_TPFLAGS_MANAGED_WEAKREF | */ + Py_TPFLAGS_MANAGED_WEAKREF | Py_TPFLAGS_HAVE_GC, .slots=OSD_type_slots }; @@ -349,8 +343,8 @@ static PyType_Spec OSD_type_spec = { */ typedef struct { - Spec spec; - /* These members are handled generically, as for Spec members. */ + SB spec; + /* These members are handled generically, as for SB members. */ PyObject* _cls; PyObject* _implements; } CPB; @@ -360,7 +354,7 @@ CPB_traverse(CPB* self, visitproc visit, void* arg) { Py_VISIT(self->_cls); Py_VISIT(self->_implements); - return Spec_traverse((Spec*)self, visit, arg); + return SB_traverse((SB*)self, visit, arg); } static int @@ -368,7 +362,7 @@ CPB_clear(CPB* self) { Py_CLEAR(self->_cls); Py_CLEAR(self->_implements); - Spec_clear((Spec*)self); + SB_clear((SB*)self); return 0; } @@ -377,7 +371,7 @@ CPB_dealloc(CPB* self) { PyObject_GC_UnTrack((PyObject*)self); CPB_clear(self); - Spec_dealloc((Spec*)self); /* handles decrefing tp */ + SB_dealloc((SB*)self); /* handles decrefing tp */ } static PyObject* @@ -434,8 +428,7 @@ static PyType_Spec CPB_type_spec = { .basicsize=sizeof(CPB), .flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - /* Only added in Python 3.11 */ - /* Py_TPFLAGS_MANAGED_WEAKREF | */ + Py_TPFLAGS_MANAGED_WEAKREF | Py_TPFLAGS_HAVE_GC, .slots=CPB_type_slots }; @@ -447,7 +440,7 @@ static PyType_Spec CPB_type_spec = { typedef struct { - Spec spec; + SB spec; PyObject* __name__; PyObject* __module__; Py_hash_t _v_cached_hash; @@ -458,7 +451,7 @@ IB_traverse(IB* self, visitproc visit, void* arg) { Py_VISIT(self->__name__); Py_VISIT(self->__module__); - return Spec_traverse((Spec*)self, visit, arg); + return SB_traverse((SB*)self, visit, arg); } static int @@ -466,7 +459,7 @@ IB_clear(IB* self) { Py_CLEAR(self->__name__); Py_CLEAR(self->__module__); - return Spec_clear((Spec*)self); + return SB_clear((SB*)self); } static void @@ -474,11 +467,11 @@ IB_dealloc(IB* self) { PyObject_GC_UnTrack((PyObject*)self); IB_clear(self); - Spec_dealloc((Spec*)self); /* handles decrefing tp */ + SB_dealloc((SB*)self); /* handles decrefing tp */ } static int -IB_init(IB* self, PyObject* args, PyObject* kwargs) +IB__init__(IB* self, PyObject* args, PyObject* kwargs) { static char* kwlist[] = { "__name__", "__module__", NULL }; PyObject* module = NULL; @@ -536,7 +529,7 @@ IB__adapt__(PyObject* self, PyObject* obj) if (PyObject_TypeCheck(decl, specification_base_class)) { PyObject* implied; - implied = ((Spec*)decl)->_implied; + implied = ((SB*)decl)->_implied; if (implied == NULL) { Py_DECREF(decl); return NULL; @@ -676,7 +669,7 @@ IB__call__(PyObject* self, PyObject* args, PyObject* kwargs) } static Py_hash_t -IB_hash(IB* self) +IB__hash__(IB* self) { PyObject* tuple; if (!self->__module__) { @@ -819,14 +812,14 @@ static char IB__doc__[] = ( static PyType_Slot IB_type_slots[] = { {Py_tp_doc, IB__doc__}, {Py_tp_dealloc, IB_dealloc}, - {Py_tp_hash, IB_hash}, + {Py_tp_hash, IB__hash__}, {Py_tp_call, IB__call__}, {Py_tp_traverse, IB_traverse}, {Py_tp_clear, IB_clear}, {Py_tp_richcompare, IB_richcompare}, {Py_tp_methods, IB_methods}, {Py_tp_members, IB_members}, - {Py_tp_init, IB_init}, + {Py_tp_init, IB__init__}, /* tp_base cannot be set as a stot -- pass to PyType_FromModuleAndSpec */ {0, NULL} }; @@ -836,8 +829,7 @@ static PyType_Spec IB_type_spec = { .basicsize=sizeof(IB), .flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - /* Only added in Python 3.11 */ - /* Py_TPFLAGS_MANAGED_WEAKREF | */ + Py_TPFLAGS_MANAGED_WEAKREF | Py_TPFLAGS_HAVE_GC, .slots=IB_type_slots }; @@ -852,10 +844,10 @@ typedef struct PyObject* _cache; PyObject* _mcache; PyObject* _scache; -} lookup; +} LB; static int -lookup_traverse(lookup* self, visitproc visit, void* arg) +LB_traverse(LB* self, visitproc visit, void* arg) { #if PY_VERSION_HEX > 0x03090000 Py_VISIT(Py_TYPE(self)); @@ -867,7 +859,7 @@ lookup_traverse(lookup* self, visitproc visit, void* arg) } static int -lookup_clear(lookup* self) +LB_clear(LB* self) { Py_CLEAR(self->_cache); Py_CLEAR(self->_mcache); @@ -876,11 +868,11 @@ lookup_clear(lookup* self) } static void -lookup_dealloc(lookup* self) +LB_dealloc(LB* self) { PyObject_GC_UnTrack((PyObject*)self); PyTypeObject* tp = Py_TYPE(self); - lookup_clear(self); + LB_clear(self); tp->tp_free((PyObject*)self); Py_DECREF(tp); } @@ -892,9 +884,9 @@ lookup_dealloc(lookup* self) self._scache.clear() */ static PyObject* -lookup_changed(lookup* self, PyObject* ignored) +LB_changed(LB* self, PyObject* ignored) { - lookup_clear(self); + LB_clear(self); Py_INCREF(Py_None); return Py_None; } @@ -935,7 +927,7 @@ _subcache(PyObject* cache, PyObject* key) } static PyObject* -_getcache(lookup* self, PyObject* provided, PyObject* name) +_getcache(LB* self, PyObject* provided, PyObject* name) { PyObject* cache; @@ -973,7 +965,7 @@ _getcache(lookup* self, PyObject* provided, PyObject* name) */ static PyObject* -_lookup(lookup* self, +_lookup(LB* self, PyObject* required, PyObject* provided, PyObject* name, @@ -1033,7 +1025,7 @@ _lookup(lookup* self, } static PyObject* -lookup_lookup(lookup* self, PyObject* args, PyObject* kwds) +LB_lookup(LB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "required", "provided", "name", "default", NULL }; PyObject *required, *provided, *name = NULL, *default_ = NULL; @@ -1064,7 +1056,7 @@ lookup_lookup(lookup* self, PyObject* args, PyObject* kwds) return result */ static PyObject* -_lookup1(lookup* self, +_lookup1(LB* self, PyObject* required, PyObject* provided, PyObject* name, @@ -1102,7 +1094,7 @@ _lookup1(lookup* self, return result; } static PyObject* -lookup_lookup1(lookup* self, PyObject* args, PyObject* kwds) +LB_lookup1(LB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "required", "provided", "name", "default", NULL }; PyObject *required, *provided, *name = NULL, *default_ = NULL; @@ -1138,7 +1130,7 @@ lookup_lookup1(lookup* self, PyObject* args, PyObject* kwds) return default */ static PyObject* -_adapter_hook(lookup* self, +_adapter_hook(LB* self, PyObject* provided, PyObject* object, PyObject* name, @@ -1193,7 +1185,7 @@ _adapter_hook(lookup* self, } static PyObject* -lookup_adapter_hook(lookup* self, PyObject* args, PyObject* kwds) +LB_adapter_hook(LB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "provided", "object", "name", "default", NULL }; PyObject *object, *provided, *name = NULL, *default_ = NULL; @@ -1212,7 +1204,7 @@ lookup_adapter_hook(lookup* self, PyObject* args, PyObject* kwds) } static PyObject* -lookup_queryAdapter(lookup* self, PyObject* args, PyObject* kwds) +LB_queryAdapter(LB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "object", "provided", "name", "default", NULL }; PyObject *object, *provided, *name = NULL, *default_ = NULL; @@ -1246,7 +1238,7 @@ lookup_queryAdapter(lookup* self, PyObject* args, PyObject* kwds) return result */ static PyObject* -_lookupAll(lookup* self, PyObject* required, PyObject* provided) +_lookupAll(LB* self, PyObject* required, PyObject* provided) { PyObject *cache, *result; @@ -1286,7 +1278,7 @@ _lookupAll(lookup* self, PyObject* required, PyObject* provided) } static PyObject* -lookup_lookupAll(lookup* self, PyObject* args, PyObject* kwds) +LB_lookupAll(LB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "required", "provided", NULL }; PyObject *required, *provided; @@ -1314,7 +1306,7 @@ lookup_lookupAll(lookup* self, PyObject* args, PyObject* kwds) return result */ static PyObject* -_subscriptions(lookup* self, PyObject* required, PyObject* provided) +_subscriptions(LB* self, PyObject* required, PyObject* provided) { PyObject *cache, *result; @@ -1354,7 +1346,7 @@ _subscriptions(lookup* self, PyObject* required, PyObject* provided) } static PyObject* -lookup_subscriptions(lookup* self, PyObject* args, PyObject* kwds) +LB_subscriptions(LB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "required", "provided", NULL }; PyObject *required, *provided; @@ -1366,86 +1358,86 @@ lookup_subscriptions(lookup* self, PyObject* args, PyObject* kwds) return _subscriptions(self, required, provided); } -static struct PyMethodDef lookup_methods[] = { - { "changed", (PyCFunction)lookup_changed, METH_O, "" }, - { "lookup", (PyCFunction)lookup_lookup, METH_KEYWORDS | METH_VARARGS, "" }, +static struct PyMethodDef LB_methods[] = { + { "changed", (PyCFunction)LB_changed, METH_O, "" }, + { "lookup", (PyCFunction)LB_lookup, METH_KEYWORDS | METH_VARARGS, "" }, { "lookup1", - (PyCFunction)lookup_lookup1, + (PyCFunction)LB_lookup1, METH_KEYWORDS | METH_VARARGS, "" }, { "queryAdapter", - (PyCFunction)lookup_queryAdapter, + (PyCFunction)LB_queryAdapter, METH_KEYWORDS | METH_VARARGS, "" }, { "adapter_hook", - (PyCFunction)lookup_adapter_hook, + (PyCFunction)LB_adapter_hook, METH_KEYWORDS | METH_VARARGS, "" }, { "lookupAll", - (PyCFunction)lookup_lookupAll, + (PyCFunction)LB_lookupAll, METH_KEYWORDS | METH_VARARGS, "" }, { "subscriptions", - (PyCFunction)lookup_subscriptions, + (PyCFunction)LB_subscriptions, METH_KEYWORDS | METH_VARARGS, "" }, { NULL, NULL } /* sentinel */ }; -static char LookupBase__doc__[] = "Base class for adapter registries"; +static char LB__doc__[] = "Base class for adapter registries"; /* * Heap type: LookupBase */ -static PyType_Slot lookup_type_slots[] = { - {Py_tp_doc, LookupBase__doc__}, - {Py_tp_dealloc, lookup_dealloc}, - {Py_tp_traverse, lookup_traverse}, - {Py_tp_clear, lookup_clear}, - {Py_tp_methods, lookup_methods}, +static PyType_Slot LB_type_slots[] = { + {Py_tp_doc, LB__doc__}, + {Py_tp_dealloc, LB_dealloc}, + {Py_tp_traverse, LB_traverse}, + {Py_tp_clear, LB_clear}, + {Py_tp_methods, LB_methods}, {0, NULL} }; -static PyType_Spec lookup_type_spec = { +static PyType_Spec LB_type_spec = { .name="_zope_interface_coptimizations.LookupBase", - .basicsize=sizeof(lookup), + .basicsize=sizeof(LB), .flags=Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_MANAGED_WEAKREF | Py_TPFLAGS_HAVE_GC, - .slots=lookup_type_slots + .slots=LB_type_slots }; typedef struct { - lookup lookup; - PyObject* _verify_ro; - PyObject* _verify_generations; -} verify; + LB lookup; + PyObject* _verify_ro; + PyObject* _verify_generations; +} VB; static int -verify_traverse(verify* self, visitproc visit, void* arg) +VB_traverse(VB* self, visitproc visit, void* arg) { Py_VISIT(self->_verify_ro); Py_VISIT(self->_verify_generations); - return lookup_traverse((lookup*)self, visit, arg); + return LB_traverse((LB*)self, visit, arg); } static int -verify_clear(verify* self) +VB_clear(VB* self) { Py_CLEAR(self->_verify_generations); Py_CLEAR(self->_verify_ro); - return lookup_clear((lookup*)self); + return LB_clear((LB*)self); } static void -verify_dealloc(verify* self) +VB_dealloc(VB* self) { PyObject_GC_UnTrack((PyObject*)self); PyTypeObject *tp = Py_TYPE(self); - verify_clear(self); + VB_clear(self); tp->tp_free((PyObject*)self); Py_DECREF(tp); } @@ -1479,11 +1471,11 @@ _generations_tuple(PyObject* ro) return generations; } static PyObject* -verify_changed(verify* self, PyObject* ignored) +verify_changed(VB* self, PyObject* ignored) { PyObject *t, *ro; - verify_clear(self); + VB_clear(self); t = PyObject_GetAttrString(OBJECT(self), "_registry"); if (t == NULL) @@ -1522,7 +1514,7 @@ verify_changed(verify* self, PyObject* ignored) self.changed(None) */ static int -_verify(verify* self) +_verify(VB* self) { PyObject* changed_result; @@ -1554,7 +1546,7 @@ _verify(verify* self) } static PyObject* -verify_lookup(verify* self, PyObject* args, PyObject* kwds) +VB_lookup(VB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "required", "provided", "name", "default", NULL }; PyObject *required, *provided, *name = NULL, *default_ = NULL; @@ -1566,11 +1558,11 @@ verify_lookup(verify* self, PyObject* args, PyObject* kwds) if (_verify(self) < 0) return NULL; - return _lookup((lookup*)self, required, provided, name, default_); + return _lookup((LB*)self, required, provided, name, default_); } static PyObject* -verify_lookup1(verify* self, PyObject* args, PyObject* kwds) +VB_lookup1(VB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "required", "provided", "name", "default", NULL }; PyObject *required, *provided, *name = NULL, *default_ = NULL; @@ -1582,11 +1574,11 @@ verify_lookup1(verify* self, PyObject* args, PyObject* kwds) if (_verify(self) < 0) return NULL; - return _lookup1((lookup*)self, required, provided, name, default_); + return _lookup1((LB*)self, required, provided, name, default_); } static PyObject* -verify_adapter_hook(verify* self, PyObject* args, PyObject* kwds) +VB_adapter_hook(VB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "provided", "object", "name", "default", NULL }; PyObject *object, *provided, *name = NULL, *default_ = NULL; @@ -1598,11 +1590,11 @@ verify_adapter_hook(verify* self, PyObject* args, PyObject* kwds) if (_verify(self) < 0) return NULL; - return _adapter_hook((lookup*)self, provided, object, name, default_); + return _adapter_hook((LB*)self, provided, object, name, default_); } static PyObject* -verify_queryAdapter(verify* self, PyObject* args, PyObject* kwds) +VB_queryAdapter(VB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "object", "provided", "name", "default", NULL }; PyObject *object, *provided, *name = NULL, *default_ = NULL; @@ -1614,11 +1606,11 @@ verify_queryAdapter(verify* self, PyObject* args, PyObject* kwds) if (_verify(self) < 0) return NULL; - return _adapter_hook((lookup*)self, provided, object, name, default_); + return _adapter_hook((LB*)self, provided, object, name, default_); } static PyObject* -verify_lookupAll(verify* self, PyObject* args, PyObject* kwds) +VB_lookupAll(VB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "required", "provided", NULL }; PyObject *required, *provided; @@ -1630,11 +1622,11 @@ verify_lookupAll(verify* self, PyObject* args, PyObject* kwds) if (_verify(self) < 0) return NULL; - return _lookupAll((lookup*)self, required, provided); + return _lookupAll((LB*)self, required, provided); } static PyObject* -verify_subscriptions(verify* self, PyObject* args, PyObject* kwds) +VB_subscriptions(VB* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = { "required", "provided", NULL }; PyObject *required, *provided; @@ -1646,63 +1638,63 @@ verify_subscriptions(verify* self, PyObject* args, PyObject* kwds) if (_verify(self) < 0) return NULL; - return _subscriptions((lookup*)self, required, provided); + return _subscriptions((LB*)self, required, provided); } -static struct PyMethodDef verify_methods[] = { +static struct PyMethodDef VB_methods[] = { { "changed", (PyCFunction)verify_changed, METH_O, "" }, { "lookup", - (PyCFunction)verify_lookup, + (PyCFunction)VB_lookup, METH_KEYWORDS | METH_VARARGS, "" }, { "lookup1", - (PyCFunction)verify_lookup1, + (PyCFunction)VB_lookup1, METH_KEYWORDS | METH_VARARGS, "" }, { "queryAdapter", - (PyCFunction)verify_queryAdapter, + (PyCFunction)VB_queryAdapter, METH_KEYWORDS | METH_VARARGS, "" }, { "adapter_hook", - (PyCFunction)verify_adapter_hook, + (PyCFunction)VB_adapter_hook, METH_KEYWORDS | METH_VARARGS, "" }, { "lookupAll", - (PyCFunction)verify_lookupAll, + (PyCFunction)VB_lookupAll, METH_KEYWORDS | METH_VARARGS, "" }, { "subscriptions", - (PyCFunction)verify_subscriptions, + (PyCFunction)VB_subscriptions, METH_KEYWORDS | METH_VARARGS, "" }, { NULL, NULL } /* sentinel */ }; -static char VerifyingBase__doc__[] = ( +static char VB__doc__[] = ( "Base class for verifying adapter registries." ); /* * Heap type: VerifyingBase */ -static PyType_Slot verify_type_slots[] = { - {Py_tp_doc, VerifyingBase__doc__}, - {Py_tp_dealloc, verify_dealloc}, - {Py_tp_traverse, verify_traverse}, - {Py_tp_clear, verify_clear}, - {Py_tp_methods, verify_methods}, +static PyType_Slot VB_type_slots[] = { + {Py_tp_doc, VB__doc__}, + {Py_tp_dealloc, VB_dealloc}, + {Py_tp_traverse, VB_traverse}, + {Py_tp_clear, VB_clear}, + {Py_tp_methods, VB_methods}, /* tp_base cannot be set as a stot -- pass to PyType_FromModuleAndSpec */ {0, NULL} }; -static PyType_Spec verify_type_spec = { +static PyType_Spec VB_type_spec = { .name="_zope_interface_coptimizations.VerifyingBase", - .basicsize=sizeof(verify), + .basicsize=sizeof(VB), .flags=Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_MANAGED_WEAKREF, - .slots=verify_type_slots + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_MANAGED_WEAKREF | + Py_TPFLAGS_HAVE_GC, + .slots=VB_type_slots }; @@ -2171,7 +2163,7 @@ _zic_module_exec(PyObject* module) /* Initialize types: */ - sb_class = PyType_FromModuleAndSpec(module, &Spec_type_spec, NULL); + sb_class = PyType_FromModuleAndSpec(module, &SB_type_spec, NULL); if (sb_class == NULL) { return -1; } rec->specification_base_class = TYPE(sb_class); @@ -2187,11 +2179,11 @@ _zic_module_exec(PyObject* module) if (ib_class == NULL) { return -1; } rec->interface_base_class = TYPE(ib_class); - lb_class = PyType_FromModuleAndSpec(module, &lookup_type_spec, NULL); + lb_class = PyType_FromModuleAndSpec(module, &LB_type_spec, NULL); if (lb_class == NULL) { return -1; } rec->lookup_base_class = TYPE(lb_class); - vb_class = PyType_FromModuleAndSpec(module, &verify_type_spec, lb_class); + vb_class = PyType_FromModuleAndSpec(module, &VB_type_spec, lb_class); if (vb_class == NULL) { return -1; } rec->verifying_base_class = TYPE(vb_class); From 5de904c2f43929838767c67bb2cac768bd8be944 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 16:09:41 -0400 Subject: [PATCH 27/39] refactor: macros for type flags Make them conditional, along with the manual weakreflist managerment, on Python < 3.12, which added the 'Py_TPFLAGS_MANAGED_WEAKREF' flag. Builds and tests pass on 3.11 with this change. --- .../_zope_interface_coptimizations.c | 60 ++++++++++++------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index b1481cc2..6695b3dc 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -37,6 +37,26 @@ return NULL; \ } +#if PY_VERSION_HEX >= 0x030c0000 +#define LEAFTYPE_FLAGS \ + Py_TPFLAGS_DEFAULT | \ + Py_TPFLAGS_MANAGED_WEAKREF | \ + Py_TPFLAGS_HAVE_GC +#define BASETYPE_FLAGS \ + Py_TPFLAGS_DEFAULT | \ + Py_TPFLAGS_BASETYPE | \ + Py_TPFLAGS_MANAGED_WEAKREF | \ + Py_TPFLAGS_HAVE_GC +#else +#define LEAFTYPE_FLAGS \ + Py_TPFLAGS_DEFAULT | \ + Py_TPFLAGS_HAVE_GC +#define BASETYPE_FLAGS \ + Py_TPFLAGS_DEFAULT | \ + Py_TPFLAGS_BASETYPE | \ + Py_TPFLAGS_HAVE_GC +#endif + /* Static strings, used to invoke PyObject_CallMethodObjArgs */ static PyObject *str_call_conform; static PyObject *str_uncached_lookup; @@ -79,6 +99,9 @@ typedef struct make any assumptions about contents. */ PyObject* _implied; +#if PY_VERSION_HEX < 0x030c0000 + PyObject* weakreflist; +#endif /* The remainder aren't used in C code but must be stored here to prevent instance layout conflicts. @@ -127,6 +150,11 @@ SB_dealloc(SB* self) { PyObject_GC_UnTrack((PyObject*)self); PyTypeObject* tp = Py_TYPE(self); +#if PY_VERSION_HEX < 0x030c0000 + if (self->weakreflist != NULL) { + PyObject_ClearWeakRefs(OBJECT(self)); + } +#endif SB_clear(self); tp->tp_free(OBJECT(self)); Py_DECREF(tp); @@ -242,6 +270,9 @@ static PyMemberDef SB_members[] = { { "_v_attrs", T_OBJECT_EX, offsetof(SB, _v_attrs), 0, "" }, { "__iro__", T_OBJECT_EX, offsetof(SB, __iro__), 0, "" }, { "__sro__", T_OBJECT_EX, offsetof(SB, __sro__), 0, "" }, +#if PY_VERSION_HEX < 0x030c0000 + { "__weaklistoffset__", T_OBJECT_EX, offsetof(SB, weakreflist), 0, "" }, +#endif { NULL }, }; @@ -264,10 +295,7 @@ static PyType_Slot SB_type_slots[] = { static PyType_Spec SB_type_spec = { .name="zope.interface.interface.SpecificationBase", .basicsize=sizeof(SB), - .flags=Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_MANAGED_WEAKREF | - Py_TPFLAGS_HAVE_GC, + .flags=BASETYPE_FLAGS, .slots=SB_type_slots }; @@ -332,9 +360,7 @@ static PyType_Slot OSD_type_slots[] = { static PyType_Spec OSD_type_spec = { .name="_interface_coptimizations.ObjectSpecificationDescriptor", .basicsize=0, - .flags=Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_MANAGED_WEAKREF | - Py_TPFLAGS_HAVE_GC, + .flags=LEAFTYPE_FLAGS, .slots=OSD_type_slots }; @@ -426,10 +452,7 @@ static PyType_Slot CPB_type_slots[] = { static PyType_Spec CPB_type_spec = { .name="zope.interface.interface.ClassProvidesBase", .basicsize=sizeof(CPB), - .flags=Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_MANAGED_WEAKREF | - Py_TPFLAGS_HAVE_GC, + .flags=BASETYPE_FLAGS, .slots=CPB_type_slots }; @@ -827,10 +850,7 @@ static PyType_Slot IB_type_slots[] = { static PyType_Spec IB_type_spec = { .name="zope.interface.interface.InterfaceBase", .basicsize=sizeof(IB), - .flags=Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_MANAGED_WEAKREF | - Py_TPFLAGS_HAVE_GC, + .flags=BASETYPE_FLAGS, .slots=IB_type_slots }; @@ -1402,10 +1422,7 @@ static PyType_Slot LB_type_slots[] = { static PyType_Spec LB_type_spec = { .name="_zope_interface_coptimizations.LookupBase", .basicsize=sizeof(LB), - .flags=Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_MANAGED_WEAKREF | - Py_TPFLAGS_HAVE_GC, + .flags=BASETYPE_FLAGS, .slots=LB_type_slots }; @@ -1690,10 +1707,7 @@ static PyType_Slot VB_type_slots[] = { static PyType_Spec VB_type_spec = { .name="_zope_interface_coptimizations.VerifyingBase", .basicsize=sizeof(VB), - .flags=Py_TPFLAGS_DEFAULT | - Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_MANAGED_WEAKREF | - Py_TPFLAGS_HAVE_GC, + .flags=BASETYPE_FLAGS, .slots=VB_type_slots }; From c642bb0a947fc1d9499dcde325cd175904e46247 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 23 May 2024 17:55:20 -0400 Subject: [PATCH 28/39] refactor: use better name for the C base classes --- src/zope/interface/_zope_interface_coptimizations.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 6695b3dc..adcf1c0a 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -293,7 +293,7 @@ static PyType_Slot SB_type_slots[] = { }; static PyType_Spec SB_type_spec = { - .name="zope.interface.interface.SpecificationBase", + .name="_zope_interface_coptimizations.SpecificationBase", .basicsize=sizeof(SB), .flags=BASETYPE_FLAGS, .slots=SB_type_slots @@ -358,7 +358,8 @@ static PyType_Slot OSD_type_slots[] = { }; static PyType_Spec OSD_type_spec = { - .name="_interface_coptimizations.ObjectSpecificationDescriptor", + .name=( + "_zope_interface_coptimizations.ObjectSpecificationDescriptor"), .basicsize=0, .flags=LEAFTYPE_FLAGS, .slots=OSD_type_slots @@ -450,7 +451,7 @@ static PyType_Slot CPB_type_slots[] = { }; static PyType_Spec CPB_type_spec = { - .name="zope.interface.interface.ClassProvidesBase", + .name="_zope_interface_coptimizations.ClassProvidesBase", .basicsize=sizeof(CPB), .flags=BASETYPE_FLAGS, .slots=CPB_type_slots @@ -848,7 +849,7 @@ static PyType_Slot IB_type_slots[] = { }; static PyType_Spec IB_type_spec = { - .name="zope.interface.interface.InterfaceBase", + .name="_zope_interface_coptimizations.InterfaceBase", .basicsize=sizeof(IB), .flags=BASETYPE_FLAGS, .slots=IB_type_slots From 8d9086c2daad659d4a9f5d08752cdaf2226607f3 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Sat, 25 May 2024 18:47:43 -0400 Subject: [PATCH 29/39] refactor: restore use of static types for Python < 3.11 --- .../_zope_interface_coptimizations.c | 464 +++++++++++++++--- 1 file changed, 393 insertions(+), 71 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index adcf1c0a..3331bafe 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -37,6 +37,18 @@ return NULL; \ } +/* + * Don't use heap-allocated types for Python < 3.11: the API needed + * to find the dynamic module, 'PyType_GetModuleByDef', was added then. + */ +#if PY_VERSION_HEX < 0x030b0000 +#define USE_STATIC_TYPES 1 +#define USE_HEAP_TYPES 0 +#else +#define USE_STATIC_TYPES 0 +#define USE_HEAP_TYPES 1 +#endif + #if PY_VERSION_HEX >= 0x030c0000 #define LEAFTYPE_FLAGS \ Py_TPFLAGS_DEFAULT | \ @@ -85,6 +97,63 @@ static PyObject* _get_adapter_hooks(PyTypeObject *typeobj); static PyTypeObject* _get_specification_base_class(PyTypeObject *typeobj); static PyTypeObject* _get_interface_base_class(PyTypeObject *typeobj); +#if USE_STATIC_TYPES +/* + * Global used by static IB__adapt + */ +static PyObject* adapter_hooks = NULL; + +/* + * Globals imported from 'zope.interface.declarations' + */ +static int imported_declarations = 0; +static PyObject* BuiltinImplementationSpecifications; +static PyObject* empty; +static PyObject* fallback; +static PyTypeObject *Implements; + +/* Import zope.interface.declarations and store results in global statics. + * + * Static alternative to '_zic_state_load_declarations' below. + */ +static int +import_declarations(void) +{ + PyObject *declarations, *i; + + declarations = PyImport_ImportModule("zope.interface.declarations"); + if (declarations == NULL) { return -1; } + + BuiltinImplementationSpecifications = PyObject_GetAttrString( + declarations, "BuiltinImplementationSpecifications"); + if (BuiltinImplementationSpecifications == NULL) { return -1; } + + empty = PyObject_GetAttrString(declarations, "_empty"); + if (empty == NULL) { return -1; } + + fallback = PyObject_GetAttrString(declarations, "implementedByFallback"); + if (fallback == NULL) { return -1;} + + i = PyObject_GetAttrString(declarations, "Implements"); + if (i == NULL) { return -1; } + + if (! PyType_Check(i)) { + PyErr_SetString( + PyExc_TypeError, + "zope.interface.declarations.Implements is not a type"); + return -1; + } + + Implements = (PyTypeObject *)i; + + Py_DECREF(declarations); + + imported_declarations = 1; + return 0; +} + +#endif + /* * SpecificationBase class */ @@ -157,7 +226,9 @@ SB_dealloc(SB* self) #endif SB_clear(self); tp->tp_free(OBJECT(self)); +#if USE_HEAP_TYPES Py_DECREF(tp); +#endif } static char SB_extends__doc__[] = @@ -276,38 +347,63 @@ static PyMemberDef SB_members[] = { { NULL }, }; +static char SB__name__[] = "_zope_interface_coptimizations.SpecificationBase"; static char SB__doc__[] = "Base type for Specification objects"; +#if USE_STATIC_TYPES + +/* + * Static type: SpecificationBase + */ + +static PyTypeObject SB_type_def = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = SB__name__, + .tp_doc = SB__doc__, + .tp_basicsize = sizeof(SB), + .tp_flags = BASETYPE_FLAGS, + .tp_call = (ternaryfunc)SB__call__, + .tp_traverse = (traverseproc)SB_traverse, + .tp_clear = (inquiry)SB_clear, + .tp_dealloc = (destructor)SB_dealloc, + .tp_weaklistoffset = offsetof(SB, weakreflist), /* XXX */ + .tp_methods = SB_methods, + .tp_members = SB_members, +}; + +#else + /* * Heap-based type: SpecificationBase */ static PyType_Slot SB_type_slots[] = { {Py_tp_doc, SB__doc__}, - {Py_tp_dealloc, SB_dealloc}, {Py_tp_call, SB__call__}, {Py_tp_traverse, SB_traverse}, {Py_tp_clear, SB_clear}, + {Py_tp_dealloc, SB_dealloc}, {Py_tp_methods, SB_methods}, {Py_tp_members, SB_members}, {0, NULL} }; static PyType_Spec SB_type_spec = { - .name="_zope_interface_coptimizations.SpecificationBase", - .basicsize=sizeof(SB), - .flags=BASETYPE_FLAGS, - .slots=SB_type_slots + .name = SB__name__, + .basicsize = sizeof(SB), + .flags = BASETYPE_FLAGS, + .slots = SB_type_slots }; +#endif + /* * ObjectSpecificationDescriptor class */ +#if USE_HEAP_TYPES static int OSD_traverse(PyObject* self, visitproc visit, void* arg) { -#if PY_VERSION_HEX > 0x03090000 Py_VISIT(Py_TYPE(self)); -#endif return 0; } @@ -319,6 +415,7 @@ OSD_dealloc(PyObject* self) tp->tp_free(OBJECT(self)); Py_DECREF(tp); } +#endif static PyObject* OSD_descr_get(PyObject* self, PyObject* inst, PyObject* cls) @@ -344,27 +441,50 @@ OSD_descr_get(PyObject* self, PyObject* inst, PyObject* cls) return implementedBy(module, cls); } +static char OSD__name__[] = ( + "_zope_interface_coptimizations.ObjectSpecificationDescriptor"); static char OSD__doc__[] = "Object Specification Descriptor"; +#if USE_STATIC_TYPES + +/* + * Static type: ObjectSpecificationDescriptor + */ + +static PyTypeObject OSD_type_def = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = OSD__name__, + .tp_doc = OSD__doc__, + /* No GC for the static version */ + .tp_flags = Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE, + .tp_descr_get = (descrgetfunc)OSD_descr_get, + /*.tp_traverse, = OSD_traverse}, not reqd for static */ + /*.tp_dealloc, = OSD_dealloc}, not reqd for static */ +}; + +#else + /* * Heap type: ObjectSpecificationDescriptor */ static PyType_Slot OSD_type_slots[] = { - {Py_tp_doc, OSD__doc__}, - {Py_tp_descr_get, OSD_descr_get}, - {Py_tp_traverse, OSD_traverse}, - {Py_tp_dealloc, OSD_dealloc}, - {0, NULL} + {Py_tp_doc, OSD__doc__}, + {Py_tp_descr_get, OSD_descr_get}, + {Py_tp_traverse, OSD_traverse}, + {Py_tp_dealloc, OSD_dealloc}, + {0, NULL} }; static PyType_Spec OSD_type_spec = { - .name=( - "_zope_interface_coptimizations.ObjectSpecificationDescriptor"), - .basicsize=0, - .flags=LEAFTYPE_FLAGS, - .slots=OSD_type_slots + .name = OSD__name__, + .basicsize = 0, + .flags = LEAFTYPE_FLAGS, + .slots = OSD_type_slots }; +#endif + /* * ClassProviderBase class */ @@ -434,29 +554,53 @@ static PyMemberDef CPB_members[] = { { NULL } }; +static char CPB__name__[] = "_zope_interface_coptimizations.ClassProvidesBase"; static char CPB__doc__[] = "C Base class for ClassProvides"; +#if USE_STATIC_TYPES + +/* + * Static type: ClassProvidesBase + */ + +static PyTypeObject CPB_type_def = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = CPB__name__, + .tp_doc = CPB__doc__, + .tp_base = &SB_type_def, + .tp_basicsize = sizeof(CPB), + .tp_flags = BASETYPE_FLAGS, + .tp_descr_get = (descrgetfunc)CPB_descr_get, + .tp_traverse = (traverseproc)CPB_traverse, + .tp_clear = (inquiry)CPB_clear, + .tp_dealloc = (destructor)CPB_dealloc, + .tp_members = CPB_members, +}; + +#else + /* * Heap type: ClassProvidesBase */ static PyType_Slot CPB_type_slots[] = { {Py_tp_doc, CPB__doc__}, - {Py_tp_dealloc, CPB_dealloc}, + {Py_tp_descr_get, CPB_descr_get}, {Py_tp_traverse, CPB_traverse}, {Py_tp_clear, CPB_clear}, + {Py_tp_dealloc, CPB_dealloc}, {Py_tp_members, CPB_members}, - {Py_tp_descr_get, CPB_descr_get}, /* tp_base cannot be set as a stot -- pass to PyType_FromModuleAndSpec */ {0, NULL} }; static PyType_Spec CPB_type_spec = { - .name="_zope_interface_coptimizations.ClassProvidesBase", - .basicsize=sizeof(CPB), - .flags=BASETYPE_FLAGS, - .slots=CPB_type_slots + .name = CPB__name__, + .basicsize = sizeof(CPB), + .flags = BASETYPE_FLAGS, + .slots = CPB_type_slots }; +#endif /* * InterfaceBase class @@ -826,35 +970,63 @@ static struct PyMethodDef IB_methods[] = { { NULL, NULL } /* sentinel */ }; +static char IB__name__[] ="_zope_interface_coptimizations.InterfaceBase"; static char IB__doc__[] = ( "Interface base type providing __call__ and __adapt__" ); +#if USE_STATIC_TYPES + +/* + * Static type: InterfaceBase + */ + +static PyTypeObject IB_type_def = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = IB__name__, + .tp_doc = IB__doc__, + .tp_base = &SB_type_def, + .tp_basicsize = sizeof(IB), + .tp_flags = BASETYPE_FLAGS, + .tp_init = (initproc)IB__init__, + .tp_hash = (hashfunc)IB__hash__, + .tp_richcompare = (richcmpfunc)IB_richcompare, + .tp_call = (ternaryfunc)IB__call__, + .tp_traverse = (traverseproc)IB_traverse, + .tp_clear = (inquiry)IB_clear, + .tp_dealloc = (destructor)IB_dealloc, + .tp_methods = IB_methods, + .tp_members = IB_members, +}; + +#else + /* * Heap type: InterfaceBase */ static PyType_Slot IB_type_slots[] = { {Py_tp_doc, IB__doc__}, - {Py_tp_dealloc, IB_dealloc}, + {Py_tp_init, IB__init__}, {Py_tp_hash, IB__hash__}, + {Py_tp_richcompare, IB_richcompare}, {Py_tp_call, IB__call__}, {Py_tp_traverse, IB_traverse}, {Py_tp_clear, IB_clear}, - {Py_tp_richcompare, IB_richcompare}, + {Py_tp_dealloc, IB_dealloc}, {Py_tp_methods, IB_methods}, {Py_tp_members, IB_members}, - {Py_tp_init, IB__init__}, /* tp_base cannot be set as a stot -- pass to PyType_FromModuleAndSpec */ {0, NULL} }; static PyType_Spec IB_type_spec = { - .name="_zope_interface_coptimizations.InterfaceBase", - .basicsize=sizeof(IB), - .flags=BASETYPE_FLAGS, - .slots=IB_type_slots + .name = IB__name__, + .basicsize = sizeof(IB), + .flags = BASETYPE_FLAGS, + .slots = IB_type_slots }; +#endif /* * LookupBase class @@ -895,7 +1067,9 @@ LB_dealloc(LB* self) PyTypeObject* tp = Py_TYPE(self); LB_clear(self); tp->tp_free((PyObject*)self); +#if USE_HEAP_TYPES Py_DECREF(tp); +#endif } /* @@ -1405,28 +1579,51 @@ static struct PyMethodDef LB_methods[] = { { NULL, NULL } /* sentinel */ }; +static char LB__name__[] = "_zope_interface_coptimizations.LookupBase"; static char LB__doc__[] = "Base class for adapter registries"; +#if USE_STATIC_TYPES + +/* + * Static type: LookupBase + */ + +static PyTypeObject LB_type_def = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = LB__name__, + .tp_doc = LB__doc__, + .tp_basicsize = sizeof(LB), + .tp_flags = BASETYPE_FLAGS, + .tp_traverse = (traverseproc)LB_traverse, + .tp_clear = (inquiry)LB_clear, + .tp_dealloc = (destructor)&LB_dealloc, + .tp_methods = LB_methods, +}; + +#else + /* * Heap type: LookupBase */ static PyType_Slot LB_type_slots[] = { {Py_tp_doc, LB__doc__}, - {Py_tp_dealloc, LB_dealloc}, {Py_tp_traverse, LB_traverse}, {Py_tp_clear, LB_clear}, + {Py_tp_dealloc, LB_dealloc}, {Py_tp_methods, LB_methods}, {0, NULL} }; static PyType_Spec LB_type_spec = { - .name="_zope_interface_coptimizations.LookupBase", - .basicsize=sizeof(LB), - .flags=BASETYPE_FLAGS, - .slots=LB_type_slots + .name = LB__name__, + .basicsize = sizeof(LB), + .flags = BASETYPE_FLAGS, + .slots = LB_type_slots }; +#endif + typedef struct { LB lookup; @@ -1457,7 +1654,9 @@ VB_dealloc(VB* self) PyTypeObject *tp = Py_TYPE(self); VB_clear(self); tp->tp_free((PyObject*)self); +#if USE_HEAP_TYPES Py_DECREF(tp); +#endif } /* @@ -1688,30 +1887,53 @@ static struct PyMethodDef VB_methods[] = { { NULL, NULL } /* sentinel */ }; -static char VB__doc__[] = ( -"Base class for verifying adapter registries." -); +static char VB__name__[] = "_zope_interface_coptimizations.VerifyingBase"; +static char VB__doc__[] = "Base class for verifying adapter registries."; + +#if USE_STATIC_TYPES + +/* + * Static type: VerifyingBase + */ + +static PyTypeObject VB_type_def = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = VB__name__, + .tp_doc = VB__doc__, + .tp_base = &LB_type_def, + .tp_basicsize = sizeof(VB), + .tp_flags = BASETYPE_FLAGS, + .tp_traverse = (traverseproc)VB_traverse, + .tp_clear = (inquiry)VB_clear, + .tp_dealloc = (destructor)&VB_dealloc, + .tp_methods = VB_methods, +}; + + +#else /* * Heap type: VerifyingBase */ static PyType_Slot VB_type_slots[] = { {Py_tp_doc, VB__doc__}, - {Py_tp_dealloc, VB_dealloc}, {Py_tp_traverse, VB_traverse}, {Py_tp_clear, VB_clear}, + {Py_tp_dealloc, VB_dealloc}, {Py_tp_methods, VB_methods}, /* tp_base cannot be set as a stot -- pass to PyType_FromModuleAndSpec */ {0, NULL} }; static PyType_Spec VB_type_spec = { - .name="_zope_interface_coptimizations.VerifyingBase", - .basicsize=sizeof(VB), - .flags=BASETYPE_FLAGS, - .slots=VB_type_slots + .name = VB__name__, + .basicsize = sizeof(VB), + .flags = BASETYPE_FLAGS, + .slots = VB_type_slots }; +#endif + /* * Module state struct: holds all data formerly kept as static globals. @@ -1807,6 +2029,11 @@ _zic_state_clear(PyObject* module) return 0; } +#if USE_HEAP_TYPES +/* Import zope.interface.declarations and store results in module state. + * + * Dynamic alternative to 'import_declarations' above. + */ static _zic_module_state* _zic_state_load_declarations(PyObject* module) { @@ -1864,26 +2091,28 @@ _zic_state_load_declarations(PyObject* module) return rec; } +#endif + /* * Provide access to the current module given the type. - * - * At the moment, this just returns the static, but we can adjust this - * to do the lookup using 'PyType_GetModuleByDef' (for slot methods) - * or via the '*defining_class' arg passed to the yet-to-be-refactored - * normal methods declared using 'PyCMethod' calling convention. */ -static struct PyModuleDef _zic_module; +static struct PyModuleDef _zic_module_def; static PyObject* _get_module(PyTypeObject *typeobj) { +#if USE_STATIC_TYPES + return (PyObject*)&_zic_module_def; +#else if (PyType_Check(typeobj)) { /* Only added in Python 3.11 */ - return PyType_GetModuleByDef(typeobj, &_zic_module); + return PyType_GetModuleByDef(typeobj, &_zic_module_def); } + PyErr_SetString(PyExc_TypeError, "_get_module: called w/ non-type"); return NULL; +#endif } /* @@ -1892,6 +2121,9 @@ _get_module(PyTypeObject *typeobj) static PyObject* _get_adapter_hooks(PyTypeObject *typeobj) { +#if USE_STATIC_TYPES + return adapter_hooks; +#else PyObject* module; _zic_module_state* rec; @@ -1900,6 +2132,7 @@ _get_adapter_hooks(PyTypeObject *typeobj) rec = _zic_state(module); return rec->adapter_hooks; +#endif } /* @@ -1908,6 +2141,9 @@ _get_adapter_hooks(PyTypeObject *typeobj) static PyTypeObject* _get_specification_base_class(PyTypeObject *typeobj) { +#if USE_STATIC_TYPES + return &SB_type_def; +#else PyObject* module; _zic_module_state* rec; @@ -1916,6 +2152,7 @@ _get_specification_base_class(PyTypeObject *typeobj) rec = _zic_state(module); return rec->specification_base_class; +#endif } /* @@ -1924,6 +2161,9 @@ _get_specification_base_class(PyTypeObject *typeobj) static PyTypeObject* _get_interface_base_class(PyTypeObject *typeobj) { +#if USE_STATIC_TYPES + return &IB_type_def; +#else PyObject* module; _zic_module_state* rec; @@ -1932,15 +2172,27 @@ _get_interface_base_class(PyTypeObject *typeobj) rec = _zic_state(module); return rec->interface_base_class; +#endif } static PyObject* implementedByFallback(PyObject* module, PyObject* cls) { +#if USE_STATIC_TYPES + if (imported_declarations == 0 && import_declarations() < 0) { + return NULL; + } + /* now use static 'fallback' */ +#else + PyObject* fallback; + _zic_module_state* rec = _zic_state_load_declarations(module); if (rec == NULL) { return NULL; } - return PyObject_CallFunctionObjArgs(rec->fallback, cls, NULL); + fallback = rec->fallback; +#endif + + return PyObject_CallFunctionObjArgs(fallback, cls, NULL); } static char implementedBy___doc__[] = @@ -1955,10 +2207,24 @@ implementedBy(PyObject* module, PyObject* cls) */ PyObject *dict = NULL; PyObject *spec; + PyTypeObject *implements_class; + PyObject *builtin_impl_specs; + +#if USE_STATIC_TYPES + if (imported_declarations == 0 && import_declarations() < 0) { + return NULL; + } + implements_class = Implements; + builtin_impl_specs = BuiltinImplementationSpecifications; +#else _zic_module_state* rec = _zic_state_load_declarations(module); if (rec == NULL) { return NULL; } + implements_class = rec->implements_class; + builtin_impl_specs = rec->builtin_impl_specs; +#endif + if (PyObject_TypeCheck(cls, &PySuper_Type)) { // Let merging be handled by Python. return implementedByFallback(module, cls); @@ -1983,7 +2249,7 @@ implementedBy(PyObject* module, PyObject* cls) Py_DECREF(dict); if (spec) { - if (PyObject_TypeCheck(spec, rec->implements_class)) + if (PyObject_TypeCheck(spec, implements_class)) return spec; /* Old-style declaration, use more expensive fallback code */ @@ -1994,7 +2260,7 @@ implementedBy(PyObject* module, PyObject* cls) PyErr_Clear(); /* Maybe we have a builtin */ - spec = PyDict_GetItem(rec->builtin_impl_specs, cls); + spec = PyDict_GetItem(builtin_impl_specs, cls); if (spec != NULL) { Py_INCREF(spec); return spec; @@ -2012,10 +2278,25 @@ getObjectSpecification(PyObject* module, PyObject* ob) { PyObject *cls; PyObject *result; + PyTypeObject *specification_base_class; + PyObject *empty_; + +#if USE_STATIC_TYPES + specification_base_class = &SB_type_def; + + if (imported_declarations == 0 && import_declarations() < 0) { + return NULL; + } + empty_ = empty; /* global from import */ +#else _zic_module_state* rec = _zic_state_load_declarations(module); if (rec == NULL) { return NULL; } + specification_base_class = rec->specification_base_class; + empty_ = rec->empty; +#endif + result = PyObject_GetAttrString(ob, "__provides__"); if (!result) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { @@ -2026,7 +2307,7 @@ getObjectSpecification(PyObject* module, PyObject* ob) } else { int is_instance = -1; is_instance = - PyObject_IsInstance(result, OBJECT(rec->specification_base_class)); + PyObject_IsInstance(result, OBJECT(specification_base_class)); if (is_instance < 0) { /* Propagate all errors */ return NULL; @@ -2045,8 +2326,8 @@ getObjectSpecification(PyObject* module, PyObject* ob) } PyErr_Clear(); - Py_INCREF(rec->empty); - return rec->empty; + Py_INCREF(empty_); + return empty_; } result = implementedBy(module, cls); Py_DECREF(cls); @@ -2062,7 +2343,7 @@ providedBy(PyObject* module, PyObject* ob) PyObject *result = NULL; PyObject *cls; PyObject *cp; - _zic_module_state *rec; + PyTypeObject *specification_base_class; int is_instance = -1; is_instance = PyObject_IsInstance(ob, (PyObject*)&PySuper_Type); @@ -2092,8 +2373,13 @@ providedBy(PyObject* module, PyObject* ob) because we may have a proxy, so we'll just try to get the only attribute. */ - rec = _zic_state(module); - if (PyObject_TypeCheck(result, rec->specification_base_class) || +#if USE_STATIC_TYPES + specification_base_class = &SB_type_def; +#else + _zic_module_state* rec = _zic_state(module); + specification_base_class = rec->specification_base_class; +#endif + if (PyObject_TypeCheck(result, specification_base_class) || PyObject_HasAttrString(result, "extends")) return result; @@ -2164,17 +2450,56 @@ static struct PyMethodDef _zic_module_methods[] = { static int _zic_module_exec(PyObject* module) { + _zic_module_state* rec = _zic_state_init(module); + + rec->adapter_hooks = PyList_New(0); + if (rec->adapter_hooks == NULL) + return -1; + +#if USE_STATIC_TYPES + + /* Initialize static global */ + adapter_hooks = rec->adapter_hooks; + + /* Initialize types: */ + SB_type_def.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&SB_type_def) < 0) { return -1; } + Py_INCREF(&SB_type_def); + rec->specification_base_class = &SB_type_def; + + OSD_type_def.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&OSD_type_def) < 0) { return -1; } + Py_INCREF(&OSD_type_def); + rec->object_specification_descriptor_class = &OSD_type_def; + + CPB_type_def.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&CPB_type_def) < 0) { return -1; } + Py_INCREF(&CPB_type_def); + rec->class_provides_base_class = &CPB_type_def; + + IB_type_def.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&IB_type_def) < 0) { return -1; } + Py_INCREF(&IB_type_def); + rec->interface_base_class = &IB_type_def; + + LB_type_def.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&LB_type_def) < 0) { return -1; } + Py_INCREF(&LB_type_def); + rec->lookup_base_class = &LB_type_def; + + VB_type_def.tp_new = PyBaseObject_Type.tp_new; + if (PyType_Ready(&VB_type_def) < 0) { return -1; } + Py_INCREF(&VB_type_def); + rec->verifying_base_class = &VB_type_def; + +#else + PyObject *sb_class; PyObject *osd_class; PyObject *cpb_class; PyObject *ib_class; PyObject *lb_class; PyObject *vb_class; - _zic_module_state* rec = _zic_state_init(module); - - rec->adapter_hooks = PyList_New(0); - if (rec->adapter_hooks == NULL) - return -1; /* Initialize types: */ @@ -2202,6 +2527,8 @@ _zic_module_exec(PyObject* module) if (vb_class == NULL) { return -1; } rec->verifying_base_class = TYPE(vb_class); +#endif + /* Add types to our dict FBO python; also the adapter hooks */ if (PyModule_AddObject(module, "SpecificationBase", OBJECT(rec->specification_base_class)) < 0) @@ -2248,7 +2575,7 @@ static PyModuleDef_Slot _zic_module_slots[] = { static char _zic_module__doc__[] = "C optimizations for zope.interface\n\n"; -static struct PyModuleDef _zic_module = { +static struct PyModuleDef _zic_module_def = { PyModuleDef_HEAD_INIT, .m_name = "_zope_interface_coptimizations", .m_doc = _zic_module__doc__, @@ -2275,12 +2602,7 @@ init(void) DEFINE_STRING(__adapt__); #undef DEFINE_STRING - /* - * To be replaced by a call to PyModuleDef_Init(&_zic_module); - * the function will just return the initilized module def structure, - * allowing the interpreter to create a new module instance - */ - return PyModuleDef_Init(&_zic_module); + return PyModuleDef_Init(&_zic_module_def); } PyMODINIT_FUNC From 2bb0ee64f4df2e198dd834283a7d128423feb80b Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Mon, 27 May 2024 14:57:04 -0400 Subject: [PATCH 30/39] tests: doctests pass under 'pypy3' --- docs/verify.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/verify.rst b/docs/verify.rst index bc1be1c6..b93f9912 100644 --- a/docs/verify.rst +++ b/docs/verify.rst @@ -49,7 +49,7 @@ defined. .. doctest:: >>> verify_foo() - The object has failed to implement interface ...IFoo: + The object <...Foo...> has failed to implement interface ...IFoo: Does not declaratively implement the interface The base.IBase.x attribute was not provided The module.IFoo.y attribute was not provided @@ -61,7 +61,7 @@ declaring the correct interface. >>> Foo.x = Foo.y = 42 >>> verify_foo() - The object has failed to implement interface ...IFoo: Does not declaratively implement the interface. + The object <...Foo...> has failed to implement interface ...IFoo: Does not declaratively implement the interface. If we want to only check the structure of the object, without examining its declarations, we can use the ``tentative`` argument. @@ -125,13 +125,13 @@ exception. ... class Foo(object): ... x = 1 >>> verify_foo() - The object has failed to implement interface ...IFoo: The module.IFoo.y attribute was not provided. + The object <...Foo...> has failed to implement interface ...IFoo: The module.IFoo.y attribute was not provided. >>> @implementer(IFoo) ... class Foo(object): ... def __init__(self): ... self.y = 2 >>> verify_foo() - The object has failed to implement interface ...IFoo: The base.IBase.x attribute was not provided. + The object <...Foo...> has failed to implement interface ...IFoo: The base.IBase.x attribute was not provided. If both attributes are missing, an exception is raised reporting both errors. @@ -142,7 +142,7 @@ both errors. ... class Foo(object): ... pass >>> verify_foo() - The object has failed to implement interface ...IFoo: + The object <...Foo ...> has failed to implement interface ...IFoo: The base.IBase.x attribute was not provided The module.IFoo.y attribute was not provided @@ -161,7 +161,7 @@ when trying to get its value, the attribute is considered missing: ... def x(self): ... raise AttributeError >>> verify_foo() - The object has failed to implement interface ...IFoo: The module.IFoo.x attribute was not provided. + The object <...Foo...> has failed to implement interface ...IFoo: The module.IFoo.x attribute was not provided. Any other exception raised by a property will propagate to the caller of @@ -209,7 +209,7 @@ that takes one argument. If we don't provide it, we get an error. ... class Foo(object): ... pass >>> verify_foo() - The object has failed to implement interface ...IFoo: The module.IFoo.simple(arg1) attribute was not provided. + The object <...Foo...> has failed to implement interface ...IFoo: The module.IFoo.simple(arg1) attribute was not provided. Once they exist, they are checked to be callable, and for compatible signatures. @@ -219,7 +219,7 @@ Not being callable is an error. >>> Foo.simple = 42 >>> verify_foo() - The object has failed to implement interface ...IFoo: The contract of module.IFoo.simple(arg1) is violated because '42' is not a method. + The object <...Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.simple(arg1) is violated because '42' is not a method. Taking too few arguments is an error. (Recall that the ``self`` argument is implicit.) @@ -228,7 +228,7 @@ argument is implicit.) >>> Foo.simple = lambda self: "I take no arguments" >>> verify_foo() - The object has failed to implement interface ...IFoo: The contract of module.IFoo.simple(arg1) is violated because '()' doesn't allow enough arguments. + The object <...Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.simple(arg1) is violated because '()' doesn't allow enough arguments. Requiring too many arguments is an error. @@ -236,7 +236,7 @@ Requiring too many arguments is an error. >>> Foo.simple = lambda self, a, b: "I require two arguments" >>> verify_foo() - The object has failed to implement interface ...IFoo: The contract of module.IFoo.simple(arg1) is violated because '(a, b)' requires too many arguments. + The object <...Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.simple(arg1) is violated because '(a, b)' requires too many arguments. Variable arguments can be used to implement the required number, as can arguments with defaults. @@ -263,7 +263,7 @@ variable keyword arguments, the implementation must also accept them. ... class Foo(object): ... def needs_kwargs(self, a=1, b=2): pass >>> verify_foo() - The object has failed to implement interface ...IFoo: The contract of module.IFoo.needs_kwargs(**kwargs) is violated because 'Foo.needs_kwargs(a=1, b=2)' doesn't support keyword arguments. + The object <...Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.needs_kwargs(**kwargs) is violated because 'Foo.needs_kwargs(a=1, b=2)' doesn't support keyword arguments. >>> oname, __name__ = __name__, 'module' >>> class IFoo(Interface): @@ -273,7 +273,7 @@ variable keyword arguments, the implementation must also accept them. ... class Foo(object): ... def needs_varargs(self, **kwargs): pass >>> verify_foo() - The object has failed to implement interface ...IFoo: The contract of module.IFoo.needs_varargs(*args) is violated because 'Foo.needs_varargs(**kwargs)' doesn't support variable arguments. + The object <...Foo...> has failed to implement interface ...IFoo: The contract of module.IFoo.needs_varargs(*args) is violated because 'Foo.needs_varargs(**kwargs)' doesn't support variable arguments. Of course, missing attributes are also found and reported, and the source interface of the missing attribute is included. Similarly, when @@ -294,7 +294,7 @@ the failing method is from a parent class, that is also reported. ... class Foo(Base): ... pass >>> verify_foo() - The object has failed to implement interface ...IFoo: + The object <...Foo...> has failed to implement interface ...IFoo: The contract of base.IBase.method(arg1) is violated because 'Base.method()' doesn't allow enough arguments The module.IFoo.x attribute was not provided From bc55fcb183682610befac1eb547046bff91c2b46 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Tue, 28 May 2024 12:41:22 -0400 Subject: [PATCH 31/39] perf: re-intern hot-path getattr names 'PyObject_GetAttrString' creates new string objects from 'char*'. --- .../_zope_interface_coptimizations.c | 105 ++++++++++++------ 1 file changed, 71 insertions(+), 34 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 3331bafe..f0ca5f73 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -69,13 +69,26 @@ Py_TPFLAGS_HAVE_GC #endif +/* Static strings, used to invoke PyObject_GetAttr (only in hot paths) */ +static PyObject *str__class__ = NULL; +static PyObject *str__conform__ = NULL; +static PyObject *str__dict__ = NULL; +static PyObject *str__module__ = NULL; +static PyObject *str__name__ = NULL; +static PyObject *str__providedBy__ = NULL; +static PyObject *str__provides__ = NULL; +static PyObject *str__self__ = NULL; +static PyObject *str_generation = NULL; +static PyObject *str_registry = NULL; +static PyObject *strro = NULL; + /* Static strings, used to invoke PyObject_CallMethodObjArgs */ -static PyObject *str_call_conform; -static PyObject *str_uncached_lookup; -static PyObject *str_uncached_lookupAll; -static PyObject *str_uncached_subscriptions; -static PyObject *strchanged; -static PyObject *str__adapt__; +static PyObject *str_call_conform = NULL; +static PyObject *str_uncached_lookup = NULL; +static PyObject *str_uncached_lookupAll = NULL; +static PyObject *str_uncached_subscriptions = NULL; +static PyObject *strchanged = NULL; +static PyObject *str__adapt__ = NULL; /* Static strings, used to invoke PyObject_GetItem * @@ -84,6 +97,41 @@ static PyObject *str__adapt__; */ static PyObject* str__implemented__; + +static int +define_static_strings() +{ + if (str__class__ != NULL) { + return 0; + } + +#define DEFINE_STATIC_STRING(S) \ + if (!(str##S = PyUnicode_FromString(#S))) \ + return -1 + + DEFINE_STATIC_STRING(__class__); + DEFINE_STATIC_STRING(__conform__); + DEFINE_STATIC_STRING(__dict__); + DEFINE_STATIC_STRING(__module__); + DEFINE_STATIC_STRING(__name__); + DEFINE_STATIC_STRING(__providedBy__); + DEFINE_STATIC_STRING(__provides__); + DEFINE_STATIC_STRING(__self__); + DEFINE_STATIC_STRING(_generation); + DEFINE_STATIC_STRING(_registry); + DEFINE_STATIC_STRING(ro); + DEFINE_STATIC_STRING(__implemented__); + DEFINE_STATIC_STRING(_call_conform); + DEFINE_STATIC_STRING(_uncached_lookup); + DEFINE_STATIC_STRING(_uncached_lookupAll); + DEFINE_STATIC_STRING(_uncached_subscriptions); + DEFINE_STATIC_STRING(changed); + DEFINE_STATIC_STRING(__adapt__); +#undef DEFINE_STATIC_STRING + + return 0; +} + /* Public module-scope functions, forward-declared here FBO type methods. */ static PyObject *implementedBy(PyObject* module, PyObject *cls); static PyObject *getObjectSpecification(PyObject *module, PyObject *ob); @@ -429,7 +477,7 @@ OSD_descr_get(PyObject* self, PyObject* inst, PyObject* cls) return getObjectSpecification(module, cls); } - provides = PyObject_GetAttrString(inst, "__provides__"); + provides = PyObject_GetAttr(inst, str__provides__); /* Return __provides__ if we got it, or return NULL and propagate * non-AttributeError. */ if (provides != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError)) { @@ -781,7 +829,7 @@ IB__call__(PyObject* self, PyObject* args, PyObject* kwargs) args, kwargs, "O|O", kwlist, &obj, &alternate)) return NULL; - conform = PyObject_GetAttrString(obj, "__conform__"); + conform = PyObject_GetAttr(obj, str__conform__); if (conform == NULL) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { /* Propagate non-AttributeErrors */ @@ -911,9 +959,9 @@ IB_richcompare(IB* self, PyObject* other, int op) othername = otherib->__name__; othermod = otherib->__module__; } else { - othername = PyObject_GetAttrString(other, "__name__"); + othername = PyObject_GetAttr(other, str__name__); if (othername) { - othermod = PyObject_GetAttrString(other, "__module__"); + othermod = PyObject_GetAttr(other, str__module__); } if (!othername || !othermod) { if (PyErr_Occurred() && @@ -1354,7 +1402,7 @@ _adapter_hook(LB* self, if (factory != Py_None) { if (PyObject_TypeCheck(object, &PySuper_Type)) { - PyObject* self = PyObject_GetAttrString(object, "__self__"); + PyObject* self = PyObject_GetAttr(object, str__self__); if (self == NULL) { Py_DECREF(factory); return NULL; @@ -1676,8 +1724,7 @@ _generations_tuple(PyObject* ro) for (i = 0; i < l; i++) { PyObject* generation; - generation = PyObject_GetAttrString( - PyTuple_GET_ITEM(ro, i), "_generation"); + generation = PyObject_GetAttr(PyTuple_GET_ITEM(ro, i), str_generation); if (generation == NULL) { Py_DECREF(generations); return NULL; @@ -1694,10 +1741,11 @@ verify_changed(VB* self, PyObject* ignored) VB_clear(self); - t = PyObject_GetAttrString(OBJECT(self), "_registry"); + t = PyObject_GetAttr(OBJECT(self), str_registry); if (t == NULL) return NULL; - ro = PyObject_GetAttrString(t, "ro"); + + ro = PyObject_GetAttr(t, strro); Py_DECREF(t); if (ro == NULL) return NULL; @@ -2236,7 +2284,7 @@ implementedBy(PyObject* module, PyObject* cls) } if (dict == NULL) - dict = PyObject_GetAttrString(cls, "__dict__"); + dict = PyObject_GetAttr(cls, str__dict__); if (dict == NULL) { /* Probably a security proxied class, use more expensive fallback code @@ -2297,7 +2345,7 @@ getObjectSpecification(PyObject* module, PyObject* ob) empty_ = rec->empty; #endif - result = PyObject_GetAttrString(ob, "__provides__"); + result = PyObject_GetAttr(ob, str__provides__); if (!result) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { /* Propagate non AttributeError exceptions. */ @@ -2318,7 +2366,7 @@ getObjectSpecification(PyObject* module, PyObject* ob) } /* We do a getattr here so as not to be defeated by proxies */ - cls = PyObject_GetAttrString(ob, "__class__"); + cls = PyObject_GetAttr(ob, str__class__); if (cls == NULL) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { /* Propagate non-AttributeErrors */ @@ -2358,7 +2406,7 @@ providedBy(PyObject* module, PyObject* ob) return implementedBy(module, ob); } - result = PyObject_GetAttrString(ob, "__providedBy__"); + result = PyObject_GetAttr(ob, str__providedBy__); if (result == NULL) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { @@ -2391,11 +2439,11 @@ providedBy(PyObject* module, PyObject* ob) */ Py_DECREF(result); - cls = PyObject_GetAttrString(ob, "__class__"); + cls = PyObject_GetAttr(ob, str__class__); if (cls == NULL) return NULL; - result = PyObject_GetAttrString(ob, "__provides__"); + result = PyObject_GetAttr(ob, str__provides__); if (result == NULL) { /* No __provides__, so just fall back to implementedBy */ PyErr_Clear(); @@ -2404,7 +2452,7 @@ providedBy(PyObject* module, PyObject* ob) return result; } - cp = PyObject_GetAttrString(cls, "__provides__"); + cp = PyObject_GetAttr(cls, str__provides__); if (cp == NULL) { /* The the class has no provides, assume we're done: */ PyErr_Clear(); @@ -2589,18 +2637,7 @@ static struct PyModuleDef _zic_module_def = { static PyObject* init(void) { -#define DEFINE_STRING(S) \ - if (!(str##S = PyUnicode_FromString(#S))) \ - return NULL - - DEFINE_STRING(__implemented__); - DEFINE_STRING(_call_conform); - DEFINE_STRING(_uncached_lookup); - DEFINE_STRING(_uncached_lookupAll); - DEFINE_STRING(_uncached_subscriptions); - DEFINE_STRING(changed); - DEFINE_STRING(__adapt__); -#undef DEFINE_STRING + if (define_static_strings() < 0) { return NULL; } return PyModuleDef_Init(&_zic_module_def); } From 61a84a13f33c642431b90010e72b8c2d7477f369 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Wed, 12 Jun 2024 10:43:02 -0400 Subject: [PATCH 32/39] refactor: limit special-case handling to 'InterfaceBase' Member descriptor behavior is tricky across Python versions, and across static vs. heap-allocated types. The 'InterfaceBase' base type is a singleton, and has a known/desired "implements name". --- src/zope/interface/declarations.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/zope/interface/declarations.py b/src/zope/interface/declarations.py index 5b4522bb..a9b983da 100644 --- a/src/zope/interface/declarations.py +++ b/src/zope/interface/declarations.py @@ -34,6 +34,7 @@ class implements (that instances of the class provides). from zope.interface._compat import _use_c_impl from zope.interface.interface import Interface +from zope.interface.interface import InterfaceBase from zope.interface.interface import InterfaceClass from zope.interface.interface import NameAndModuleComparisonMixin from zope.interface.interface import Specification @@ -364,12 +365,13 @@ def _implements_name(ob): # It might be nice to use __qualname__ on Python 3, but that would produce # different values between Py2 and Py3. - # Workaround: some C-based interfaces return a 'member_descriptor' for - # their '__module__'. - mod = getattr(ob, '__module__', None) - if not isinstance(mod, str): - mod = getattr(mod, '__name__', '?') - return mod + '.' + (getattr(ob, '__name__', '?') or '?') + # Special-case 'InterfaceBase': its '__module__' member descriptor + # behaves differently across Python 3.x versions. + if ob is InterfaceBase: + return 'zope.interface.interface.InterfaceBase' + + return (getattr(ob, '__module__', '?') or '?') + \ + '.' + (getattr(ob, '__name__', '?') or '?') def _implementedBy_super(sup): From e173384a23d45cfb73132bff6e8ea54579f0bcc2 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 1 Aug 2024 10:58:54 -0400 Subject: [PATCH 33/39] chore: document version hex usage Co-authored-by: David Glick --- src/zope/interface/_zope_interface_coptimizations.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index f0ca5f73..46f93d43 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -49,6 +49,7 @@ #define USE_HEAP_TYPES 1 #endif +/* Add MANAGED_WEAKREF flag for Python >= 3.12 */ #if PY_VERSION_HEX >= 0x030c0000 #define LEAFTYPE_FLAGS \ Py_TPFLAGS_DEFAULT | \ From ee3efff67b8fea89a28f82b41a90e10d69f0eb0f Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 1 Aug 2024 10:59:37 -0400 Subject: [PATCH 34/39] chore: drop use of obscure acronym in comment Co-authored-by: David Glick --- src/zope/interface/_zope_interface_coptimizations.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 46f93d43..b6a08350 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -133,7 +133,7 @@ define_static_strings() return 0; } -/* Public module-scope functions, forward-declared here FBO type methods. */ +/* Public module-scope functions, forward-declared here for type methods. */ static PyObject *implementedBy(PyObject* module, PyObject *cls); static PyObject *getObjectSpecification(PyObject *module, PyObject *ob); static PyObject *providedBy(PyObject *module, PyObject *ob); From 743903dc7a48c68e1c8123fc878cc10663125e1e Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 1 Aug 2024 11:00:16 -0400 Subject: [PATCH 35/39] chore: another acronym bites the dust Co-authored-by: David Glick --- src/zope/interface/_zope_interface_coptimizations.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index b6a08350..0a706f66 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -139,7 +139,7 @@ static PyObject *getObjectSpecification(PyObject *module, PyObject *ob); static PyObject *providedBy(PyObject *module, PyObject *ob); /* - * Utility functions, forward-declared here FBO type methods. + * Utility functions, forward-declared here for type methods. */ static PyObject* _get_module(PyTypeObject *typeobj); static PyObject* _get_adapter_hooks(PyTypeObject *typeobj); From d6f56403e0708e1e2053020245ecfd8d43494148 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 1 Aug 2024 11:04:13 -0400 Subject: [PATCH 36/39] chore: fix typos in comments Co-authored-by: David Glick --- src/zope/interface/_zope_interface_coptimizations.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 0a706f66..c0ea2c68 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -535,7 +535,7 @@ static PyType_Spec OSD_type_spec = { #endif /* - * ClassProviderBase class + * ClassProvidesBase class */ typedef struct { @@ -1064,7 +1064,7 @@ static PyType_Slot IB_type_slots[] = { {Py_tp_dealloc, IB_dealloc}, {Py_tp_methods, IB_methods}, {Py_tp_members, IB_members}, - /* tp_base cannot be set as a stot -- pass to PyType_FromModuleAndSpec */ + /* tp_base cannot be set as a slot -- pass to PyType_FromModuleAndSpec */ {0, NULL} }; @@ -1970,7 +1970,7 @@ static PyType_Slot VB_type_slots[] = { {Py_tp_clear, VB_clear}, {Py_tp_dealloc, VB_dealloc}, {Py_tp_methods, VB_methods}, - /* tp_base cannot be set as a stot -- pass to PyType_FromModuleAndSpec */ + /* tp_base cannot be set as a slot -- pass to PyType_FromModuleAndSpec */ {0, NULL} }; @@ -1997,13 +1997,13 @@ typedef struct PyTypeObject* lookup_base_class; PyTypeObject* verifying_base_class; PyObject* adapter_hooks; - /* members importe from 'zope.interface.declarations' + /* members imported from 'zope.interface.declarations' */ PyObject* empty; PyObject* fallback; PyObject* builtin_impl_specs; PyTypeObject* implements_class; - /* flag: have we importe the next set of members yet from + /* flag: have we imported the next set of members yet from * 'zope.interface.declarations? */ int decl_imported; From 25d664a8af6dfdf84fb07e8f073008dee5c9d2e5 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 1 Aug 2024 11:18:35 -0400 Subject: [PATCH 37/39] chore: link to C API howto for Python 3.8 quirk --- src/zope/interface/_zope_interface_coptimizations.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index c0ea2c68..086a8d86 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -238,7 +238,10 @@ typedef struct static int SB_traverse(SB* self, visitproc visit, void* arg) { -/* Visit our 'tp_type' only on Python >= 3.9 */ +/* Visit our 'tp_type' only on Python >= 3.9, per + * https://docs.python.org/3/howto/isolating-extensions.html + * #tp-traverse-in-python-3-8-and-lower + */ #if PY_VERSION_HEX > 0x03090000 Py_VISIT(Py_TYPE(self)); #endif @@ -1091,6 +1094,10 @@ typedef struct static int LB_traverse(LB* self, visitproc visit, void* arg) { +/* Visit our 'tp_type' only on Python >= 3.9, per + * https://docs.python.org/3/howto/isolating-extensions.html + * #tp-traverse-in-python-3-8-and-lower + */ #if PY_VERSION_HEX > 0x03090000 Py_VISIT(Py_TYPE(self)); #endif From 6bb37a51392dc8ec56e7b2144d2467cc090d7389 Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 1 Aug 2024 13:31:04 -0400 Subject: [PATCH 38/39] refactor: use named flag for explicit weakref lists Rather than checking the Python version repeatedly. See: https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_weaklistoffset --- .../_zope_interface_coptimizations.c | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index 086a8d86..febbe06a 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -49,8 +49,14 @@ #define USE_HEAP_TYPES 1 #endif -/* Add MANAGED_WEAKREF flag for Python >= 3.12 */ #if PY_VERSION_HEX >= 0x030c0000 +/* Add MANAGED_WEAKREF flag for Python >= 3.12, and don't define + * the '.tp_weaklistoffset' slot. + * + * See: https://docs.python.org/3/c-api/typeobj.html + * #c.PyTypeObject.tp_weaklistoffset + */ +#define USE_EXPLICIT_WEAKREFLIST 0 #define LEAFTYPE_FLAGS \ Py_TPFLAGS_DEFAULT | \ Py_TPFLAGS_MANAGED_WEAKREF | \ @@ -61,6 +67,13 @@ Py_TPFLAGS_MANAGED_WEAKREF | \ Py_TPFLAGS_HAVE_GC #else +/* No MANAGED_WEAKREF flag for Python < 3.12, and therefore define + * the '.tp_weaklistoffset' slot, and the member whose offset it holds. + * + * See: https://docs.python.org/3/c-api/typeobj.html + * #c.PyTypeObject.tp_weaklistoffset + */ +#define USE_EXPLICIT_WEAKREFLIST 1 #define LEAFTYPE_FLAGS \ Py_TPFLAGS_DEFAULT | \ Py_TPFLAGS_HAVE_GC @@ -217,7 +230,7 @@ typedef struct make any assumptions about contents. */ PyObject* _implied; -#if PY_VERSION_HEX < 0x030c0000 +#if USE_EXPLICIT_WEAKREFLIST PyObject* weakreflist; #endif /* @@ -271,7 +284,7 @@ SB_dealloc(SB* self) { PyObject_GC_UnTrack((PyObject*)self); PyTypeObject* tp = Py_TYPE(self); -#if PY_VERSION_HEX < 0x030c0000 +#if USE_EXPLICIT_WEAKREFLIST if (self->weakreflist != NULL) { PyObject_ClearWeakRefs(OBJECT(self)); } @@ -393,7 +406,7 @@ static PyMemberDef SB_members[] = { { "_v_attrs", T_OBJECT_EX, offsetof(SB, _v_attrs), 0, "" }, { "__iro__", T_OBJECT_EX, offsetof(SB, __iro__), 0, "" }, { "__sro__", T_OBJECT_EX, offsetof(SB, __sro__), 0, "" }, -#if PY_VERSION_HEX < 0x030c0000 +#if USE_EXPLICIT_WEAKREFLIST { "__weaklistoffset__", T_OBJECT_EX, offsetof(SB, weakreflist), 0, "" }, #endif { NULL }, @@ -418,7 +431,9 @@ static PyTypeObject SB_type_def = { .tp_traverse = (traverseproc)SB_traverse, .tp_clear = (inquiry)SB_clear, .tp_dealloc = (destructor)SB_dealloc, - .tp_weaklistoffset = offsetof(SB, weakreflist), /* XXX */ +#if USE_EXPLICIT_WEAKREFLIST + .tp_weaklistoffset = offsetof(SB, weakreflist), +#endif .tp_methods = SB_methods, .tp_members = SB_members, }; From c35f95ece57c0ccc5740adff03187137b82db1ac Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Sat, 3 Aug 2024 14:43:46 -0400 Subject: [PATCH 39/39] chore: clarify condition for visiting the type object --- src/zope/interface/_zope_interface_coptimizations.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zope/interface/_zope_interface_coptimizations.c b/src/zope/interface/_zope_interface_coptimizations.c index febbe06a..99f36399 100644 --- a/src/zope/interface/_zope_interface_coptimizations.c +++ b/src/zope/interface/_zope_interface_coptimizations.c @@ -255,7 +255,7 @@ SB_traverse(SB* self, visitproc visit, void* arg) * https://docs.python.org/3/howto/isolating-extensions.html * #tp-traverse-in-python-3-8-and-lower */ -#if PY_VERSION_HEX > 0x03090000 +#if USE_HEAP_TYPES && PY_VERSION_HEX > 0x03090000 Py_VISIT(Py_TYPE(self)); #endif Py_VISIT(self->_implied); @@ -1113,7 +1113,7 @@ LB_traverse(LB* self, visitproc visit, void* arg) * https://docs.python.org/3/howto/isolating-extensions.html * #tp-traverse-in-python-3-8-and-lower */ -#if PY_VERSION_HEX > 0x03090000 +#if USE_HEAP_TYPES && PY_VERSION_HEX > 0x03090000 Py_VISIT(Py_TYPE(self)); #endif Py_VISIT(self->_cache);