GH-131798: Optimize cached class attributes and methods in the JIT (GH-134403)

This commit is contained in:
Brandt Bucher 2025-05-22 11:15:03 -04:00 committed by GitHub
parent 09e72cf091
commit ec736e7dae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 365 additions and 130 deletions

View file

@ -1280,8 +1280,8 @@ class TestUopsOptimization(unittest.TestCase):
self.assertIsNotNone(ex)
self.assertEqual(res, TIER2_THRESHOLD * 6 + 1)
call = opnames.index("_CALL_BUILTIN_FAST")
load_attr_top = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", 0, call)
load_attr_bottom = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", call)
load_attr_top = opnames.index("_POP_TOP_LOAD_CONST_INLINE_BORROW", 0, call)
load_attr_bottom = opnames.index("_POP_TOP_LOAD_CONST_INLINE_BORROW", call)
self.assertEqual(opnames[:load_attr_top].count("_GUARD_TYPE_VERSION"), 1)
self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 2)
@ -1303,8 +1303,8 @@ class TestUopsOptimization(unittest.TestCase):
self.assertIsNotNone(ex)
self.assertEqual(res, TIER2_THRESHOLD * 2)
call = opnames.index("_CALL_BUILTIN_FAST_WITH_KEYWORDS")
load_attr_top = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", 0, call)
load_attr_bottom = opnames.index("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", call)
load_attr_top = opnames.index("_POP_TOP_LOAD_CONST_INLINE_BORROW", 0, call)
load_attr_bottom = opnames.index("_POP_TOP_LOAD_CONST_INLINE_BORROW", call)
self.assertEqual(opnames[:load_attr_top].count("_GUARD_TYPE_VERSION"), 1)
self.assertEqual(opnames[call:load_attr_bottom].count("_CHECK_VALIDITY"), 2)
@ -2169,6 +2169,45 @@ class TestUopsOptimization(unittest.TestCase):
self.assertNotIn("_LOAD_SMALL_INT", uops)
self.assertIn("_LOAD_CONST_INLINE_BORROW", uops)
def test_cached_attributes(self):
class C:
A = 1
def m(self):
return 1
class D:
__slots__ = ()
A = 1
def m(self):
return 1
class E(Exception):
def m(self):
return 1
def f(n):
x = 0
c = C()
d = D()
e = E()
for _ in range(n):
x += C.A # _LOAD_ATTR_CLASS
x += c.A # _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES
x += d.A # _LOAD_ATTR_NONDESCRIPTOR_NO_DICT
x += c.m() # _LOAD_ATTR_METHOD_WITH_VALUES
x += d.m() # _LOAD_ATTR_METHOD_NO_DICT
x += e.m() # _LOAD_ATTR_METHOD_LAZY_DICT
return x
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
self.assertEqual(res, 6 * TIER2_THRESHOLD)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertNotIn("_LOAD_ATTR_CLASS", uops)
self.assertNotIn("_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES", uops)
self.assertNotIn("_LOAD_ATTR_NONDESCRIPTOR_NO_DICT", uops)
self.assertNotIn("_LOAD_ATTR_METHOD_WITH_VALUES", uops)
self.assertNotIn("_LOAD_ATTR_METHOD_NO_DICT", uops)
self.assertNotIn("_LOAD_ATTR_METHOD_LAZY_DICT", uops)
def global_identity(x):
return x