From c2f1e953371c25f6c42b599ba3d8797effbb503e Mon Sep 17 00:00:00 2001 From: Irit Katriel <1055913+iritkatriel@users.noreply.github.com> Date: Tue, 14 Sep 2021 09:53:32 +0100 Subject: [PATCH] =?UTF-8?q?bpo-45152:=20Add=20HAS=5FCONST=20macro=20and=20?= =?UTF-8?q?get=5Fconst=5Fvalue()=20function=20and=20use=E2=80=A6=20(#28262?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Include/opcode.h | 4 +++ Python/compile.c | 46 +++++++++++++++++++++++++----- Tools/scripts/generate_opcode_h.py | 10 +++++++ 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/Include/opcode.h b/Include/opcode.h index 0043cc2d209..27895255947 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -190,6 +190,10 @@ static uint32_t _PyOpcode_Jump[8] = { }; #endif /* OPCODE_TABLES */ +#define HAS_CONST(op) (false\ + || ((op) == 100) \ + ) + #define HAS_ARG(op) ((op) >= HAVE_ARGUMENT) /* Reserve some bytecodes for internal use in the compiler. diff --git a/Python/compile.c b/Python/compile.c index 389b3e0d723..fdc2ce61a8e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1638,14 +1638,14 @@ compiler_addop_j_noline(struct compiler *c, int opcode, basicblock *b) } #define ADDOP_O(C, OP, O, TYPE) { \ - assert((OP) != LOAD_CONST); /* use ADDOP_LOAD_CONST */ \ + assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST */ \ if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) \ return 0; \ } /* Same as ADDOP_O, but steals a reference. */ #define ADDOP_N(C, OP, O, TYPE) { \ - assert((OP) != LOAD_CONST); /* use ADDOP_LOAD_CONST_NEW */ \ + assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \ if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) { \ Py_DECREF((O)); \ return 0; \ @@ -7951,6 +7951,24 @@ assemble(struct compiler *c, int addNone) return co; } +static PyObject* +get_const_value(int opcode, int oparg, PyObject *co_consts) +{ + PyObject *constant = NULL; + assert(HAS_CONST(opcode)); + if (opcode == LOAD_CONST) { + constant = PyList_GET_ITEM(co_consts, oparg); + } + + if (constant == NULL) { + PyErr_SetString(PyExc_SystemError, + "Internal error: failed to get value of a constant"); + return NULL; + } + Py_INCREF(constant); + return constant; +} + /* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n with LOAD_CONST (c1, c2, ... cn). The consts table must still be in list form so that the @@ -7968,7 +7986,7 @@ fold_tuple_on_constants(struct compiler *c, assert(inst[n].i_oparg == n); for (int i = 0; i < n; i++) { - if (inst[i].i_opcode != LOAD_CONST) { + if (!HAS_CONST(inst[i].i_opcode)) { return 0; } } @@ -7979,9 +7997,12 @@ fold_tuple_on_constants(struct compiler *c, return -1; } for (int i = 0; i < n; i++) { + int op = inst[i].i_opcode; int arg = inst[i].i_oparg; - PyObject *constant = PyList_GET_ITEM(consts, arg); - Py_INCREF(constant); + PyObject *constant = get_const_value(op, arg, consts); + if (constant == NULL) { + return -1; + } PyTuple_SET_ITEM(newconst, i, constant); } if (merge_const_one(c, &newconst) == 0) { @@ -8107,8 +8128,12 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) switch(nextop) { case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: - cnt = PyList_GET_ITEM(consts, oparg); + cnt = get_const_value(inst->i_opcode, oparg, consts); + if (cnt == NULL) { + goto error; + } is_true = PyObject_IsTrue(cnt); + Py_DECREF(cnt); if (is_true == -1) { goto error; } @@ -8124,8 +8149,12 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) break; case JUMP_IF_FALSE_OR_POP: case JUMP_IF_TRUE_OR_POP: - cnt = PyList_GET_ITEM(consts, oparg); + cnt = get_const_value(inst->i_opcode, oparg, consts); + if (cnt == NULL) { + goto error; + } is_true = PyObject_IsTrue(cnt); + Py_DECREF(cnt); if (is_true == -1) { goto error; } @@ -8310,6 +8339,9 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) fold_rotations(inst - oparg + 1, oparg); } break; + default: + /* All HAS_CONST opcodes should be handled with LOAD_CONST */ + assert (!HAS_CONST(inst->i_opcode)); } } return 0; diff --git a/Tools/scripts/generate_opcode_h.py b/Tools/scripts/generate_opcode_h.py index 41ae3fe6e53..48875d2a9dd 100644 --- a/Tools/scripts/generate_opcode_h.py +++ b/Tools/scripts/generate_opcode_h.py @@ -51,6 +51,7 @@ def main(opcode_py, outfile='Include/opcode.h'): code = fp.read() exec(code, opcode) opmap = opcode['opmap'] + hasconst = opcode['hasconst'] hasjrel = opcode['hasjrel'] hasjabs = opcode['hasjabs'] used = [ False ] * 256 @@ -65,15 +66,24 @@ def main(opcode_py, outfile='Include/opcode.h'): if name == 'POP_EXCEPT': # Special entry for HAVE_ARGUMENT fobj.write("#define %-23s %3d\n" % ('HAVE_ARGUMENT', opcode['HAVE_ARGUMENT'])) + for name in opcode['_specialized_instructions']: while used[next_op]: next_op += 1 fobj.write("#define %-23s %3s\n" % (name, next_op)) used[next_op] = True + fobj.write("#ifdef NEED_OPCODE_JUMP_TABLES\n") write_int_array_from_ops("_PyOpcode_RelativeJump", opcode['hasjrel'], fobj) write_int_array_from_ops("_PyOpcode_Jump", opcode['hasjrel'] + opcode['hasjabs'], fobj) fobj.write("#endif /* OPCODE_TABLES */\n") + + fobj.write("\n") + fobj.write("#define HAS_CONST(op) (false\\") + for op in hasconst: + fobj.write(f"\n || ((op) == {op}) \\") + fobj.write("\n )\n") + fobj.write(footer)