bpo-42246: Don't eliminate jumps to jumps, if it will break PEP 626. (GH-23896)

This commit is contained in:
Mark Shannon 2020-12-23 11:43:10 +00:00 committed by GitHub
parent d90ff37681
commit 28b75c80dc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 4355 additions and 4253 deletions

View file

@ -1432,26 +1432,30 @@ compiler_addop_i(struct compiler *c, int opcode, Py_ssize_t oparg)
return 1;
}
static int add_jump_to_block(basicblock *b, int opcode, int lineno, basicblock *target)
{
assert(HAS_ARG(opcode));
assert(b != NULL);
assert(target != NULL);
int off = compiler_next_instr(b);
struct instr *i = &b->b_instr[off];
if (off < 0) {
return 0;
}
i->i_opcode = opcode;
i->i_target = target;
i->i_lineno = lineno;
return 1;
}
static int
compiler_addop_j(struct compiler *c, int opcode, basicblock *b)
{
struct instr *i;
int off;
if (c->c_do_not_emit_bytecode) {
return 1;
}
assert(HAS_ARG(opcode));
assert(b != NULL);
off = compiler_next_instr(c->u->u_curblock);
if (off < 0)
return 0;
i = &c->u->u_curblock->b_instr[off];
i->i_opcode = opcode;
i->i_target = b;
i->i_lineno = c->u->u_lineno;
return 1;
return add_jump_to_block(c->u->u_curblock, opcode, c->u->u_lineno, b);
}
/* NEXT_BLOCK() creates an implicit jump from the current block
@ -6067,6 +6071,27 @@ fold_tuple_on_constants(struct instr *inst,
return 0;
}
static int
eliminate_jump_to_jump(basicblock *bb, int opcode) {
assert (bb->b_iused > 0);
struct instr *inst = &bb->b_instr[bb->b_iused-1];
assert (is_jump(inst));
assert (inst->i_target->b_iused > 0);
struct instr *target = &inst->i_target->b_instr[0];
if (inst->i_target == target->i_target) {
/* Nothing to do */
return 0;
}
int lineno = target->i_lineno;
if (add_jump_to_block(bb, opcode, lineno, target->i_target) == 0) {
return -1;
}
assert (bb->b_iused >= 2);
bb->b_instr[bb->b_iused-2].i_opcode = NOP;
return 0;
}
/* Maximum size of basic block that should be copied in optimizer */
#define MAX_COPY_SIZE 4
@ -6183,22 +6208,27 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
case JUMP_IF_FALSE_OR_POP:
switch(target->i_opcode) {
case POP_JUMP_IF_FALSE:
*inst = *target;
--i;
if (inst->i_lineno == target->i_lineno) {
*inst = *target;
i--;
}
break;
case JUMP_ABSOLUTE:
case JUMP_FORWARD:
case JUMP_IF_FALSE_OR_POP:
if (inst->i_target != target->i_target) {
if (inst->i_lineno == target->i_lineno &&
inst->i_target != target->i_target) {
inst->i_target = target->i_target;
--i;
i--;
}
break;
case JUMP_IF_TRUE_OR_POP:
assert (inst->i_target->b_iused == 1);
inst->i_opcode = POP_JUMP_IF_FALSE;
inst->i_target = inst->i_target->b_next;
--i;
if (inst->i_lineno == target->i_lineno) {
inst->i_opcode = POP_JUMP_IF_FALSE;
inst->i_target = inst->i_target->b_next;
--i;
}
break;
}
break;
@ -6206,22 +6236,27 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
case JUMP_IF_TRUE_OR_POP:
switch(target->i_opcode) {
case POP_JUMP_IF_TRUE:
*inst = *target;
--i;
if (inst->i_lineno == target->i_lineno) {
*inst = *target;
i--;
}
break;
case JUMP_ABSOLUTE:
case JUMP_FORWARD:
case JUMP_IF_TRUE_OR_POP:
if (inst->i_target != target->i_target) {
if (inst->i_lineno == target->i_lineno &&
inst->i_target != target->i_target) {
inst->i_target = target->i_target;
--i;
i--;
}
break;
case JUMP_IF_FALSE_OR_POP:
assert (inst->i_target->b_iused == 1);
inst->i_opcode = POP_JUMP_IF_TRUE;
inst->i_target = inst->i_target->b_next;
--i;
if (inst->i_lineno == target->i_lineno) {
inst->i_opcode = POP_JUMP_IF_TRUE;
inst->i_target = inst->i_target->b_next;
--i;
}
break;
}
break;
@ -6230,9 +6265,9 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
switch(target->i_opcode) {
case JUMP_ABSOLUTE:
case JUMP_FORWARD:
if (inst->i_target != target->i_target) {
if (inst->i_lineno == target->i_lineno) {
inst->i_target = target->i_target;
--i;
i--;
}
break;
}
@ -6242,9 +6277,9 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
switch(target->i_opcode) {
case JUMP_ABSOLUTE:
case JUMP_FORWARD:
if (inst->i_target != target->i_target) {
if (inst->i_lineno == target->i_lineno) {
inst->i_target = target->i_target;
--i;
i--;
}
break;
}
@ -6255,32 +6290,30 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
assert (i == bb->b_iused-1);
switch(target->i_opcode) {
case JUMP_FORWARD:
if (inst->i_target != target->i_target) {
inst->i_target = target->i_target;
// --i;
if (eliminate_jump_to_jump(bb, inst->i_opcode)) {
goto error;
}
break;
case JUMP_ABSOLUTE:
if (inst->i_target != target->i_target) {
inst->i_target = target->i_target;
inst->i_opcode = target->i_opcode;
--i;
if (eliminate_jump_to_jump(bb, JUMP_ABSOLUTE)) {
goto error;
}
break;
}
if (inst->i_target->b_exit && inst->i_target->b_iused <= MAX_COPY_SIZE) {
basicblock *to_copy = inst->i_target;
inst->i_opcode = NOP;
for (i = 0; i < to_copy->b_iused; i++) {
int index = compiler_next_instr(bb);
if (index < 0) {
return -1;
default:
if (inst->i_target->b_exit && inst->i_target->b_iused <= MAX_COPY_SIZE) {
basicblock *to_copy = inst->i_target;
inst->i_opcode = NOP;
for (i = 0; i < to_copy->b_iused; i++) {
int index = compiler_next_instr(bb);
if (index < 0) {
return -1;
}
bb->b_instr[index] = to_copy->b_instr[i];
}
bb->b_exit = 1;
}
bb->b_instr[index] = to_copy->b_instr[i];
}
bb->b_exit = 1;
}
break;
}
}
return 0;