mirror of https://github.com/python/cpython
bpo-45056: Remove trailing unused constants from co_consts (GH-28109)
This commit is contained in:
parent
19ba2122ac
commit
55c4a92fc1
|
@ -650,6 +650,17 @@ if 1:
|
|||
self.assertIs(f1.__code__.co_linetable, f2.__code__.co_linetable)
|
||||
self.assertIs(f1.__code__.co_code, f2.__code__.co_code)
|
||||
|
||||
# Stripping unused constants is not a strict requirement for the
|
||||
# Python semantics, it's a more an implementation detail.
|
||||
@support.cpython_only
|
||||
def test_strip_unused_consts(self):
|
||||
# Python 3.10rc1 appended None to co_consts when None is not used
|
||||
# at all. See bpo-45056.
|
||||
def f1():
|
||||
"docstring"
|
||||
return 42
|
||||
self.assertEqual(f1.__code__.co_consts, ("docstring", 42))
|
||||
|
||||
# This is a regression test for a CPython specific peephole optimizer
|
||||
# implementation bug present in a few releases. It's assertion verifies
|
||||
# that peephole optimization was actually done though that isn't an
|
||||
|
|
|
@ -702,10 +702,7 @@ class DisWithFileTests(DisTests):
|
|||
if sys.flags.optimize:
|
||||
code_info_consts = "0: None"
|
||||
else:
|
||||
code_info_consts = (
|
||||
"""0: 'Formatted details of methods, functions, or code.'
|
||||
1: None"""
|
||||
)
|
||||
code_info_consts = "0: 'Formatted details of methods, functions, or code.'"
|
||||
|
||||
code_info_code_info = f"""\
|
||||
Name: code_info
|
||||
|
@ -828,7 +825,6 @@ Flags: 0x0
|
|||
Constants:
|
||||
0: 0
|
||||
1: 1
|
||||
2: None
|
||||
Names:
|
||||
0: x"""
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Compiler now removes trailing unused constants from co_consts.
|
|
@ -7573,6 +7573,9 @@ normalize_basic_block(basicblock *bb);
|
|||
static int
|
||||
optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts);
|
||||
|
||||
static int
|
||||
trim_unused_consts(struct compiler *c, struct assembler *a, PyObject *consts);
|
||||
|
||||
/* Duplicates exit BBs, so that line numbers can be propagated to them */
|
||||
static int
|
||||
duplicate_exits_without_lineno(struct compiler *c);
|
||||
|
@ -7870,6 +7873,9 @@ assemble(struct compiler *c, int addNone)
|
|||
if (duplicate_exits_without_lineno(c)) {
|
||||
return NULL;
|
||||
}
|
||||
if (trim_unused_consts(c, &a, consts)) {
|
||||
goto error;
|
||||
}
|
||||
propagate_line_numbers(&a);
|
||||
guarantee_lineno_for_exits(&a, c->u->u_firstlineno);
|
||||
int maxdepth = stackdepth(c);
|
||||
|
@ -8599,6 +8605,33 @@ optimize_cfg(struct compiler *c, struct assembler *a, PyObject *consts)
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Remove trailing unused constants.
|
||||
static int
|
||||
trim_unused_consts(struct compiler *c, struct assembler *a, PyObject *consts)
|
||||
{
|
||||
assert(PyList_CheckExact(consts));
|
||||
|
||||
// The first constant may be docstring; keep it always.
|
||||
int max_const_index = 0;
|
||||
for (basicblock *b = a->a_entry; b != NULL; b = b->b_next) {
|
||||
for (int i = 0; i < b->b_iused; i++) {
|
||||
if (b->b_instr[i].i_opcode == LOAD_CONST &&
|
||||
b->b_instr[i].i_oparg > max_const_index) {
|
||||
max_const_index = b->b_instr[i].i_oparg;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (max_const_index+1 < PyList_GET_SIZE(consts)) {
|
||||
//fprintf(stderr, "removing trailing consts: max=%d, size=%d\n",
|
||||
// max_const_index, (int)PyList_GET_SIZE(consts));
|
||||
if (PyList_SetSlice(consts, max_const_index+1,
|
||||
PyList_GET_SIZE(consts), NULL) < 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_exit_without_lineno(basicblock *b) {
|
||||
return b->b_exit && b->b_instr[0].i_lineno < 0;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue