From fbb6def08a7ce7d21653e15ccbc4017b4eb2e795 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 12 May 2023 16:03:47 -0700 Subject: [3.11] GH-104405: Add missing PEP 523 checks (GH-104441) --- Lib/test/test_capi/test_misc.py | 47 +++++++++++++--------- .../2023-05-12-00-19-02.gh-issue-104405.tXV5fn.rst | 2 + Python/ceval.c | 1 + Python/specialize.c | 4 ++ 4 files changed, 36 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-05-12-00-19-02.gh-issue-104405.tXV5fn.rst diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index 67150a8..3e36fbd 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1378,28 +1378,39 @@ SUFFICIENT_TO_DEOPT_AND_SPECIALIZE = 100 class Test_Pep523API(unittest.TestCase): - def do_test(self, func): - calls = [] + def do_test(self, func, names): + actual_calls = [] start = SUFFICIENT_TO_DEOPT_AND_SPECIALIZE count = start + SUFFICIENT_TO_DEOPT_AND_SPECIALIZE - for i in range(count): - if i == start: - _testinternalcapi.set_eval_frame_record(calls) - func() - _testinternalcapi.set_eval_frame_default() - self.assertEqual(len(calls), SUFFICIENT_TO_DEOPT_AND_SPECIALIZE) - for name in calls: - self.assertEqual(name, func.__name__) - - def test_pep523_with_specialization_simple(self): - def func1(): - pass - self.do_test(func1) + try: + for i in range(count): + if i == start: + _testinternalcapi.set_eval_frame_record(actual_calls) + func() + finally: + _testinternalcapi.set_eval_frame_default() + expected_calls = names * SUFFICIENT_TO_DEOPT_AND_SPECIALIZE + self.assertEqual(len(expected_calls), len(actual_calls)) + for expected, actual in zip(expected_calls, actual_calls, strict=True): + self.assertEqual(expected, actual) + + def test_inlined_binary_subscr(self): + class C: + def __getitem__(self, other): + return None + def func(): + C()[42] + names = ["func", "__getitem__"] + self.do_test(func, names) - def test_pep523_with_specialization_with_default(self): - def func2(x=None): + def test_inlined_call(self): + def inner(x=42): pass - self.do_test(func2) + def func(): + inner() + inner(42) + names = ["func", "inner", "inner"] + self.do_test(func, names) if __name__ == "__main__": diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-05-12-00-19-02.gh-issue-104405.tXV5fn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-05-12-00-19-02.gh-issue-104405.tXV5fn.rst new file mode 100644 index 0000000..06ec5d7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-05-12-00-19-02.gh-issue-104405.tXV5fn.rst @@ -0,0 +1,2 @@ +Fix an issue where some :term:`bytecode` instructions could ignore +:pep:`523` when "inlining" calls. diff --git a/Python/ceval.c b/Python/ceval.c index 72f9c83..47df353 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2233,6 +2233,7 @@ handle_eval_breaker: } TARGET(BINARY_SUBSCR_GETITEM) { + DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR); PyObject *sub = TOP(); PyObject *container = SECOND(); _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr; diff --git a/Python/specialize.c b/Python/specialize.c index 08ce2f5..9d182fd 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -1238,6 +1238,10 @@ _Py_Specialize_BinarySubscr( SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OUT_OF_VERSIONS); goto fail; } + if (_PyInterpreterState_GET()->eval_frame) { + SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_OTHER); + goto fail; + } cache->func_version = version; ((PyHeapTypeObject *)container_type)->_spec_cache.getitem = descriptor; _Py_SET_OPCODE(*instr, BINARY_SUBSCR_GETITEM); -- cgit v0.12