Thanks to visit codestin.com
Credit goes to github.com

Skip to content

bpo-42246: Remove DO_NOT_EMIT_BYTECODE macros, so that while loops and if statements conform to PEP 626. #23743

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,10 +728,10 @@ def unused_block_while_else():

for func in funcs:
opcodes = list(dis.get_instructions(func))
self.assertEqual(2, len(opcodes))
self.assertEqual('LOAD_CONST', opcodes[0].opname)
self.assertEqual(None, opcodes[0].argval)
self.assertEqual('RETURN_VALUE', opcodes[1].opname)
self.assertLessEqual(len(opcodes), 3)
self.assertEqual('LOAD_CONST', opcodes[-2].opname)
self.assertEqual(None, opcodes[-2].argval)
self.assertEqual('RETURN_VALUE', opcodes[-1].opname)

def test_false_while_loop(self):
def break_in_while():
Expand Down
137 changes: 71 additions & 66 deletions Lib/test/test_dis.py

Large diffs are not rendered by default.

15 changes: 0 additions & 15 deletions Lib/test/test_peepholer.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,21 +409,6 @@ def f(cond1, cond2):
self.assertLessEqual(len(returns), 6)
self.check_lnotab(f)

def test_elim_jump_after_return2(self):
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed this test, as doesn't test what it claims to test. There is no dead code in

def f(cond1, cond2):
    while 1:
        if cond1: return 4

# Eliminate dead code: jumps immediately after returns can't be reached
def f(cond1, cond2):
while 1:
if cond1: return 4
self.assertNotInBytecode(f, 'JUMP_FORWARD')
# There should be one jump for the while loop.
jumps = [instr for instr in dis.get_instructions(f)
if 'JUMP' in instr.opname]
self.assertEqual(len(jumps), 1)
returns = [instr for instr in dis.get_instructions(f)
if instr.opname == 'RETURN_VALUE']
self.assertLessEqual(len(returns), 2)
self.check_lnotab(f)

def test_make_function_doesnt_bail(self):
def f():
def g()->1+1:
Expand Down
12 changes: 9 additions & 3 deletions Lib/test/test_sys_settrace.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,8 @@ def basic():
# following that clause?


# Some constructs like "while 0:", "if 0:" or "if 1:...else:..." are optimized
# away. No code # exists for them, so the line numbers skip directly from
# "del x" to "x = 1".
# Some constructs like "while 0:", "if 0:" or "if 1:...else:..." could be optimized
# away. Make sure that those lines aren't skipped.
def arigo_example0():
x = 1
del x
Expand All @@ -66,6 +65,7 @@ def arigo_example0():
arigo_example0.events = [(0, 'call'),
(1, 'line'),
(2, 'line'),
(3, 'line'),
(5, 'line'),
(5, 'return')]

Expand All @@ -79,6 +79,7 @@ def arigo_example1():
arigo_example1.events = [(0, 'call'),
(1, 'line'),
(2, 'line'),
(3, 'line'),
(5, 'line'),
(5, 'return')]

Expand All @@ -94,6 +95,7 @@ def arigo_example2():
arigo_example2.events = [(0, 'call'),
(1, 'line'),
(2, 'line'),
(3, 'line'),
(4, 'line'),
(7, 'line'),
(7, 'return')]
Expand Down Expand Up @@ -236,9 +238,13 @@ def tightloop_example():
(1, 'line'),
(2, 'line'),
(3, 'line'),
(4, 'line'),
(5, 'line'),
(4, 'line'),
(5, 'line'),
(4, 'line'),
(5, 'line'),
(4, 'line'),
(5, 'line'),
(5, 'exception'),
(6, 'line'),
Expand Down
112 changes: 27 additions & 85 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ static int compiler_slice(struct compiler *, expr_ty);

static int inplace_binop(operator_ty);
static int are_all_items_const(asdl_expr_seq *, Py_ssize_t, Py_ssize_t);
static int expr_constant(expr_ty);


static int compiler_with(struct compiler *, stmt_ty, int);
static int compiler_async_with(struct compiler *, stmt_ty, int);
Expand Down Expand Up @@ -1572,17 +1572,6 @@ compiler_addop_j(struct compiler *c, int opcode, basicblock *b)
} \
}

/* These macros allows to check only for errors and not emmit bytecode
* while visiting nodes.
*/

#define BEGIN_DO_NOT_EMIT_BYTECODE { \
c->c_do_not_emit_bytecode++;

#define END_DO_NOT_EMIT_BYTECODE \
c->c_do_not_emit_bytecode--; \
}

/* Search if variable annotations are present statically in a block. */

static int
Expand Down Expand Up @@ -2704,48 +2693,28 @@ static int
compiler_if(struct compiler *c, stmt_ty s)
{
basicblock *end, *next;
int constant;
assert(s->kind == If_kind);
end = compiler_new_block(c);
if (end == NULL)
if (end == NULL) {
return 0;

constant = expr_constant(s->v.If.test);
/* constant = 0: "if 0"
* constant = 1: "if 1", "if 2", ...
* constant = -1: rest */
if (constant == 0) {
BEGIN_DO_NOT_EMIT_BYTECODE
VISIT_SEQ(c, stmt, s->v.If.body);
END_DO_NOT_EMIT_BYTECODE
if (s->v.If.orelse) {
VISIT_SEQ(c, stmt, s->v.If.orelse);
}
} else if (constant == 1) {
VISIT_SEQ(c, stmt, s->v.If.body);
if (s->v.If.orelse) {
BEGIN_DO_NOT_EMIT_BYTECODE
VISIT_SEQ(c, stmt, s->v.If.orelse);
END_DO_NOT_EMIT_BYTECODE
}
} else {
if (asdl_seq_LEN(s->v.If.orelse)) {
next = compiler_new_block(c);
if (next == NULL)
return 0;
}
else {
next = end;
}
if (!compiler_jump_if(c, s->v.If.test, next, 0)) {
}
if (asdl_seq_LEN(s->v.If.orelse)) {
next = compiler_new_block(c);
if (next == NULL) {
return 0;
}
VISIT_SEQ(c, stmt, s->v.If.body);
if (asdl_seq_LEN(s->v.If.orelse)) {
ADDOP_JUMP(c, JUMP_FORWARD, end);
compiler_use_next_block(c, next);
VISIT_SEQ(c, stmt, s->v.If.orelse);
}
}
else {
next = end;
}
if (!compiler_jump_if(c, s->v.If.test, next, 0)) {
return 0;
}
VISIT_SEQ(c, stmt, s->v.If.body);
if (asdl_seq_LEN(s->v.If.orelse)) {
ADDOP_JUMP(c, JUMP_FORWARD, end);
compiler_use_next_block(c, next);
VISIT_SEQ(c, stmt, s->v.If.orelse);
}
compiler_use_next_block(c, end);
return 1;
Expand Down Expand Up @@ -2842,25 +2811,6 @@ static int
compiler_while(struct compiler *c, stmt_ty s)
{
basicblock *loop, *body, *end, *anchor = NULL;
int constant = expr_constant(s->v.While.test);

if (constant == 0) {
BEGIN_DO_NOT_EMIT_BYTECODE
// Push a dummy block so the VISIT_SEQ knows that we are
// inside a while loop so it can correctly evaluate syntax
// errors.
if (!compiler_push_fblock(c, WHILE_LOOP, NULL, NULL, NULL)) {
return 0;
}
VISIT_SEQ(c, stmt, s->v.While.body);
// Remove the dummy block now that is not needed.
compiler_pop_fblock(c, WHILE_LOOP, NULL);
END_DO_NOT_EMIT_BYTECODE
if (s->v.While.orelse) {
VISIT_SEQ(c, stmt, s->v.While.orelse);
}
return 1;
}
loop = compiler_new_block(c);
body = compiler_new_block(c);
anchor = compiler_new_block(c);
Expand All @@ -2872,15 +2822,16 @@ compiler_while(struct compiler *c, stmt_ty s)
if (!compiler_push_fblock(c, WHILE_LOOP, loop, end, NULL)) {
return 0;
}
if (constant == -1) {
if (!compiler_jump_if(c, s->v.While.test, anchor, 0)) {
return 0;
}
if (!compiler_jump_if(c, s->v.While.test, anchor, 0)) {
return 0;
}

compiler_use_next_block(c, body);
VISIT_SEQ(c, stmt, s->v.While.body);
ADDOP_JUMP(c, JUMP_ABSOLUTE, loop);
SET_LOC(c, s);
if (!compiler_jump_if(c, s->v.While.test, body, 1)) {
return 0;
}

compiler_pop_fblock(c, WHILE_LOOP, loop);

Expand Down Expand Up @@ -4791,15 +4742,6 @@ compiler_visit_keyword(struct compiler *c, keyword_ty k)
Return values: 1 for true, 0 for false, -1 for non-constant.
*/

static int
expr_constant(expr_ty e)
{
if (e->kind == Constant_kind) {
return PyObject_IsTrue(e->v.Constant.value);
}
return -1;
}

static int
compiler_with_except_finish(struct compiler *c) {
basicblock *exit;
Expand Down Expand Up @@ -6304,7 +6246,7 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
case JUMP_FORWARD:
if (inst->i_target != target->i_target) {
inst->i_target = target->i_target;
--i;
// --i;
}
break;
case JUMP_ABSOLUTE:
Expand All @@ -6317,8 +6259,8 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
}
if (inst->i_target->b_exit && inst->i_target->b_iused <= MAX_COPY_SIZE) {
basicblock *to_copy = inst->i_target;
*inst = to_copy->b_instr[0];
for (i = 1; i < to_copy->b_iused; i++) {
inst->i_opcode = NOP;
for (i = 0; i < to_copy->b_iused; i++) {
int index = compiler_next_instr(bb);
if (index < 0) {
return -1;
Expand Down
Loading