Skip to content

Commit c2f1e95

Browse files
authored
bpo-45152: Add HAS_CONST macro and get_const_value() function and use… (#28262)
1 parent 9f93018 commit c2f1e95

File tree

3 files changed

+53
-7
lines changed

3 files changed

+53
-7
lines changed

Include/opcode.h

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/compile.c

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1638,14 +1638,14 @@ compiler_addop_j_noline(struct compiler *c, int opcode, basicblock *b)
16381638
}
16391639

16401640
#define ADDOP_O(C, OP, O, TYPE) { \
1641-
assert((OP) != LOAD_CONST); /* use ADDOP_LOAD_CONST */ \
1641+
assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST */ \
16421642
if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) \
16431643
return 0; \
16441644
}
16451645

16461646
/* Same as ADDOP_O, but steals a reference. */
16471647
#define ADDOP_N(C, OP, O, TYPE) { \
1648-
assert((OP) != LOAD_CONST); /* use ADDOP_LOAD_CONST_NEW */ \
1648+
assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \
16491649
if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) { \
16501650
Py_DECREF((O)); \
16511651
return 0; \
@@ -7951,6 +7951,24 @@ assemble(struct compiler *c, int addNone)
79517951
return co;
79527952
}
79537953

7954+
static PyObject*
7955+
get_const_value(int opcode, int oparg, PyObject *co_consts)
7956+
{
7957+
PyObject *constant = NULL;
7958+
assert(HAS_CONST(opcode));
7959+
if (opcode == LOAD_CONST) {
7960+
constant = PyList_GET_ITEM(co_consts, oparg);
7961+
}
7962+
7963+
if (constant == NULL) {
7964+
PyErr_SetString(PyExc_SystemError,
7965+
"Internal error: failed to get value of a constant");
7966+
return NULL;
7967+
}
7968+
Py_INCREF(constant);
7969+
return constant;
7970+
}
7971+
79547972
/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n
79557973
with LOAD_CONST (c1, c2, ... cn).
79567974
The consts table must still be in list form so that the
@@ -7968,7 +7986,7 @@ fold_tuple_on_constants(struct compiler *c,
79687986
assert(inst[n].i_oparg == n);
79697987

79707988
for (int i = 0; i < n; i++) {
7971-
if (inst[i].i_opcode != LOAD_CONST) {
7989+
if (!HAS_CONST(inst[i].i_opcode)) {
79727990
return 0;
79737991
}
79747992
}
@@ -7979,9 +7997,12 @@ fold_tuple_on_constants(struct compiler *c,
79797997
return -1;
79807998
}
79817999
for (int i = 0; i < n; i++) {
8000+
int op = inst[i].i_opcode;
79828001
int arg = inst[i].i_oparg;
7983-
PyObject *constant = PyList_GET_ITEM(consts, arg);
7984-
Py_INCREF(constant);
8002+
PyObject *constant = get_const_value(op, arg, consts);
8003+
if (constant == NULL) {
8004+
return -1;
8005+
}
79858006
PyTuple_SET_ITEM(newconst, i, constant);
79868007
}
79878008
if (merge_const_one(c, &newconst) == 0) {
@@ -8107,8 +8128,12 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
81078128
switch(nextop) {
81088129
case POP_JUMP_IF_FALSE:
81098130
case POP_JUMP_IF_TRUE:
8110-
cnt = PyList_GET_ITEM(consts, oparg);
8131+
cnt = get_const_value(inst->i_opcode, oparg, consts);
8132+
if (cnt == NULL) {
8133+
goto error;
8134+
}
81118135
is_true = PyObject_IsTrue(cnt);
8136+
Py_DECREF(cnt);
81128137
if (is_true == -1) {
81138138
goto error;
81148139
}
@@ -8124,8 +8149,12 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
81248149
break;
81258150
case JUMP_IF_FALSE_OR_POP:
81268151
case JUMP_IF_TRUE_OR_POP:
8127-
cnt = PyList_GET_ITEM(consts, oparg);
8152+
cnt = get_const_value(inst->i_opcode, oparg, consts);
8153+
if (cnt == NULL) {
8154+
goto error;
8155+
}
81288156
is_true = PyObject_IsTrue(cnt);
8157+
Py_DECREF(cnt);
81298158
if (is_true == -1) {
81308159
goto error;
81318160
}
@@ -8310,6 +8339,9 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
83108339
fold_rotations(inst - oparg + 1, oparg);
83118340
}
83128341
break;
8342+
default:
8343+
/* All HAS_CONST opcodes should be handled with LOAD_CONST */
8344+
assert (!HAS_CONST(inst->i_opcode));
83138345
}
83148346
}
83158347
return 0;

Tools/scripts/generate_opcode_h.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def main(opcode_py, outfile='Include/opcode.h'):
5151
code = fp.read()
5252
exec(code, opcode)
5353
opmap = opcode['opmap']
54+
hasconst = opcode['hasconst']
5455
hasjrel = opcode['hasjrel']
5556
hasjabs = opcode['hasjabs']
5657
used = [ False ] * 256
@@ -65,15 +66,24 @@ def main(opcode_py, outfile='Include/opcode.h'):
6566
if name == 'POP_EXCEPT': # Special entry for HAVE_ARGUMENT
6667
fobj.write("#define %-23s %3d\n" %
6768
('HAVE_ARGUMENT', opcode['HAVE_ARGUMENT']))
69+
6870
for name in opcode['_specialized_instructions']:
6971
while used[next_op]:
7072
next_op += 1
7173
fobj.write("#define %-23s %3s\n" % (name, next_op))
7274
used[next_op] = True
75+
7376
fobj.write("#ifdef NEED_OPCODE_JUMP_TABLES\n")
7477
write_int_array_from_ops("_PyOpcode_RelativeJump", opcode['hasjrel'], fobj)
7578
write_int_array_from_ops("_PyOpcode_Jump", opcode['hasjrel'] + opcode['hasjabs'], fobj)
7679
fobj.write("#endif /* OPCODE_TABLES */\n")
80+
81+
fobj.write("\n")
82+
fobj.write("#define HAS_CONST(op) (false\\")
83+
for op in hasconst:
84+
fobj.write(f"\n || ((op) == {op}) \\")
85+
fobj.write("\n )\n")
86+
7787
fobj.write(footer)
7888

7989

0 commit comments

Comments
 (0)