Skip to content

Commit d7cccef

Browse files
Merge branch 'python:main' into fix/148222
2 parents e6a5d95 + e371ce1 commit d7cccef

File tree

4 files changed

+54
-8
lines changed

4 files changed

+54
-8
lines changed

Lib/test/test_opcache.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,5 +2047,25 @@ def load_module_attr_missing():
20472047
sys.modules.pop("test_module_with_getattr", None)
20482048

20492049

2050+
@cpython_only
2051+
@requires_specialization
2052+
def test_load_attr_enum(self):
2053+
import enum
2054+
2055+
class Color(enum.IntEnum):
2056+
RED = 1
2057+
GREEN = 2
2058+
BLUE = 3
2059+
2060+
def load_enum_member():
2061+
for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
2062+
x = Color.RED
2063+
assert x == 1
2064+
2065+
load_enum_member()
2066+
self.assert_specialized(load_enum_member,
2067+
"LOAD_ATTR_CLASS_WITH_METACLASS_CHECK")
2068+
2069+
20502070
if __name__ == "__main__":
20512071
unittest.main()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The specializing interpreter now specializes for :class:`enum.Enum` improving performance and scaling in free-threading. Patch by Kumar Aditya.

Python/specialize.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,22 +1201,33 @@ specialize_class_load_attr(PyObject *owner, _Py_CODEUNIT *instr,
12011201
}
12021202
}
12031203
switch (kind) {
1204-
case METHOD:
1205-
case NON_DESCRIPTOR:
1206-
#ifdef Py_GIL_DISABLED
1207-
if (!_PyObject_HasDeferredRefcount(descr)) {
1208-
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED);
1204+
case MUTABLE:
1205+
// special case for enums which has Py_TYPE(descr) == cls
1206+
// so guarding on type version is sufficient
1207+
if (Py_TYPE(descr) != cls) {
1208+
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
12091209
Py_XDECREF(descr);
12101210
return -1;
12111211
}
1212-
#endif
1213-
write_u32(cache->type_version, tp_version);
1212+
if (Py_TYPE(descr)->tp_descr_get || Py_TYPE(descr)->tp_descr_set) {
1213+
SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
1214+
Py_XDECREF(descr);
1215+
return -1;
1216+
}
1217+
_Py_FALLTHROUGH;
1218+
case METHOD:
1219+
case NON_DESCRIPTOR:
1220+
#ifdef Py_GIL_DISABLED
1221+
maybe_enable_deferred_ref_count(descr);
1222+
#endif
12141223
write_ptr(cache->descr, descr);
12151224
if (metaclass_check) {
1216-
write_u32(cache->keys_version, meta_version);
1225+
write_u32(cache->keys_version, tp_version);
1226+
write_u32(cache->type_version, meta_version);
12171227
specialize(instr, LOAD_ATTR_CLASS_WITH_METACLASS_CHECK);
12181228
}
12191229
else {
1230+
write_u32(cache->type_version, tp_version);
12201231
specialize(instr, LOAD_ATTR_CLASS);
12211232
}
12221233
Py_XDECREF(descr);

Tools/ftscalingbench/ftscalingbench.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,20 @@ def setattr_non_interned():
295295
setattr(obj, f"{prefix}_c", None)
296296

297297

298+
from enum import Enum
299+
class MyEnum(Enum):
300+
X = 1
301+
Y = 2
302+
Z = 3
303+
304+
@register_benchmark
305+
def enum_attr():
306+
for _ in range(1000 * WORK_SCALE):
307+
MyEnum.X
308+
MyEnum.Y
309+
MyEnum.Z
310+
311+
298312
def bench_one_thread(func):
299313
t0 = time.perf_counter_ns()
300314
func()

0 commit comments

Comments
 (0)