From 1ed4e037aae219d48ed671fff956f28a23b109f3 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Tue, 9 Jan 2024 17:01:44 +0000 Subject: [PATCH 1/6] duplicate blocks with no lineno that have an eval break and multiple predecessors --- Lib/test/test_compile.py | 15 +++++++++++++++ Python/flowgraph.c | 18 ++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 45fd30987760cb..50629b22822245 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -1098,6 +1098,21 @@ async def test(aseq): code_lines = self.get_code_lines(test.__code__) self.assertEqual(expected_lines, code_lines) + def test_line_number_synthetic_jump_multiple_predecessors(self): + def f(): + for x in it: + try: + if C1: + yield 2 + except OSError: + pass + + # Ensure that all JUMP_BACKWARDs have line number + code = f.__code__ + for inst in dis.Bytecode(code): + if inst.opname == 'JUMP_BACKWARD': + self.assertIsNotNone(inst.positions.lineno) + def test_lineno_of_backward_jump(self): # Issue gh-107901 def f(): diff --git a/Python/flowgraph.c b/Python/flowgraph.c index dad945761a4a58..18fe5b57f78fc8 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -316,6 +316,16 @@ basicblock_exits_scope(const basicblock *b) { return last && IS_SCOPE_EXIT_OPCODE(last->i_opcode); } +static inline int +basicblock_has_eval_break(const basicblock *b) { + for (int i = 0; i < b->b_iused; i++) { + if (OPCODE_HAS_EVAL_BREAK(b->b_instr[i].i_opcode)) { + return true; + } + } + return false; +} + static bool cfg_builder_current_block_is_terminated(cfg_builder *g) { @@ -2246,8 +2256,8 @@ convert_pseudo_ops(basicblock *entryblock) } static inline bool -is_exit_without_lineno(basicblock *b) { - if (!basicblock_exits_scope(b)) { +is_exit_or_eval_check_without_lineno(basicblock *b) { + if (! (basicblock_exits_scope(b) || basicblock_has_eval_break(b))) { return false; } for (int i = 0; i < b->b_iused; i++) { @@ -2283,7 +2293,7 @@ duplicate_exits_without_lineno(cfg_builder *g) } if (is_jump(last)) { basicblock *target = next_nonempty_block(last->i_target); - if (is_exit_without_lineno(target) && target->b_predecessors > 1) { + if (is_exit_or_eval_check_without_lineno(target) && target->b_predecessors > 1) { basicblock *new_target = copy_basicblock(g, target); if (new_target == NULL) { return ERROR; @@ -2303,7 +2313,7 @@ duplicate_exits_without_lineno(cfg_builder *g) * fall through, and thus can only have a single predecessor */ for (basicblock *b = entryblock; b != NULL; b = b->b_next) { if (BB_HAS_FALLTHROUGH(b) && b->b_next && b->b_iused > 0) { - if (is_exit_without_lineno(b->b_next)) { + if (is_exit_or_eval_check_without_lineno(b->b_next)) { cfg_instr *last = basicblock_last_instr(b); assert(last != NULL); b->b_next->b_instr[0].i_loc = last->i_loc; From 92b4cc40a14b25f5bc609513653d6f91e72978c8 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 16:54:57 +0000 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2024-01-11-16-54-53.gh-issue-107901.Td3JPI.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-53.gh-issue-107901.Td3JPI.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-53.gh-issue-107901.Td3JPI.rst b/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-53.gh-issue-107901.Td3JPI.rst new file mode 100644 index 00000000000000..bf349a3e504ac8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-53.gh-issue-107901.Td3JPI.rst @@ -0,0 +1 @@ +Compiler duplicates basic blocks that have an eval breaker check, no line number, and multiple predecessors on different lines. From 742721df71c4745366ce7ca9879889ce4a25b50a Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 11 Jan 2024 16:54:58 +0000 Subject: [PATCH 3/6] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst b/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst new file mode 100644 index 00000000000000..bf349a3e504ac8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst @@ -0,0 +1 @@ +Compiler duplicates basic blocks that have an eval breaker check, no line number, and multiple predecessors on different lines. From 331f7c8176975f93efa50e3f73a9bcd75f3d26df Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 11 Jan 2024 16:57:15 +0000 Subject: [PATCH 4/6] Delete Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-53.gh-issue-107901.Td3JPI.rst --- .../2024-01-11-16-54-53.gh-issue-107901.Td3JPI.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-53.gh-issue-107901.Td3JPI.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-53.gh-issue-107901.Td3JPI.rst b/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-53.gh-issue-107901.Td3JPI.rst deleted file mode 100644 index bf349a3e504ac8..00000000000000 --- a/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-53.gh-issue-107901.Td3JPI.rst +++ /dev/null @@ -1 +0,0 @@ -Compiler duplicates basic blocks that have an eval breaker check, no line number, and multiple predecessors on different lines. From ebc40fef2746626ae663f0b4dd4704d42732ac42 Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Thu, 11 Jan 2024 17:08:28 +0000 Subject: [PATCH 5/6] tweak news --- .../2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst b/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst index bf349a3e504ac8..ce59ef55b5ee60 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2024-01-11-16-54-55.gh-issue-107901.Td3JPI.rst @@ -1 +1 @@ -Compiler duplicates basic blocks that have an eval breaker check, no line number, and multiple predecessors on different lines. +Compiler duplicates basic blocks that have an eval breaker check, no line number, and multiple predecessors. From 575c14deef70dbe65ed310d16415805e6a5ab163 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 12 Jan 2024 14:41:51 +0000 Subject: [PATCH 6/6] rejig is_exit_or_eval_check_without_lineno to make it clearer --- Python/flowgraph.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 18fe5b57f78fc8..4778f89e19b143 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -2257,15 +2257,17 @@ convert_pseudo_ops(basicblock *entryblock) static inline bool is_exit_or_eval_check_without_lineno(basicblock *b) { - if (! (basicblock_exits_scope(b) || basicblock_has_eval_break(b))) { - return false; - } - for (int i = 0; i < b->b_iused; i++) { - if (b->b_instr[i].i_loc.lineno >= 0) { - return false; + if (basicblock_exits_scope(b) || basicblock_has_eval_break(b)) { + for (int i = 0; i < b->b_iused; i++) { + if (b->b_instr[i].i_loc.lineno >= 0) { + return false; + } } + return true; + } + else { + return false; } - return true; }