Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -10581,7 +10581,10 @@ _Py_slot_tp_getattr_hook(PyObject *self, PyObject *name)
getattr = _PyType_LookupRef(tp, &_Py_ID(__getattr__));
if (getattr == NULL) {
/* No __getattr__ hook: use a simpler dispatcher */
#ifndef Py_GIL_DISABLED
// Replacing the slot is only thread-safe if there is a GIL.
tp->tp_getattro = _Py_slot_tp_getattro;
#endif
return _Py_slot_tp_getattro(self, name);
}
/* speed hack: we could use lookup_maybe, but that would resolve the
Expand Down
9 changes: 1 addition & 8 deletions Python/specialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -935,8 +935,7 @@ analyze_descriptor_load(PyTypeObject *type, PyObject *name, PyObject **descr, un
PyObject *getattr = _PyType_Lookup(type, &_Py_ID(__getattr__));
has_getattr = getattr != NULL;
if (has_custom_getattribute) {
if (getattro_slot == _Py_slot_tp_getattro &&
!has_getattr &&
if (!has_getattr &&
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Fidget-Spinner, I removed the getattro_slot == _Py_slot_tp_getattro check here because:

  1. It would prevent specialization of __getattribute__ Python calls in the free threaded build with this change
  2. I don't think it's necessary. The combined has_custom_getattribute and !has_getattr checks are sufficient.

Does this make sense to you?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense for the FT build. Just reasoning out loud here: From what I see above, we replace the NULL slot with the special "__getattribute__ but no __getattr__" slot at some lookup time. But it's functionally the same as just saying get_attr == NULL. So the check for the slot is redundant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I should add that we already check getattro_slot == _Py_slot_tp_getattr_hook || getattro_slot == _Py_slot_tp_getattro above.

Another way of saying this:

  1. There's a C pseudo-specialization process of rewriting _Py_slot_tp_getattr_hook to _Py_slot_tp_getattro
  2. The Python specialization of rewriting LOAD_ATTR to LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN shouldn't require _Py_slot_tp_getattr_hook to have already replaced by _Py_slot_tp_getattro. It just needs to ensure the conditions are correct (i.e, __getattribute__ is present, __getattr__ is not and the getattro_slot isn't overridden with something else)

Py_IS_TYPE(getattribute, &PyFunction_Type)) {
*descr = getattribute;
*tp_version = ga_version;
Expand Down Expand Up @@ -1259,12 +1258,6 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
return -1;
case GETATTRIBUTE_IS_PYTHON_FUNCTION:
{
#ifndef Py_GIL_DISABLED
// In free-threaded builds it's possible for tp_getattro to change
// after the call to analyze_descriptor. That is fine: the version
// guard will fail.
assert(type->tp_getattro == _Py_slot_tp_getattro);
#endif
assert(Py_IS_TYPE(descr, &PyFunction_Type));
_PyLoadMethodCache *lm_cache = (_PyLoadMethodCache *)(instr + 1);
if (!function_check_args(descr, 2, LOAD_ATTR)) {
Expand Down
1 change: 0 additions & 1 deletion Tools/tsan/suppressions_free_threading.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ race:list_inplace_repeat_lock_held
race:PyObject_Realloc

# gh-133467. Some of these could be hard to trigger.
race_top:_Py_slot_tp_getattr_hook
race_top:slot_tp_descr_get
race_top:type_set_name
race_top:set_tp_bases
Expand Down
Loading