Bytecode parity (#7885)

* Align codegen CFG cleanup with CPython

* Align codegen bytecode with CPython 3.14

* Remove remove_jump_target_line_nops

The pass dropped a same-line NOP at the start of any jump-targeted block
whose body advanced to a later line, but CPython's basicblock_remove_redundant_nops
only consults the previous/next instruction inside the same block. The
extra pass deleted the else-body line trace anchor exercised by
test_nested_double_async_with.

Ignore test_conditional_break_finally_does_not_keep_break_cleanup_nop;
the break NOP lands in a separate block from the inlined finally body,
so same-line successor elision does not apply here.

* Keep except_handler blocks reachable in eliminate_unreachable_blocks

After convert_pseudo_ops lowers SETUP_FINALLY to a plain NOP, the only
remaining link from the try body to the except_handler block was the
per-instruction except_handler annotation. When earlier passes had
already removed every NOP that carried that annotation (e.g. an empty
try body with `pass`), the handler block became unreachable from the
entry block and its instructions were cleared, dropping the handler
entirely. Seed reachability with blocks already marked except_handler
so handler dispatch survives independent of the in-block annotation.

Also drop two expectedFailure markers in test_patma whose match-tracing
expectations now pass.

* Align bytecode CFG cleanup with CPython
This commit is contained in:
Jeong, YunWon authored and GitHub committed 2026-05-19 19:24:45 +09:00
1 parent d6160df238
commit 4266f1e8a6
5 files changed
+4517 -9610

No files matched your search

+3
View File
@@ -57,6 +57,7 @@
"words": [
"aiterable",
"alnum",
"csock",
"coro",
"dedentations",
"dedents",
@@ -80,6 +81,8 @@
"reraising",
"significand",
"summands",
"TESTFN",
"TZPATH",
"unraisable",
"wasi",
"weaked",
-2
View File
@@ -3433,7 +3433,6 @@ class TestTracing(unittest.TestCase):
sys.settrace(old_trace)
return actual_linenos
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_default_wildcard(self):
def f(command): # 0
match command.split(): # 1
@@ -3494,7 +3493,6 @@ class TestTracing(unittest.TestCase):
self.assertListEqual(self._trace(f, "go x"), [1, 2, 3])
self.assertListEqual(self._trace(f, "spam"), [1, 2, 3])
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_unreachable_code(self):
def f(command): # 0
match command: # 1
File diff suppressed because it is too large. Load diff
+1404 -9432
View File
File diff suppressed because it is too large. Load diff
@@ -81,21 +81,21 @@ Disassembly of <code object test at 0xdeadbeef file "<?>", line 1>:
L18: CLEANUP_THROW
L19: END_SEND
TO_BOOL
POP_JUMP_IF_TRUE 2 (to L20)
NOT_TAKEN
RERAISE 2
L20: POP_TOP
L21: POP_EXCEPT
POP_JUMP_IF_TRUE 2 (to L22)
L20: NOT_TAKEN
L21: RERAISE 2
L22: POP_TOP
L23: POP_EXCEPT
POP_TOP
POP_TOP
POP_TOP
JUMP_FORWARD 3 (to L23)
L22: COPY 3
JUMP_FORWARD 3 (to L25)
L24: COPY 3
POP_EXCEPT
RERAISE 1
L23: NOP
L25: NOP
10 L24: LOAD_GLOBAL 4 (self)
10 L26: LOAD_GLOBAL 4 (self)
LOAD_ATTR 13 (fail + NULL|self)
LOAD_FAST 0 (stop_exc)
FORMAT_SIMPLE
@@ -103,81 +103,83 @@ Disassembly of <code object test at 0xdeadbeef file "<?>", line 1>:
BUILD_STRING 2
CALL 1
POP_TOP
JUMP_FORWARD 45 (to L31)
JUMP_FORWARD 45 (to L33)
-- L25: PUSH_EXC_INFO
-- L27: PUSH_EXC_INFO
7 LOAD_GLOBAL 14 (Exception)
CHECK_EXC_MATCH
POP_JUMP_IF_FALSE 32 (to L29)
POP_JUMP_IF_FALSE 32 (to L31)
NOT_TAKEN
STORE_FAST 1 (ex)
8 L26: LOAD_GLOBAL 4 (self)
8 L28: LOAD_GLOBAL 4 (self)
LOAD_ATTR 17 (assertIs + NULL|self)
LOAD_FAST_LOAD_FAST 16 (ex, stop_exc)
CALL 2
POP_TOP
L27: POP_EXCEPT
L29: POP_EXCEPT
LOAD_CONST 3 (None)
STORE_FAST 1 (ex)
DELETE_FAST 1 (ex)
JUMP_FORWARD 8 (to L31)
JUMP_FORWARD 8 (to L33)
-- L28: LOAD_CONST 3 (None)
-- L30: LOAD_CONST 3 (None)
STORE_FAST 1 (ex)
DELETE_FAST 1 (ex)
RERAISE 1
7 L29: RERAISE 0
7 L31: RERAISE 0
-- L30: COPY 3
-- L32: COPY 3
POP_EXCEPT
RERAISE 1
3 L31: LOAD_CONST 3 (None)
3 L33: LOAD_CONST 3 (None)
LOAD_CONST 3 (None)
LOAD_CONST 3 (None)
CALL 3
POP_TOP
JUMP_BACKWARD 188 (to L2)
L32: PUSH_EXC_INFO
L34: PUSH_EXC_INFO
WITH_EXCEPT_START
TO_BOOL
POP_JUMP_IF_TRUE 2 (to L33)
NOT_TAKEN
RERAISE 2
L33: POP_TOP
L34: POP_EXCEPT
POP_JUMP_IF_TRUE 2 (to L37)
L35: NOT_TAKEN
L36: RERAISE 2
L37: POP_TOP
L38: POP_EXCEPT
POP_TOP
POP_TOP
POP_TOP
JUMP_BACKWARD 205 (to L2)
L35: COPY 3
L39: COPY 3
POP_EXCEPT
RERAISE 1
-- L36: CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR)
-- L40: CALL_INTRINSIC_1 3 (INTRINSIC_STOPITERATION_ERROR)
RERAISE 1
ExceptionTable:
L1 to L3 -> L36 [0] lasti
L3 to L4 -> L32 [3] lasti
L5 to L7 -> L25 [3]
L1 to L3 -> L40 [0] lasti
L3 to L4 -> L34 [3] lasti
L5 to L7 -> L27 [3]
L7 to L8 -> L12 [7]
L8 to L10 -> L25 [3]
L8 to L10 -> L27 [3]
L10 to L11 -> L14 [5] lasti
L11 to L12 -> L36 [0] lasti
L12 to L13 -> L25 [3]
L14 to L16 -> L22 [7] lasti
L11 to L12 -> L40 [0] lasti
L12 to L13 -> L27 [3]
L14 to L16 -> L24 [7] lasti
L16 to L17 -> L18 [10]
L17 to L21 -> L22 [7] lasti
L21 to L23 -> L25 [3]
L24 to L25 -> L32 [3] lasti
L25 to L26 -> L30 [4] lasti
L26 to L27 -> L28 [4] lasti
L27 to L28 -> L32 [3] lasti
L28 to L30 -> L30 [4] lasti
L30 to L31 -> L32 [3] lasti
L31 to L32 -> L36 [0] lasti
L32 to L34 -> L35 [5] lasti
L34 to L36 -> L36 [0] lasti
L17 to L20 -> L24 [7] lasti
L21 to L23 -> L24 [7] lasti
L23 to L25 -> L27 [3]
L26 to L27 -> L34 [3] lasti
L27 to L28 -> L32 [4] lasti
L28 to L29 -> L30 [4] lasti
L29 to L30 -> L34 [3] lasti
L30 to L32 -> L32 [4] lasti
L32 to L33 -> L34 [3] lasti
L33 to L34 -> L40 [0] lasti
L34 to L35 -> L39 [5] lasti
L36 to L38 -> L39 [5] lasti
L38 to L40 -> L40 [0] lasti