>> FOR_ITER 2 (to 40)
STORE_FAST 0 (res)
-%3d JUMP_ABSOLUTE 17 (to 34)
+%3d JUMP_BACKWARD 3 (to 34)
%3d >> LOAD_CONST 0 (None)
RETURN_VALUE
BINARY_OP 13 (+=)
STORE_NAME 0 (x)
- 2 JUMP_ABSOLUTE 4 (to 8)
+ 2 JUMP_BACKWARD 6 (to 8)
"""
dis_traceback = """\
LOAD_FAST 1 (z)
BINARY_OP 0 (+)
LIST_APPEND 2
- JUMP_ABSOLUTE 4 (to 8)
+ JUMP_BACKWARD 8 (to 8)
>> RETURN_VALUE
""" % (dis_nested_1,
__file__,
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=68, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=70, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=40, argval=80, argrepr='to 80', offset=76, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=16, argval=32, argrepr='to 32', offset=78, starts_line=6, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=140, arg=24, argval=32, argrepr='to 32', offset=78, starts_line=6, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=80, starts_line=7, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=82, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=84, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=48, argval=96, argrepr='to 96', offset=90, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=92, starts_line=8, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=128, argrepr='to 128', offset=94, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=16, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=140, arg=33, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, starts_line=10, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=110, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=3, argval=6, argrepr='6', offset=174, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=4, argval='>', argrepr='>', offset=176, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=93, argval=186, argrepr='to 186', offset=182, starts_line=None, is_jump_target=False, positions=None),
- Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=64, argval=128, argrepr='to 128', offset=184, starts_line=15, is_jump_target=False, positions=None),
+ Instruction(opname='JUMP_BACKWARD', opcode=140, arg=29, argval=128, argrepr='to 128', offset=184, starts_line=15, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=186, starts_line=16, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=188, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COMPARE_OP', opcode=107, arg=0, argval='<', argrepr='<', offset=190, starts_line=None, is_jump_target=False, positions=None),
#define SETUP_CLEANUP 254
#define SETUP_WITH 253
#define POP_BLOCK 252
+#define JUMP 251
#define IS_TOP_LEVEL_AWAIT(c) ( \
(c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \
static inline int
is_jump(struct instr *i)
{
- return i->i_opcode >= SETUP_WITH || is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode);
+ return i->i_opcode >= SETUP_WITH ||
+ i->i_opcode == JUMP ||
+ is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode);
}
static int
/* Jumps */
case JUMP_FORWARD:
- case JUMP_ABSOLUTE:
+ case JUMP_BACKWARD:
+ case JUMP:
case JUMP_NO_INTERRUPT:
return 0;
return 0;
if (!compiler_jump_if(c, e->v.IfExp.body, next, cond))
return 0;
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end);
+ ADDOP_JUMP_NOLINE(c, JUMP, end);
compiler_use_next_block(c, next2);
if (!compiler_jump_if(c, e->v.IfExp.orelse, next, cond))
return 0;
basicblock *end = compiler_new_block(c);
if (end == NULL)
return 0;
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end);
+ ADDOP_JUMP_NOLINE(c, JUMP, end);
compiler_use_next_block(c, cleanup);
ADDOP(c, POP_TOP);
if (!cond) {
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, next);
+ ADDOP_JUMP_NOLINE(c, JUMP, next);
}
compiler_use_next_block(c, end);
return 1;
if (!compiler_jump_if(c, e->v.IfExp.test, next, 0))
return 0;
VISIT(c, expr, e->v.IfExp.body);
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end);
+ ADDOP_JUMP_NOLINE(c, JUMP, end);
compiler_use_next_block(c, next);
VISIT(c, expr, e->v.IfExp.orelse);
compiler_use_next_block(c, end);
}
VISIT_SEQ(c, stmt, s->v.If.body);
if (asdl_seq_LEN(s->v.If.orelse)) {
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end);
+ ADDOP_JUMP_NOLINE(c, JUMP, end);
compiler_use_next_block(c, next);
VISIT_SEQ(c, stmt, s->v.If.orelse);
}
VISIT_SEQ(c, stmt, s->v.For.body);
/* Mark jump as artificial */
UNSET_LOC(c);
- ADDOP_JUMP(c, JUMP_ABSOLUTE, start);
+ ADDOP_JUMP(c, JUMP, start);
compiler_use_next_block(c, cleanup);
compiler_pop_fblock(c, FOR_LOOP, start);
/* Success block for __anext__ */
VISIT(c, expr, s->v.AsyncFor.target);
VISIT_SEQ(c, stmt, s->v.AsyncFor.body);
- ADDOP_JUMP(c, JUMP_ABSOLUTE, start);
+ ADDOP_JUMP(c, JUMP, start);
compiler_pop_fblock(c, FOR_LOOP, start);
if (!compiler_unwind_fblock(c, loop, 0)) {
return 0;
}
- ADDOP_JUMP(c, JUMP_ABSOLUTE, loop->fb_exit);
+ ADDOP_JUMP(c, JUMP, loop->fb_exit);
return 1;
}
if (loop == NULL) {
return compiler_error(c, "'continue' not properly in loop");
}
- ADDOP_JUMP(c, JUMP_ABSOLUTE, loop->fb_block);
+ ADDOP_JUMP(c, JUMP, loop->fb_block);
return 1;
}
ADDOP_NOLINE(c, POP_BLOCK);
compiler_pop_fblock(c, FINALLY_TRY, body);
VISIT_SEQ(c, stmt, s->v.Try.finalbody);
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, exit);
+ ADDOP_JUMP_NOLINE(c, JUMP, exit);
/* `finally` block */
compiler_use_next_block(c, end);
ADDOP_NOLINE(c, POP_BLOCK);
compiler_pop_fblock(c, FINALLY_TRY, body);
VISIT_SEQ(c, stmt, s->v.TryStar.finalbody);
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, exit);
+ ADDOP_JUMP_NOLINE(c, JUMP, exit);
/* `finally` block */
compiler_use_next_block(c, end);
[] SETUP_FINALLY L1
[] <code for S>
[] POP_BLOCK
- [] JUMP_FORWARD L0
+ [] JUMP L0
[exc] L1: <evaluate E1> )
[exc, E1] JUMP_IF_NOT_EXC_MATCH L2 ) only if E1
[exc] <assign to V1> (or POP if no V1)
[] <code for S1>
- JUMP_FORWARD L0
+ JUMP L0
[exc] L2: <evaluate E2>
.............................etc.......................
if (s->v.Try.orelse && asdl_seq_LEN(s->v.Try.orelse)) {
VISIT_SEQ(c, stmt, s->v.Try.orelse);
}
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end);
+ ADDOP_JUMP_NOLINE(c, JUMP, end);
n = asdl_seq_LEN(s->v.Try.handlers);
compiler_use_next_block(c, except);
ADDOP_LOAD_CONST(c, Py_None);
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
compiler_nameop(c, handler->v.ExceptHandler.name, Del);
- ADDOP_JUMP(c, JUMP_FORWARD, end);
+ ADDOP_JUMP(c, JUMP, end);
/* except: */
compiler_use_next_block(c, cleanup_end);
UNSET_LOC(c);
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
- ADDOP_JUMP(c, JUMP_FORWARD, end);
+ ADDOP_JUMP(c, JUMP, end);
}
compiler_use_next_block(c, except);
}
[] SETUP_FINALLY L1
[] <code for S>
[] POP_BLOCK
- [] JUMP_FORWARD L0
+ [] JUMP L0
[exc] L1: COPY 1 ) save copy of the original exception
[orig, exc] BUILD_LIST ) list for raised/reraised excs ("result")
[orig, res, rest] SETUP_FINALLY R1
[orig, res, rest] <code for S1>
- [orig, res, rest] JUMP_FORWARD L2
+ [orig, res, rest] JUMP L2
[orig, res, rest, i, v] R1: LIST_APPEND 3 ) exc raised in except* body - add to res
[orig, res, rest, i] POP
[exc] COPY 1
[exc, exc] POP_JUMP_IF_NOT_NONE RER
[exc] POP_TOP
- [] JUMP_FORWARD L0
+ [] JUMP L0
[exc] RER: SWAP 2
[exc, prev_exc_info] POP_EXCEPT
VISIT_SEQ(c, stmt, s->v.TryStar.body);
compiler_pop_fblock(c, TRY_EXCEPT, body);
ADDOP_NOLINE(c, POP_BLOCK);
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, orelse);
+ ADDOP_JUMP_NOLINE(c, JUMP, orelse);
Py_ssize_t n = asdl_seq_LEN(s->v.TryStar.handlers);
compiler_use_next_block(c, except);
compiler_nameop(c, handler->v.ExceptHandler.name, Store);
compiler_nameop(c, handler->v.ExceptHandler.name, Del);
}
- ADDOP_JUMP(c, JUMP_FORWARD, except);
+ ADDOP_JUMP(c, JUMP, except);
/* except: */
compiler_use_next_block(c, cleanup_end);
ADDOP_I(c, LIST_APPEND, 3); // exc
ADDOP(c, POP_TOP); // lasti
- ADDOP_JUMP(c, JUMP_ABSOLUTE, except);
+ ADDOP_JUMP(c, JUMP, except);
compiler_use_next_block(c, except);
if (i == n - 1) {
/* Add exc to the list (if not None it's the unhandled part of the EG) */
ADDOP_I(c, LIST_APPEND, 1);
- ADDOP_JUMP(c, JUMP_FORWARD, reraise_star);
+ ADDOP_JUMP(c, JUMP, reraise_star);
}
}
/* Mark as artificial */
ADDOP(c, POP_TOP);
ADDOP(c, POP_BLOCK);
ADDOP(c, POP_EXCEPT);
- ADDOP_JUMP(c, JUMP_FORWARD, end);
+ ADDOP_JUMP(c, JUMP, end);
compiler_use_next_block(c, reraise);
ADDOP(c, POP_BLOCK);
ADDOP_I(c, SWAP, 2);
basicblock *end = compiler_new_block(c);
if (end == NULL)
return 0;
- ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end);
+ ADDOP_JUMP_NOLINE(c, JUMP, end);
compiler_use_next_block(c, cleanup);
ADDOP_I(c, SWAP, 2);
ADDOP(c, POP_TOP);
}
compiler_use_next_block(c, if_cleanup);
if (start) {
- ADDOP_JUMP(c, JUMP_ABSOLUTE, start);
+ ADDOP_JUMP(c, JUMP, start);
compiler_use_next_block(c, anchor);
}
}
}
compiler_use_next_block(c, if_cleanup);
- ADDOP_JUMP(c, JUMP_ABSOLUTE, start);
+ ADDOP_JUMP(c, JUMP, start);
compiler_pop_fblock(c, ASYNC_COMPREHENSION_GENERATOR, start);
ADDOP(c, POP_TOP);
- ADDOP_JUMP(c, JUMP_ABSOLUTE, exit);
+ ADDOP_JUMP(c, JUMP, exit);
/* For exceptional outcome: */
compiler_use_next_block(c, final);
<code for BLOCK>
LOAD_CONST (None, None, None)
CALL_FUNCTION_EX 0
- JUMP_FORWARD EXIT
+ JUMP EXIT
E: WITH_EXCEPT_START (calls EXPR.__exit__)
POP_JUMP_IF_TRUE T:
RERAISE
if (!compiler_call_exit_with_nones(c))
return 0;
ADDOP(c, POP_TOP);
- ADDOP_JUMP(c, JUMP_FORWARD, exit);
+ ADDOP_JUMP(c, JUMP, exit);
/* For exceptional outcome: */
compiler_use_next_block(c, final);
}
}
assert(control);
- if (!compiler_addop_j(c, JUMP_FORWARD, end) ||
+ if (!compiler_addop_j(c, JUMP, end) ||
!emit_and_reset_fail_pop(c, pc))
{
goto error;
// Need to NULL this for the PyObject_Free call in the error block.
old_pc.fail_pop = NULL;
// No match. Pop the remaining copy of the subject and fail:
- if (!compiler_addop(c, POP_TOP) || !jump_to_fail_pop(c, pc, JUMP_FORWARD)) {
+ if (!compiler_addop(c, POP_TOP) || !jump_to_fail_pop(c, pc, JUMP)) {
goto error;
}
compiler_use_next_block(c, end);
ADDOP(c, POP_TOP);
}
VISIT_SEQ(c, stmt, m->body);
- ADDOP_JUMP(c, JUMP_FORWARD, end);
+ ADDOP_JUMP(c, JUMP, end);
// If the pattern fails to match, we want the line number of the
// cleanup to be associated with the failed pattern, not the last line
// of the body
stackdepth_push(&sp, instr->i_target, target_depth);
}
depth = new_depth;
- if (instr->i_opcode == JUMP_ABSOLUTE ||
- instr->i_opcode == JUMP_NO_INTERRUPT ||
- instr->i_opcode == JUMP_FORWARD ||
+ assert(instr->i_opcode != JUMP_FORWARD);
+ assert(instr->i_opcode != JUMP_BACKWARD);
+ if (instr->i_opcode == JUMP_NO_INTERRUPT ||
+ instr->i_opcode == JUMP ||
instr->i_opcode == RETURN_VALUE ||
instr->i_opcode == RAISE_VARARGS ||
instr->i_opcode == RERAISE)
continue;
}
struct instr *last = &b->b_instr[b->b_iused-1];
- if (last->i_opcode == JUMP_ABSOLUTE) {
+ assert(last->i_opcode != JUMP_FORWARD);
+ assert(last->i_opcode != JUMP_BACKWARD);
+ if (last->i_opcode == JUMP) {
if (last->i_target->b_visited == 0) {
last->i_opcode = JUMP_FORWARD;
}
- }
- if (last->i_opcode == JUMP_FORWARD) {
- if (last->i_target->b_visited == 1) {
- last->i_opcode = JUMP_ABSOLUTE;
+ else {
+ last->i_opcode = JUMP_BACKWARD;
}
}
}
if (is_jump(instr)) {
instr->i_oparg = instr->i_target->b_offset;
if (is_relative_jump(instr)) {
- instr->i_oparg -= bsize;
+ if (instr->i_oparg < bsize) {
+ assert(instr->i_opcode == JUMP_BACKWARD);
+ instr->i_oparg = bsize - instr->i_oparg;
+ }
+ else {
+ assert(instr->i_opcode != JUMP_BACKWARD);
+ instr->i_oparg -= bsize;
+ }
}
if (instr_size(instr) != isize) {
extended_arg_recompile = 1;
inst->i_target = inst->i_target->b_next;
}
target = &inst->i_target->b_instr[0];
+ assert(target->i_opcode != JUMP_FORWARD);
+ assert(target->i_opcode != JUMP_BACKWARD);
}
else {
target = &nop;
}
+ assert(inst->i_opcode != JUMP_FORWARD);
+ assert(inst->i_opcode != JUMP_BACKWARD);
switch (inst->i_opcode) {
/* Remove LOAD_CONST const; conditional jump */
case LOAD_CONST:
inst->i_opcode = NOP;
jump_if_true = nextop == POP_JUMP_IF_TRUE;
if (is_true == jump_if_true) {
- bb->b_instr[i+1].i_opcode = JUMP_ABSOLUTE;
+ bb->b_instr[i+1].i_opcode = JUMP;
bb->b_nofallthrough = 1;
}
else {
}
jump_if_true = nextop == JUMP_IF_TRUE_OR_POP;
if (is_true == jump_if_true) {
- bb->b_instr[i+1].i_opcode = JUMP_ABSOLUTE;
+ bb->b_instr[i+1].i_opcode = JUMP;
bb->b_nofallthrough = 1;
}
else {
case POP_JUMP_IF_FALSE:
i -= jump_thread(inst, target, POP_JUMP_IF_FALSE);
break;
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
case JUMP_IF_FALSE_OR_POP:
i -= jump_thread(inst, target, JUMP_IF_FALSE_OR_POP);
break;
case POP_JUMP_IF_TRUE:
i -= jump_thread(inst, target, POP_JUMP_IF_TRUE);
break;
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
case JUMP_IF_TRUE_OR_POP:
i -= jump_thread(inst, target, JUMP_IF_TRUE_OR_POP);
break;
case POP_JUMP_IF_NOT_NONE:
case POP_JUMP_IF_NONE:
switch (target->i_opcode) {
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
i -= jump_thread(inst, target, inst->i_opcode);
}
break;
case POP_JUMP_IF_FALSE:
switch (target->i_opcode) {
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
i -= jump_thread(inst, target, POP_JUMP_IF_FALSE);
}
break;
case POP_JUMP_IF_TRUE:
switch (target->i_opcode) {
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
i -= jump_thread(inst, target, POP_JUMP_IF_TRUE);
}
break;
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
switch (target->i_opcode) {
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
- i -= jump_thread(inst, target, JUMP_ABSOLUTE);
+ case JUMP:
+ i -= jump_thread(inst, target, JUMP);
}
break;
case FOR_ITER:
- if (target->i_opcode == JUMP_FORWARD) {
+ if (target->i_opcode == JUMP) {
+ /* This will not work now because the jump (at target) could
+ * be forward or backward and FOR_ITER only jumps forward. We
+ * can re-enable this if ever we implement a backward version
+ * of FOR_ITER.
+ */
+ /*
i -= jump_thread(inst, target, FOR_ITER);
+ */
}
break;
case SWAP:
return 0;
}
struct instr *last = &bb->b_instr[bb->b_iused-1];
- if (last->i_opcode != JUMP_ABSOLUTE && last->i_opcode != JUMP_FORWARD) {
+ if (last->i_opcode != JUMP &&
+ last->i_opcode != JUMP_FORWARD &&
+ last->i_opcode != JUMP_BACKWARD) {
return 0;
}
if (last->i_target->b_exit && last->i_target->b_iused <= MAX_COPY_SIZE) {
/* Mark blocks as exit and/or nofallthrough.
Raise SystemError if CFG is malformed. */
for (int i = 0; i < bb->b_iused; i++) {
+ assert(bb->b_instr[i].i_opcode != JUMP_FORWARD);
+ assert(bb->b_instr[i].i_opcode != JUMP_BACKWARD);
switch(bb->b_instr[i].i_opcode) {
case RETURN_VALUE:
case RAISE_VARARGS:
bb->b_exit = 1;
bb->b_nofallthrough = 1;
break;
- case JUMP_ABSOLUTE:
- case JUMP_FORWARD:
+ case JUMP:
case JUMP_NO_INTERRUPT:
bb->b_nofallthrough = 1;
/* fall through */
for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
if (b->b_iused > 0) {
struct instr *b_last_instr = &b->b_instr[b->b_iused - 1];
- if (b_last_instr->i_opcode == JUMP_ABSOLUTE ||
- b_last_instr->i_opcode == JUMP_NO_INTERRUPT ||
- b_last_instr->i_opcode == JUMP_FORWARD) {
+ assert(b_last_instr->i_opcode != JUMP_FORWARD);
+ assert(b_last_instr->i_opcode != JUMP_BACKWARD);
+ if (b_last_instr->i_opcode == JUMP ||
+ b_last_instr->i_opcode == JUMP_NO_INTERRUPT) {
if (b_last_instr->i_target == b->b_next) {
assert(b->b_next->b_iused);
b->b_nofallthrough = 0;