Skip to content

Commit 28b75c8

Browse files
authored
bpo-42246: Don't eliminate jumps to jumps, if it will break PEP 626. (GH-23896)
1 parent d90ff37 commit 28b75c8

File tree

7 files changed

+4341
-4239
lines changed

7 files changed

+4341
-4239
lines changed

Lib/test/test_dis.py

Lines changed: 85 additions & 84 deletions
Large diffs are not rendered by default.

Lib/test/test_sys_settrace.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,70 @@ def func():
810810
(6, 'line'),
811811
(6, 'return')])
812812

813+
def test_break_to_continue1(self):
814+
815+
def func():
816+
TRUE = 1
817+
x = [1]
818+
while x:
819+
x.pop()
820+
while TRUE:
821+
break
822+
continue
823+
824+
self.run_and_compare(func,
825+
[(0, 'call'),
826+
(1, 'line'),
827+
(2, 'line'),
828+
(3, 'line'),
829+
(4, 'line'),
830+
(5, 'line'),
831+
(6, 'line'),
832+
(7, 'line'),
833+
(3, 'line'),
834+
(3, 'return')])
835+
836+
def test_break_to_continue2(self):
837+
838+
def func():
839+
TRUE = 1
840+
x = [1]
841+
while x:
842+
x.pop()
843+
while TRUE:
844+
break
845+
else:
846+
continue
847+
848+
self.run_and_compare(func,
849+
[(0, 'call'),
850+
(1, 'line'),
851+
(2, 'line'),
852+
(3, 'line'),
853+
(4, 'line'),
854+
(5, 'line'),
855+
(6, 'line'),
856+
(3, 'line'),
857+
(3, 'return')])
858+
859+
def test_break_to_break(self):
860+
861+
def func():
862+
TRUE = 1
863+
while TRUE:
864+
while TRUE:
865+
break
866+
break
867+
868+
self.run_and_compare(func,
869+
[(0, 'call'),
870+
(1, 'line'),
871+
(2, 'line'),
872+
(3, 'line'),
873+
(4, 'line'),
874+
(5, 'line'),
875+
(5, 'return')])
876+
813877

814878
class SkipLineEventsTraceTestCase(TraceTestCase):
815879
"""Repeat the trace tests, but with per-line events skipped"""
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Jumps to jumps are not eliminated when it would break PEP 626.

Python/compile.c

Lines changed: 84 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,28 +1432,32 @@ compiler_addop_i(struct compiler *c, int opcode, Py_ssize_t oparg)
14321432
return 1;
14331433
}
14341434

1435-
static int
1436-
compiler_addop_j(struct compiler *c, int opcode, basicblock *b)
1435+
static int add_jump_to_block(basicblock *b, int opcode, int lineno, basicblock *target)
14371436
{
1438-
struct instr *i;
1439-
int off;
1440-
1441-
if (c->c_do_not_emit_bytecode) {
1442-
return 1;
1443-
}
1444-
14451437
assert(HAS_ARG(opcode));
14461438
assert(b != NULL);
1447-
off = compiler_next_instr(c->u->u_curblock);
1448-
if (off < 0)
1439+
assert(target != NULL);
1440+
1441+
int off = compiler_next_instr(b);
1442+
struct instr *i = &b->b_instr[off];
1443+
if (off < 0) {
14491444
return 0;
1450-
i = &c->u->u_curblock->b_instr[off];
1445+
}
14511446
i->i_opcode = opcode;
1452-
i->i_target = b;
1453-
i->i_lineno = c->u->u_lineno;
1447+
i->i_target = target;
1448+
i->i_lineno = lineno;
14541449
return 1;
14551450
}
14561451

1452+
static int
1453+
compiler_addop_j(struct compiler *c, int opcode, basicblock *b)
1454+
{
1455+
if (c->c_do_not_emit_bytecode) {
1456+
return 1;
1457+
}
1458+
return add_jump_to_block(c->u->u_curblock, opcode, c->u->u_lineno, b);
1459+
}
1460+
14571461
/* NEXT_BLOCK() creates an implicit jump from the current block
14581462
to the new block.
14591463
@@ -6067,6 +6071,27 @@ fold_tuple_on_constants(struct instr *inst,
60676071
return 0;
60686072
}
60696073

6074+
6075+
static int
6076+
eliminate_jump_to_jump(basicblock *bb, int opcode) {
6077+
assert (bb->b_iused > 0);
6078+
struct instr *inst = &bb->b_instr[bb->b_iused-1];
6079+
assert (is_jump(inst));
6080+
assert (inst->i_target->b_iused > 0);
6081+
struct instr *target = &inst->i_target->b_instr[0];
6082+
if (inst->i_target == target->i_target) {
6083+
/* Nothing to do */
6084+
return 0;
6085+
}
6086+
int lineno = target->i_lineno;
6087+
if (add_jump_to_block(bb, opcode, lineno, target->i_target) == 0) {
6088+
return -1;
6089+
}
6090+
assert (bb->b_iused >= 2);
6091+
bb->b_instr[bb->b_iused-2].i_opcode = NOP;
6092+
return 0;
6093+
}
6094+
60706095
/* Maximum size of basic block that should be copied in optimizer */
60716096
#define MAX_COPY_SIZE 4
60726097

@@ -6183,45 +6208,55 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
61836208
case JUMP_IF_FALSE_OR_POP:
61846209
switch(target->i_opcode) {
61856210
case POP_JUMP_IF_FALSE:
6186-
*inst = *target;
6187-
--i;
6211+
if (inst->i_lineno == target->i_lineno) {
6212+
*inst = *target;
6213+
i--;
6214+
}
61886215
break;
61896216
case JUMP_ABSOLUTE:
61906217
case JUMP_FORWARD:
61916218
case JUMP_IF_FALSE_OR_POP:
6192-
if (inst->i_target != target->i_target) {
6219+
if (inst->i_lineno == target->i_lineno &&
6220+
inst->i_target != target->i_target) {
61936221
inst->i_target = target->i_target;
6194-
--i;
6222+
i--;
61956223
}
61966224
break;
61976225
case JUMP_IF_TRUE_OR_POP:
61986226
assert (inst->i_target->b_iused == 1);
6199-
inst->i_opcode = POP_JUMP_IF_FALSE;
6200-
inst->i_target = inst->i_target->b_next;
6201-
--i;
6227+
if (inst->i_lineno == target->i_lineno) {
6228+
inst->i_opcode = POP_JUMP_IF_FALSE;
6229+
inst->i_target = inst->i_target->b_next;
6230+
--i;
6231+
}
62026232
break;
62036233
}
62046234
break;
62056235

62066236
case JUMP_IF_TRUE_OR_POP:
62076237
switch(target->i_opcode) {
62086238
case POP_JUMP_IF_TRUE:
6209-
*inst = *target;
6210-
--i;
6239+
if (inst->i_lineno == target->i_lineno) {
6240+
*inst = *target;
6241+
i--;
6242+
}
62116243
break;
62126244
case JUMP_ABSOLUTE:
62136245
case JUMP_FORWARD:
62146246
case JUMP_IF_TRUE_OR_POP:
6215-
if (inst->i_target != target->i_target) {
6247+
if (inst->i_lineno == target->i_lineno &&
6248+
inst->i_target != target->i_target) {
62166249
inst->i_target = target->i_target;
6217-
--i;
6250+
i--;
62186251
}
62196252
break;
62206253
case JUMP_IF_FALSE_OR_POP:
62216254
assert (inst->i_target->b_iused == 1);
6222-
inst->i_opcode = POP_JUMP_IF_TRUE;
6223-
inst->i_target = inst->i_target->b_next;
6224-
--i;
6255+
if (inst->i_lineno == target->i_lineno) {
6256+
inst->i_opcode = POP_JUMP_IF_TRUE;
6257+
inst->i_target = inst->i_target->b_next;
6258+
--i;
6259+
}
62256260
break;
62266261
}
62276262
break;
@@ -6230,9 +6265,9 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
62306265
switch(target->i_opcode) {
62316266
case JUMP_ABSOLUTE:
62326267
case JUMP_FORWARD:
6233-
if (inst->i_target != target->i_target) {
6268+
if (inst->i_lineno == target->i_lineno) {
62346269
inst->i_target = target->i_target;
6235-
--i;
6270+
i--;
62366271
}
62376272
break;
62386273
}
@@ -6242,9 +6277,9 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
62426277
switch(target->i_opcode) {
62436278
case JUMP_ABSOLUTE:
62446279
case JUMP_FORWARD:
6245-
if (inst->i_target != target->i_target) {
6280+
if (inst->i_lineno == target->i_lineno) {
62466281
inst->i_target = target->i_target;
6247-
--i;
6282+
i--;
62486283
}
62496284
break;
62506285
}
@@ -6255,32 +6290,30 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
62556290
assert (i == bb->b_iused-1);
62566291
switch(target->i_opcode) {
62576292
case JUMP_FORWARD:
6258-
if (inst->i_target != target->i_target) {
6259-
inst->i_target = target->i_target;
6260-
// --i;
6293+
if (eliminate_jump_to_jump(bb, inst->i_opcode)) {
6294+
goto error;
62616295
}
62626296
break;
6297+
62636298
case JUMP_ABSOLUTE:
6264-
if (inst->i_target != target->i_target) {
6265-
inst->i_target = target->i_target;
6266-
inst->i_opcode = target->i_opcode;
6267-
--i;
6299+
if (eliminate_jump_to_jump(bb, JUMP_ABSOLUTE)) {
6300+
goto error;
62686301
}
62696302
break;
6270-
}
6271-
if (inst->i_target->b_exit && inst->i_target->b_iused <= MAX_COPY_SIZE) {
6272-
basicblock *to_copy = inst->i_target;
6273-
inst->i_opcode = NOP;
6274-
for (i = 0; i < to_copy->b_iused; i++) {
6275-
int index = compiler_next_instr(bb);
6276-
if (index < 0) {
6277-
return -1;
6303+
default:
6304+
if (inst->i_target->b_exit && inst->i_target->b_iused <= MAX_COPY_SIZE) {
6305+
basicblock *to_copy = inst->i_target;
6306+
inst->i_opcode = NOP;
6307+
for (i = 0; i < to_copy->b_iused; i++) {
6308+
int index = compiler_next_instr(bb);
6309+
if (index < 0) {
6310+
return -1;
6311+
}
6312+
bb->b_instr[index] = to_copy->b_instr[i];
6313+
}
6314+
bb->b_exit = 1;
62786315
}
6279-
bb->b_instr[index] = to_copy->b_instr[i];
6280-
}
6281-
bb->b_exit = 1;
62826316
}
6283-
break;
62846317
}
62856318
}
62866319
return 0;

0 commit comments

Comments
 (0)