|
21 | 21 | * objects.
|
22 | 22 | */
|
23 | 23 |
|
| 24 | +#include <stdbool.h> |
| 25 | + |
24 | 26 | #include "Python.h"
|
25 | 27 | #include "pycore_ast.h" // _PyAST_GetDocString()
|
26 | 28 | #include "pycore_compile.h" // _PyFuture_FromAST()
|
@@ -7264,25 +7266,24 @@ fold_rotations(struct instr *inst, int n)
|
7264 | 7266 | }
|
7265 | 7267 | }
|
7266 | 7268 |
|
7267 |
| - |
7268 |
| -static int |
7269 |
| -eliminate_jump_to_jump(basicblock *bb, int opcode) { |
7270 |
| - assert (bb->b_iused > 0); |
7271 |
| - struct instr *inst = &bb->b_instr[bb->b_iused-1]; |
7272 |
| - assert (is_jump(inst)); |
7273 |
| - assert (inst->i_target->b_iused > 0); |
7274 |
| - struct instr *target = &inst->i_target->b_instr[0]; |
7275 |
| - if (inst->i_target == target->i_target) { |
7276 |
| - /* Nothing to do */ |
7277 |
| - return 0; |
7278 |
| - } |
7279 |
| - int lineno = target->i_lineno; |
7280 |
| - if (add_jump_to_block(bb, opcode, lineno, target->i_target) == 0) { |
7281 |
| - return -1; |
| 7269 | +// Attempt to eliminate jumps to jumps by updating inst to jump to |
| 7270 | +// target->i_target using the provided opcode. Return whether or not the |
| 7271 | +// optimization was successful. |
| 7272 | +static bool |
| 7273 | +jump_thread(struct instr *inst, struct instr *target, int opcode) |
| 7274 | +{ |
| 7275 | + assert(is_jump(inst)); |
| 7276 | + assert(is_jump(target)); |
| 7277 | + // bpo-45773: If inst->i_target == target->i_target, then nothing actually |
| 7278 | + // changes (and we fall into an infinite loop): |
| 7279 | + if (inst->i_lineno == target->i_lineno && |
| 7280 | + inst->i_target != target->i_target) |
| 7281 | + { |
| 7282 | + inst->i_target = target->i_target; |
| 7283 | + inst->i_opcode = opcode; |
| 7284 | + return true; |
7282 | 7285 | }
|
7283 |
| - assert (bb->b_iused >= 2); |
7284 |
| - bb->b_instr[bb->b_iused-2].i_opcode = NOP; |
7285 |
| - return 0; |
| 7286 | + return false; |
7286 | 7287 | }
|
7287 | 7288 |
|
7288 | 7289 | /* Maximum size of basic block that should be copied in optimizer */
|
@@ -7399,108 +7400,78 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
|
7399 | 7400 | where y+1 is the instruction following the second test.
|
7400 | 7401 | */
|
7401 | 7402 | case JUMP_IF_FALSE_OR_POP:
|
7402 |
| - switch(target->i_opcode) { |
| 7403 | + switch (target->i_opcode) { |
7403 | 7404 | case POP_JUMP_IF_FALSE:
|
7404 |
| - if (inst->i_lineno == target->i_lineno) { |
7405 |
| - *inst = *target; |
7406 |
| - i--; |
7407 |
| - } |
| 7405 | + i -= jump_thread(inst, target, POP_JUMP_IF_FALSE); |
7408 | 7406 | break;
|
7409 | 7407 | case JUMP_ABSOLUTE:
|
7410 | 7408 | case JUMP_FORWARD:
|
7411 | 7409 | case JUMP_IF_FALSE_OR_POP:
|
7412 |
| - if (inst->i_lineno == target->i_lineno && |
7413 |
| - inst->i_target != target->i_target) { |
7414 |
| - inst->i_target = target->i_target; |
7415 |
| - i--; |
7416 |
| - } |
| 7410 | + i -= jump_thread(inst, target, JUMP_IF_FALSE_OR_POP); |
7417 | 7411 | break;
|
7418 | 7412 | case JUMP_IF_TRUE_OR_POP:
|
7419 |
| - assert (inst->i_target->b_iused == 1); |
| 7413 | + case POP_JUMP_IF_TRUE: |
7420 | 7414 | if (inst->i_lineno == target->i_lineno) {
|
| 7415 | + // We don't need to bother checking for loops here, |
| 7416 | + // since a block's b_next cannot point to itself: |
| 7417 | + assert(inst->i_target != inst->i_target->b_next); |
7421 | 7418 | inst->i_opcode = POP_JUMP_IF_FALSE;
|
7422 | 7419 | inst->i_target = inst->i_target->b_next;
|
7423 | 7420 | --i;
|
7424 | 7421 | }
|
7425 | 7422 | break;
|
7426 | 7423 | }
|
7427 | 7424 | break;
|
7428 |
| - |
7429 | 7425 | case JUMP_IF_TRUE_OR_POP:
|
7430 |
| - switch(target->i_opcode) { |
| 7426 | + switch (target->i_opcode) { |
7431 | 7427 | case POP_JUMP_IF_TRUE:
|
7432 |
| - if (inst->i_lineno == target->i_lineno) { |
7433 |
| - *inst = *target; |
7434 |
| - i--; |
7435 |
| - } |
| 7428 | + i -= jump_thread(inst, target, POP_JUMP_IF_TRUE); |
7436 | 7429 | break;
|
7437 | 7430 | case JUMP_ABSOLUTE:
|
7438 | 7431 | case JUMP_FORWARD:
|
7439 | 7432 | case JUMP_IF_TRUE_OR_POP:
|
7440 |
| - if (inst->i_lineno == target->i_lineno && |
7441 |
| - inst->i_target != target->i_target) { |
7442 |
| - inst->i_target = target->i_target; |
7443 |
| - i--; |
7444 |
| - } |
| 7433 | + i -= jump_thread(inst, target, JUMP_IF_TRUE_OR_POP); |
7445 | 7434 | break;
|
7446 | 7435 | case JUMP_IF_FALSE_OR_POP:
|
7447 |
| - assert (inst->i_target->b_iused == 1); |
| 7436 | + case POP_JUMP_IF_FALSE: |
7448 | 7437 | if (inst->i_lineno == target->i_lineno) {
|
| 7438 | + // We don't need to bother checking for loops here, |
| 7439 | + // since a block's b_next cannot point to itself: |
| 7440 | + assert(inst->i_target != inst->i_target->b_next); |
7449 | 7441 | inst->i_opcode = POP_JUMP_IF_TRUE;
|
7450 | 7442 | inst->i_target = inst->i_target->b_next;
|
7451 | 7443 | --i;
|
7452 | 7444 | }
|
7453 | 7445 | break;
|
7454 | 7446 | }
|
7455 | 7447 | break;
|
7456 |
| - |
7457 | 7448 | case POP_JUMP_IF_FALSE:
|
7458 |
| - switch(target->i_opcode) { |
| 7449 | + switch (target->i_opcode) { |
7459 | 7450 | case JUMP_ABSOLUTE:
|
7460 | 7451 | case JUMP_FORWARD:
|
7461 |
| - if (inst->i_lineno == target->i_lineno) { |
7462 |
| - inst->i_target = target->i_target; |
7463 |
| - i--; |
7464 |
| - } |
7465 |
| - break; |
| 7452 | + case JUMP_IF_FALSE_OR_POP: |
| 7453 | + i -= jump_thread(inst, target, POP_JUMP_IF_FALSE); |
7466 | 7454 | }
|
7467 | 7455 | break;
|
7468 |
| - |
7469 | 7456 | case POP_JUMP_IF_TRUE:
|
7470 |
| - switch(target->i_opcode) { |
| 7457 | + switch (target->i_opcode) { |
7471 | 7458 | case JUMP_ABSOLUTE:
|
7472 | 7459 | case JUMP_FORWARD:
|
7473 |
| - if (inst->i_lineno == target->i_lineno) { |
7474 |
| - inst->i_target = target->i_target; |
7475 |
| - i--; |
7476 |
| - } |
7477 |
| - break; |
| 7460 | + case JUMP_IF_TRUE_OR_POP: |
| 7461 | + i -= jump_thread(inst, target, POP_JUMP_IF_TRUE); |
7478 | 7462 | }
|
7479 | 7463 | break;
|
7480 |
| - |
7481 | 7464 | case JUMP_ABSOLUTE:
|
7482 | 7465 | case JUMP_FORWARD:
|
7483 |
| - assert (i == bb->b_iused-1); |
7484 |
| - switch(target->i_opcode) { |
7485 |
| - case JUMP_FORWARD: |
7486 |
| - if (eliminate_jump_to_jump(bb, inst->i_opcode)) { |
7487 |
| - goto error; |
7488 |
| - } |
7489 |
| - break; |
7490 |
| - |
| 7466 | + switch (target->i_opcode) { |
7491 | 7467 | case JUMP_ABSOLUTE:
|
7492 |
| - if (eliminate_jump_to_jump(bb, JUMP_ABSOLUTE)) { |
7493 |
| - goto error; |
7494 |
| - } |
7495 |
| - break; |
| 7468 | + case JUMP_FORWARD: |
| 7469 | + i -= jump_thread(inst, target, JUMP_ABSOLUTE); |
7496 | 7470 | }
|
7497 | 7471 | break;
|
7498 | 7472 | case FOR_ITER:
|
7499 |
| - assert (i == bb->b_iused-1); |
7500 | 7473 | if (target->i_opcode == JUMP_FORWARD) {
|
7501 |
| - if (eliminate_jump_to_jump(bb, inst->i_opcode)) { |
7502 |
| - goto error; |
7503 |
| - } |
| 7474 | + i -= jump_thread(inst, target, FOR_ITER); |
7504 | 7475 | }
|
7505 | 7476 | break;
|
7506 | 7477 | case ROT_N:
|
|
0 commit comments