Skip to content

Commit e7cea82

Browse files
committed
Specialize LOAD_ATTR_SLOT
- Use atomics and _Py_TryIncrefCompareStackRef in _LOAD_ATTR_SLOT - Pass type version during specialization
1 parent d0920ea commit e7cea82

File tree

5 files changed

+76
-16
lines changed

5 files changed

+76
-16
lines changed

Lib/test/test_opcache.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,33 @@ def write(items):
947947
opname = "LOAD_ATTR_PROPERTY"
948948
self.assert_races_do_not_crash(opname, get_items, read, write)
949949

950+
@requires_specialization_ft
951+
def test_load_attr_slot(self):
952+
def get_items():
953+
class C:
954+
__slots__ = ["a", "b"]
955+
956+
items = []
957+
for i in range(self.ITEMS):
958+
item = C()
959+
item.a = i
960+
item.b = i + self.ITEMS
961+
items.append(item)
962+
return items
963+
964+
def read(items):
965+
for item in items:
966+
item.a
967+
item.b
968+
969+
def write(items):
970+
for item in items:
971+
item.a = 100
972+
item.b = 200
973+
974+
opname = "LOAD_ATTR_SLOT"
975+
self.assert_races_do_not_crash(opname, get_items, read, write)
976+
950977
@requires_specialization_ft
951978
def test_load_attr_with_hint(self):
952979
def get_items():

Python/bytecodes.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2255,12 +2255,20 @@ dummy_func(
22552255
split op(_LOAD_ATTR_SLOT, (index/1, owner -- attr, null if (oparg & 1))) {
22562256
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
22572257

2258-
char *addr = (char *)owner_o + index;
2259-
PyObject *attr_o = *(PyObject **)addr;
2258+
PyObject **addr = (PyObject **)((char *)owner_o + index);
2259+
PyObject *attr_o = FT_ATOMIC_LOAD_PTR(*addr);
22602260
DEOPT_IF(attr_o == NULL);
2261+
#ifdef Py_GIL_DISABLED
2262+
int increfed = _Py_TryIncrefCompareStackRef(addr, attr_o, &attr);
2263+
DEOPT_IF(!increfed);
2264+
#else
2265+
// XXX - Bug in cases generator
2266+
Py_INCREF(attr_o);
2267+
attr = PyStackRef_FromPyObjectSteal(attr_o);
2268+
#endif
22612269
STAT_INC(LOAD_ATTR, hit);
2270+
22622271
null = PyStackRef_NULL;
2263-
attr = PyStackRef_FromPyObjectNew(attr_o);
22642272
DECREF_INPUTS();
22652273
}
22662274

Python/executor_cases.c.h

Lines changed: 26 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 10 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/specialize.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,7 +1203,6 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
12031203
}
12041204
case OBJECT_SLOT:
12051205
{
1206-
FT_UNIMPLEMENTED();
12071206
PyMemberDescrObject *member = (PyMemberDescrObject *)descr;
12081207
struct PyMemberDef *dmem = member->d_member;
12091208
Py_ssize_t offset = dmem->offset;
@@ -1222,17 +1221,16 @@ do_specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject*
12221221
assert(dmem->type == Py_T_OBJECT_EX || dmem->type == _Py_T_OBJECT);
12231222
assert(offset > 0);
12241223
cache->index = (uint16_t)offset;
1225-
write_u32(cache->version, type->tp_version_tag);
1224+
write_u32(cache->version, tp_version);
12261225
specialize(instr, LOAD_ATTR_SLOT);
12271226
return 0;
12281227
}
12291228
case DUNDER_CLASS:
12301229
{
1231-
FT_UNIMPLEMENTED();
12321230
Py_ssize_t offset = offsetof(PyObject, ob_type);
12331231
assert(offset == (uint16_t)offset);
12341232
cache->index = (uint16_t)offset;
1235-
write_u32(cache->version, type->tp_version_tag);
1233+
write_u32(cache->version, tp_version);
12361234
specialize(instr, LOAD_ATTR_SLOT);
12371235
return 0;
12381236
}

0 commit comments

Comments
 (0)