Skip to content

Commit d18afa0

Browse files
JIT constant fold special method lookup
1 parent b3b0cef commit d18afa0

File tree

6 files changed

+69
-6
lines changed

6 files changed

+69
-6
lines changed

Include/internal/pycore_opcode_metadata.h

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

Lib/test/test_capi/test_opt.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3316,6 +3316,25 @@ def f(n):
33163316
self.assertNotIn("_LOAD_ATTR_METHOD_NO_DICT", uops)
33173317
self.assertIn("_LOAD_CONST_INLINE_BORROW", uops)
33183318

3319+
def test_cached_load_special(self):
3320+
class CM:
3321+
def __enter__(self):
3322+
return self
3323+
def __exit__(self, *args):
3324+
pass
3325+
def f(n):
3326+
cm = CM()
3327+
x = 0
3328+
for _ in range(n):
3329+
with cm:
3330+
x += 1
3331+
return x
3332+
res, ex = self._run_with_optimizer(f, TIER2_THRESHOLD)
3333+
self.assertIsNotNone(ex)
3334+
self.assertEqual(res, TIER2_THRESHOLD)
3335+
uops = get_opnames(ex)
3336+
self.assertNotIn("_LOAD_SPECIAL", uops)
3337+
33193338
def test_store_fast_refcount_elimination(self):
33203339
def foo(x):
33213340
# Since x is known to be

Python/bytecodes.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3887,6 +3887,7 @@ dummy_func(
38873887
}
38883888

38893889
macro(LOAD_SPECIAL) =
3890+
_RECORD_TOS_TYPE +
38903891
_INSERT_NULL +
38913892
_LOAD_SPECIAL;
38923893

Python/optimizer_bytecodes.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1682,8 +1682,29 @@ dummy_func(void) {
16821682
}
16831683

16841684
op(_LOAD_SPECIAL, (method_and_self[2] -- method_and_self[2])) {
1685-
method_and_self[0] = sym_new_not_null(ctx);
1686-
method_and_self[1] = sym_new_unknown(ctx);
1685+
PyTypeObject *type = sym_get_probable_type(method_and_self[1]);
1686+
if (type != NULL) {
1687+
PyObject *name = _Py_SpecialMethods[oparg].name;
1688+
PyObject *descr = _PyType_Lookup(type, name);
1689+
if (descr != NULL && _PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR))
1690+
{
1691+
ADD_OP(_GUARD_TYPE_VERSION, 0, type->tp_version_tag);
1692+
bool immortal = _Py_IsImmortal(descr) || (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE);
1693+
ADD_OP(immortal ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE,
1694+
0, (uintptr_t)descr);
1695+
ADD_OP(_SWAP, 3, 0);
1696+
ADD_OP(_POP_TOP, 0, 0);
1697+
if ((type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) == 0) {
1698+
PyType_Watch(TYPE_WATCHER_ID, (PyObject *)type);
1699+
_Py_BloomFilter_Add(dependencies, type);
1700+
}
1701+
method_and_self[0] = sym_new_const(ctx, descr);
1702+
}
1703+
}
1704+
else {
1705+
method_and_self[0] = sym_new_not_null(ctx);
1706+
method_and_self[1] = sym_new_unknown(ctx);
1707+
}
16871708
}
16881709

16891710
op(_JUMP_TO_TOP, (--)) {

Python/optimizer_cases.c.h

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

Python/record_functions.c.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)