sys.modules.pop("test_module_with_getattr", None)
+ @cpython_only
+ @requires_specialization
+ def test_load_attr_enum(self):
+ import enum
+
+ class Color(enum.IntEnum):
+ RED = 1
+ GREEN = 2
+ BLUE = 3
+
+ def load_enum_member():
+ for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
+ x = Color.RED
+ assert x == 1
+
+ load_enum_member()
+ self.assert_specialized(load_enum_member,
+ "LOAD_ATTR_CLASS_WITH_METACLASS_CHECK")
+
+
if __name__ == "__main__":
unittest.main()
}
}
switch (kind) {
- case METHOD:
- case NON_DESCRIPTOR:
- #ifdef Py_GIL_DISABLED
- if (!_PyObject_HasDeferredRefcount(descr)) {
- SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_DESCR_NOT_DEFERRED);
+ case MUTABLE:
+ // special case for enums which has Py_TYPE(descr) == cls
+ // so guarding on type version is sufficient
+ if (Py_TYPE(descr) != cls) {
+ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_MUTABLE_CLASS);
Py_XDECREF(descr);
return -1;
}
- #endif
- write_u32(cache->type_version, tp_version);
+ if (Py_TYPE(descr)->tp_descr_get || Py_TYPE(descr)->tp_descr_set) {
+ SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR);
+ Py_XDECREF(descr);
+ return -1;
+ }
+ _Py_FALLTHROUGH;
+ case METHOD:
+ case NON_DESCRIPTOR:
+#ifdef Py_GIL_DISABLED
+ maybe_enable_deferred_ref_count(descr);
+#endif
write_ptr(cache->descr, descr);
if (metaclass_check) {
- write_u32(cache->keys_version, meta_version);
+ write_u32(cache->keys_version, tp_version);
+ write_u32(cache->type_version, meta_version);
specialize(instr, LOAD_ATTR_CLASS_WITH_METACLASS_CHECK);
}
else {
+ write_u32(cache->type_version, tp_version);
specialize(instr, LOAD_ATTR_CLASS);
}
Py_XDECREF(descr);
setattr(obj, f"{prefix}_c", None)
+from enum import Enum
+class MyEnum(Enum):
+ X = 1
+ Y = 2
+ Z = 3
+
+@register_benchmark
+def enum_attr():
+ for _ in range(1000 * WORK_SCALE):
+ MyEnum.X
+ MyEnum.Y
+ MyEnum.Z
+
+
def bench_one_thread(func):
t0 = time.perf_counter_ns()
func()