mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-115999: Specialize STORE_ATTR
in free-threaded builds. (gh-127838)
* Add `_PyDictKeys_StringLookupSplit` which does locking on dict keys and use in place of `_PyDictKeys_StringLookup`. * Change `_PyObject_TryGetInstanceAttribute` to use that function in the case of split keys. * Add `unicodekeys_lookup_split` helper which allows code sharing between `_Py_dict_lookup` and `_PyDictKeys_StringLookupSplit`. * Fix locking for `STORE_ATTR_INSTANCE_VALUE`. Create `_GUARD_TYPE_VERSION_AND_LOCK` uop so that object stays locked and `tp_version_tag` cannot change. * Pass `tp_version_tag` to `specialize_dict_access()`, ensuring the version we store on the cache is the correct one (in case of it changing during the specalize analysis). * Split `analyze_descriptor` into `analyze_descriptor_load` and `analyze_descriptor_store` since those don't share much logic. Add `descriptor_is_class` helper function. * In `specialize_dict_access`, double check `_PyObject_GetManagedDict()` in case we race and dict was materialized before the lock. * Avoid borrowed references in `_Py_Specialize_StoreAttr()`. * Use `specialize()` and `unspecialize()` helpers. * Add unit tests to ensure specializing happens as expected in FT builds. * Add unit tests to attempt to trigger data races (useful for running under TSAN). * Add `has_split_table` function to `_testinternalcapi`.
This commit is contained in:
parent
d2f1d917e8
commit
1b15c89a17
13 changed files with 716 additions and 297 deletions
|
@ -1383,6 +1383,72 @@ class TestSpecializer(TestBase):
|
|||
self.assert_specialized(send_yield_from, "SEND_GEN")
|
||||
self.assert_no_opcode(send_yield_from, "SEND")
|
||||
|
||||
@cpython_only
|
||||
@requires_specialization_ft
|
||||
def test_store_attr_slot(self):
|
||||
class C:
|
||||
__slots__ = ['x']
|
||||
|
||||
def set_slot():
|
||||
c = C()
|
||||
for i in range(100):
|
||||
c.x = i
|
||||
|
||||
set_slot()
|
||||
|
||||
self.assert_specialized(set_slot, "STORE_ATTR_SLOT")
|
||||
self.assert_no_opcode(set_slot, "STORE_ATTR")
|
||||
|
||||
# Adding a property for 'x' should unspecialize it.
|
||||
C.x = property(lambda self: None, lambda self, x: None)
|
||||
set_slot()
|
||||
self.assert_no_opcode(set_slot, "STORE_ATTR_SLOT")
|
||||
|
||||
@cpython_only
|
||||
@requires_specialization_ft
|
||||
def test_store_attr_instance_value(self):
|
||||
class C:
|
||||
pass
|
||||
|
||||
def set_value():
|
||||
c = C()
|
||||
for i in range(100):
|
||||
c.x = i
|
||||
|
||||
set_value()
|
||||
|
||||
self.assert_specialized(set_value, "STORE_ATTR_INSTANCE_VALUE")
|
||||
self.assert_no_opcode(set_value, "STORE_ATTR")
|
||||
|
||||
# Adding a property for 'x' should unspecialize it.
|
||||
C.x = property(lambda self: None, lambda self, x: None)
|
||||
set_value()
|
||||
self.assert_no_opcode(set_value, "STORE_ATTR_INSTANCE_VALUE")
|
||||
|
||||
@cpython_only
|
||||
@requires_specialization_ft
|
||||
def test_store_attr_with_hint(self):
|
||||
class C:
|
||||
pass
|
||||
|
||||
c = C()
|
||||
for i in range(29):
|
||||
setattr(c, f"_{i}", None)
|
||||
|
||||
def set_value():
|
||||
for i in range(100):
|
||||
c.x = i
|
||||
|
||||
set_value()
|
||||
|
||||
self.assert_specialized(set_value, "STORE_ATTR_WITH_HINT")
|
||||
self.assert_no_opcode(set_value, "STORE_ATTR")
|
||||
|
||||
# Adding a property for 'x' should unspecialize it.
|
||||
C.x = property(lambda self: None, lambda self, x: None)
|
||||
set_value()
|
||||
self.assert_no_opcode(set_value, "STORE_ATTR_WITH_HINT")
|
||||
|
||||
@cpython_only
|
||||
@requires_specialization_ft
|
||||
def test_to_bool(self):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue