summaryrefslogtreecommitdiffstats
path: root/Python/compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/compile.c')
-rw-r--r--Python/compile.c115
1 files changed, 43 insertions, 72 deletions
diff --git a/Python/compile.c b/Python/compile.c
index 9086103..3eb34d8 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -21,6 +21,8 @@
* objects.
*/
+#include <stdbool.h>
+
#include "Python.h"
#include "pycore_ast.h" // _PyAST_GetDocString()
#include "pycore_compile.h" // _PyFuture_FromAST()
@@ -7264,25 +7266,24 @@ fold_rotations(struct instr *inst, int n)
}
}
-
-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;
+// Attempt to eliminate jumps to jumps by updating inst to jump to
+// target->i_target using the provided opcode. Return whether or not the
+// optimization was successful.
+static bool
+jump_thread(struct instr *inst, struct instr *target, int opcode)
+{
+ assert(is_jump(inst));
+ assert(is_jump(target));
+ // bpo-45773: If inst->i_target == target->i_target, then nothing actually
+ // changes (and we fall into an infinite loop):
+ if (inst->i_lineno == target->i_lineno &&
+ inst->i_target != target->i_target)
+ {
+ inst->i_target = target->i_target;
+ inst->i_opcode = opcode;
+ return true;
}
- assert (bb->b_iused >= 2);
- bb->b_instr[bb->b_iused-2].i_opcode = NOP;
- return 0;
+ return false;
}
/* Maximum size of basic block that should be copied in optimizer */
@@ -7399,25 +7400,21 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
where y+1 is the instruction following the second test.
*/
case JUMP_IF_FALSE_OR_POP:
- switch(target->i_opcode) {
+ switch (target->i_opcode) {
case POP_JUMP_IF_FALSE:
- if (inst->i_lineno == target->i_lineno) {
- *inst = *target;
- i--;
- }
+ i -= jump_thread(inst, target, POP_JUMP_IF_FALSE);
break;
case JUMP_ABSOLUTE:
case JUMP_FORWARD:
case JUMP_IF_FALSE_OR_POP:
- if (inst->i_lineno == target->i_lineno &&
- inst->i_target != target->i_target) {
- inst->i_target = target->i_target;
- i--;
- }
+ i -= jump_thread(inst, target, JUMP_IF_FALSE_OR_POP);
break;
case JUMP_IF_TRUE_OR_POP:
- assert (inst->i_target->b_iused == 1);
+ case POP_JUMP_IF_TRUE:
if (inst->i_lineno == target->i_lineno) {
+ // We don't need to bother checking for loops here,
+ // since a block's b_next cannot point to itself:
+ assert(inst->i_target != inst->i_target->b_next);
inst->i_opcode = POP_JUMP_IF_FALSE;
inst->i_target = inst->i_target->b_next;
--i;
@@ -7425,27 +7422,22 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
break;
}
break;
-
case JUMP_IF_TRUE_OR_POP:
- switch(target->i_opcode) {
+ switch (target->i_opcode) {
case POP_JUMP_IF_TRUE:
- if (inst->i_lineno == target->i_lineno) {
- *inst = *target;
- i--;
- }
+ i -= jump_thread(inst, target, POP_JUMP_IF_TRUE);
break;
case JUMP_ABSOLUTE:
case JUMP_FORWARD:
case JUMP_IF_TRUE_OR_POP:
- if (inst->i_lineno == target->i_lineno &&
- inst->i_target != target->i_target) {
- inst->i_target = target->i_target;
- i--;
- }
+ i -= jump_thread(inst, target, JUMP_IF_TRUE_OR_POP);
break;
case JUMP_IF_FALSE_OR_POP:
- assert (inst->i_target->b_iused == 1);
+ case POP_JUMP_IF_FALSE:
if (inst->i_lineno == target->i_lineno) {
+ // We don't need to bother checking for loops here,
+ // since a block's b_next cannot point to itself:
+ assert(inst->i_target != inst->i_target->b_next);
inst->i_opcode = POP_JUMP_IF_TRUE;
inst->i_target = inst->i_target->b_next;
--i;
@@ -7453,54 +7445,33 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
break;
}
break;
-
case POP_JUMP_IF_FALSE:
- switch(target->i_opcode) {
+ switch (target->i_opcode) {
case JUMP_ABSOLUTE:
case JUMP_FORWARD:
- if (inst->i_lineno == target->i_lineno) {
- inst->i_target = target->i_target;
- i--;
- }
- break;
+ case JUMP_IF_FALSE_OR_POP:
+ i -= jump_thread(inst, target, POP_JUMP_IF_FALSE);
}
break;
-
case POP_JUMP_IF_TRUE:
- switch(target->i_opcode) {
+ switch (target->i_opcode) {
case JUMP_ABSOLUTE:
case JUMP_FORWARD:
- if (inst->i_lineno == target->i_lineno) {
- inst->i_target = target->i_target;
- i--;
- }
- break;
+ case JUMP_IF_TRUE_OR_POP:
+ i -= jump_thread(inst, target, POP_JUMP_IF_TRUE);
}
break;
-
case JUMP_ABSOLUTE:
case JUMP_FORWARD:
- assert (i == bb->b_iused-1);
- switch(target->i_opcode) {
- case JUMP_FORWARD:
- if (eliminate_jump_to_jump(bb, inst->i_opcode)) {
- goto error;
- }
- break;
-
+ switch (target->i_opcode) {
case JUMP_ABSOLUTE:
- if (eliminate_jump_to_jump(bb, JUMP_ABSOLUTE)) {
- goto error;
- }
- break;
+ case JUMP_FORWARD:
+ i -= jump_thread(inst, target, JUMP_ABSOLUTE);
}
break;
case FOR_ITER:
- assert (i == bb->b_iused-1);
if (target->i_opcode == JUMP_FORWARD) {
- if (eliminate_jump_to_jump(bb, inst->i_opcode)) {
- goto error;
- }
+ i -= jump_thread(inst, target, FOR_ITER);
}
break;
case ROT_N: