Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
6 changes: 6 additions & 0 deletions Doc/library/dis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,12 @@ operation is being performed, so the intermediate analysis object isn't useful:
.. versionchanged:: 3.8
Added *jump* parameter.

.. versionchanged:: 3.13
If ``oparg`` is omitted (or ``None``), the stack effect is now returned
for ``oparg=0``. Previously this was an error for opcodes that use their
arg. It is also no longer an error to pass an integer ``oparg`` when
the ``opcode`` does not use it; the ``oparg`` in this case is ignored.


.. _bytecodes:

Expand Down
13 changes: 0 additions & 13 deletions Include/internal/pycore_opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 1 addition & 25 deletions Include/internal/pycore_opcode_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ extern "C" {

#define IS_WITHIN_OPCODE_RANGE(opcode) \
(((opcode) >= 0 && (opcode) <= MAX_REAL_OPCODE) || \
IS_PSEUDO_OPCODE(opcode))

#define IS_JUMP_OPCODE(opcode) \
is_bit_set_in_table(_PyOpcode_Jump, opcode)
IS_PSEUDO_INSTR(opcode))

#define IS_BLOCK_PUSH_OPCODE(opcode) \
((opcode) == SETUP_FINALLY || \
Expand Down Expand Up @@ -55,27 +52,6 @@ extern "C" {
(opcode) == RAISE_VARARGS || \
(opcode) == RERAISE)

#define LOG_BITS_PER_INT 5
#define MASK_LOW_LOG_BITS 31

static inline int
is_bit_set_in_table(const uint32_t *table, int bitindex) {
/* Is the relevant bit set in the relevant word? */
/* 512 bits fit into 9 32-bits words.
* Word is indexed by (bitindex>>ln(size of int in bits)).
* Bit within word is the low bits of bitindex.
*/
if (bitindex >= 0 && bitindex < 512) {
uint32_t word = table[bitindex >> LOG_BITS_PER_INT];
return (word >> (bitindex & MASK_LOW_LOG_BITS)) & 1;
}
else {
return 0;
}
}

#undef LOG_BITS_PER_INT
#undef MASK_LOW_LOG_BITS

/* Flags used in the oparg for MAKE_FUNCTION */
#define MAKE_FUNCTION_DEFAULTS 0x01
Expand Down
19 changes: 0 additions & 19 deletions Include/opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 2 additions & 8 deletions Lib/test/test__opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,14 @@ def test_stack_effect(self):
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 1), -1)
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 3), -2)
self.assertRaises(ValueError, stack_effect, 30000)
self.assertRaises(ValueError, stack_effect, dis.opmap['BUILD_SLICE'])
self.assertRaises(ValueError, stack_effect, dis.opmap['POP_TOP'], 0)
# All defined opcodes
has_arg = dis.hasarg
for name, code in filter(lambda item: item[0] not in dis.deoptmap, dis.opmap.items()):
if code >= opcode.MIN_INSTRUMENTED_OPCODE:
continue
with self.subTest(opname=name):
if code not in has_arg:
stack_effect(code)
self.assertRaises(ValueError, stack_effect, code, 0)
else:
stack_effect(code, 0)
self.assertRaises(ValueError, stack_effect, code)
stack_effect(code)
stack_effect(code, 0)
# All not defined opcodes
for code in set(range(256)) - set(dis.opmap.values()):
with self.subTest(opcode=code):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:func:`~dis.stack_effect`B no longer raises an exception if an ``oparg`` is
Comment thread
arhadthedev marked this conversation as resolved.
Outdated
provided for an ``opcode`` that doesn't use its arg, or when it is not
provided for an ``opcode`` that does use it. In the latter case, the stack
effect is returned or ``oparg=0``.
22 changes: 6 additions & 16 deletions Modules/_opcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,16 @@ _opcode_stack_effect_impl(PyObject *module, int opcode, PyObject *oparg,
PyObject *jump)
/*[clinic end generated code: output=64a18f2ead954dbb input=461c9d4a44851898]*/
{
int effect;
int oparg_int = 0;
int jump_int;
if (HAS_ARG(opcode)) {
if (oparg == Py_None) {
PyErr_SetString(PyExc_ValueError,
"stack_effect: opcode requires oparg but oparg was not specified");
return -1;
}

if (oparg != Py_None) {
oparg_int = (int)PyLong_AsLong(oparg);
if ((oparg_int == -1) && PyErr_Occurred()) {
return -1;
}
}
else if (oparg != Py_None) {
PyErr_SetString(PyExc_ValueError,
"stack_effect: opcode does not permit oparg but oparg was specified");
return -1;
}

if (jump == Py_None) {
jump_int = -1;
}
Expand All @@ -60,11 +51,10 @@ _opcode_stack_effect_impl(PyObject *module, int opcode, PyObject *oparg,
"stack_effect: jump must be False, True or None");
return -1;
}
effect = PyCompile_OpcodeStackEffectWithJump(opcode, oparg_int, jump_int);
int effect = PyCompile_OpcodeStackEffectWithJump(opcode, oparg_int, jump_int);
if (effect == PY_INVALID_STACK_EFFECT) {
PyErr_SetString(PyExc_ValueError,
"invalid opcode or oparg");
return -1;
PyErr_SetString(PyExc_ValueError, "invalid opcode or oparg");
return -1;
}
return effect;
}
Expand Down
3 changes: 1 addition & 2 deletions Python/assemble.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,10 +339,9 @@ static void
write_instr(_Py_CODEUNIT *codestr, instruction *instr, int ilen)
{
int opcode = instr->i_opcode;
assert(IS_PSEUDO_OPCODE(opcode) == IS_PSEUDO_INSTR(opcode));
assert(!IS_PSEUDO_INSTR(opcode));
int oparg = instr->i_oparg;
assert(HAS_ARG(opcode) || oparg == 0);
assert(OPCODE_HAS_ARG(opcode) || oparg == 0);
int caches = _PyOpcode_Caches[opcode];
switch (ilen - caches) {
case 4:
Expand Down
5 changes: 3 additions & 2 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "pycore_frame.h"
#include "frameobject.h" // _PyInterpreterFrame_GetLine
#include "opcode.h"
#include "opcode_metadata.h"
#include "pydtrace.h"
#include "setobject.h"
#include "structmember.h" // struct PyMemberDef, T_OFFSET_EX
Expand Down Expand Up @@ -141,7 +142,7 @@ lltrace_instruction(_PyInterpreterFrame *frame,
const char *opname = _PyOpcode_OpName[opcode];
assert(opname != NULL);
int offset = (int)(next_instr - _PyCode_CODE(_PyFrame_GetCode(frame)));
if (HAS_ARG((int)_PyOpcode_Deopt[opcode])) {
if (OPCODE_HAS_ARG((int)_PyOpcode_Deopt[opcode])) {
printf("%d: %s %d\n", offset * 2, opname, oparg);
}
else {
Expand Down Expand Up @@ -882,7 +883,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
#if USE_COMPUTED_GOTOS
_unknown_opcode:
#else
EXTRA_CASES // From opcode.h, a 'case' for each unused opcode
EXTRA_CASES // From pycore_opcode.h, a 'case' for each unused opcode
#endif
/* Tell C compilers not to hold the opcode variable in the loop.
next_instr points the current instruction without TARGET(). */
Expand Down
17 changes: 5 additions & 12 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,8 @@ enum {
int
_PyCompile_InstrSize(int opcode, int oparg)
{
assert(IS_PSEUDO_OPCODE(opcode) == IS_PSEUDO_INSTR(opcode));
assert(!IS_PSEUDO_INSTR(opcode));
assert(HAS_ARG(opcode) || oparg == 0);
assert(OPCODE_HAS_ARG(opcode) || oparg == 0);
int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg);
int caches = _PyOpcode_Caches[opcode];
return extended_args + 1 + caches;
Expand Down Expand Up @@ -248,15 +247,9 @@ instr_sequence_use_label(instr_sequence *seq, int lbl) {
static int
instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc)
{
/* compare old and new opcode macros - use ! to compare as bools. */
assert(!HAS_ARG(opcode) == !OPCODE_HAS_ARG(opcode));
assert(!HAS_CONST(opcode) == !OPCODE_HAS_CONST(opcode));
assert(!OPCODE_HAS_JUMP(opcode) == !OPCODE_HAS_JUMP(opcode));

assert(0 <= opcode && opcode <= MAX_OPCODE);
assert(IS_PSEUDO_OPCODE(opcode) == IS_PSEUDO_INSTR(opcode));
assert(IS_WITHIN_OPCODE_RANGE(opcode));
assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0);
assert(OPCODE_HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0);
assert(0 <= oparg && oparg < (1 << 30));

int idx = instr_sequence_next_inst(seq);
Expand Down Expand Up @@ -874,7 +867,7 @@ PyCompile_OpcodeStackEffect(int opcode, int oparg)
static int
codegen_addop_noarg(instr_sequence *seq, int opcode, location loc)
{
assert(!HAS_ARG(opcode));
assert(!OPCODE_HAS_ARG(opcode));
assert(!IS_ASSEMBLER_OPCODE(opcode));
return instr_sequence_addop(seq, opcode, 0, loc);
}
Expand Down Expand Up @@ -1151,7 +1144,7 @@ codegen_addop_j(instr_sequence *seq, location loc,
}

#define ADDOP_N(C, LOC, OP, O, TYPE) { \
assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \
assert(!OPCODE_HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \
if (compiler_addop_o((C)->u, (LOC), (OP), (C)->u->u_metadata.u_ ## TYPE, (O)) < 0) { \
Py_DECREF((O)); \
return ERROR; \
Expand Down Expand Up @@ -7798,7 +7791,7 @@ instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq)
goto error;
}
int oparg;
if (HAS_ARG(opcode)) {
if (OPCODE_HAS_ARG(opcode)) {
oparg = PyLong_AsLong(PyTuple_GET_ITEM(item, 1));
if (PyErr_Occurred()) {
goto error;
Expand Down
21 changes: 10 additions & 11 deletions Python/flowgraph.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,13 @@ is_block_push(cfg_instr *i)
static inline int
is_jump(cfg_instr *i)
{
assert(!OPCODE_HAS_JUMP(i->i_opcode) == !IS_JUMP_OPCODE(i->i_opcode));
return OPCODE_HAS_JUMP(i->i_opcode);
}

/* One arg*/
#define INSTR_SET_OP1(I, OP, ARG) \
do { \
assert(HAS_ARG(OP)); \
assert(OPCODE_HAS_ARG(OP)); \
_PyCfgInstruction *_instr__ptr_ = (I); \
_instr__ptr_->i_opcode = (OP); \
_instr__ptr_->i_oparg = (ARG); \
Expand All @@ -61,7 +60,7 @@ is_jump(cfg_instr *i)
/* No args*/
#define INSTR_SET_OP0(I, OP) \
do { \
assert(!HAS_ARG(OP)); \
assert(!OPCODE_HAS_ARG(OP)); \
_PyCfgInstruction *_instr__ptr_ = (I); \
_instr__ptr_->i_opcode = (OP); \
_instr__ptr_->i_oparg = 0; \
Expand Down Expand Up @@ -111,7 +110,7 @@ basicblock_addop(basicblock *b, int opcode, int oparg, location loc)
{
assert(IS_WITHIN_OPCODE_RANGE(opcode));
assert(!IS_ASSEMBLER_OPCODE(opcode));
assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0);
assert(OPCODE_HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0);
assert(0 <= oparg && oparg < (1 << 30));

int off = basicblock_next_instr(b);
Expand Down Expand Up @@ -193,7 +192,7 @@ dump_instr(cfg_instr *i)
char arg[128];

*arg = '\0';
if (HAS_ARG(i->i_opcode)) {
if (OPCODE_HAS_ARG(i->i_opcode)) {
sprintf(arg, "arg: %d ", i->i_oparg);
}
if (HAS_TARGET(i->i_opcode)) {
Expand Down Expand Up @@ -1108,7 +1107,7 @@ static PyObject*
get_const_value(int opcode, int oparg, PyObject *co_consts)
{
PyObject *constant = NULL;
assert(HAS_CONST(opcode));
assert(OPCODE_HAS_CONST(opcode));
if (opcode == LOAD_CONST) {
constant = PyList_GET_ITEM(co_consts, oparg);
}
Expand Down Expand Up @@ -1139,7 +1138,7 @@ fold_tuple_on_constants(PyObject *const_cache,
assert(inst[n].i_oparg == n);

for (int i = 0; i < n; i++) {
if (!HAS_CONST(inst[i].i_opcode)) {
if (!OPCODE_HAS_CONST(inst[i].i_opcode)) {
return SUCCESS;
}
}
Expand Down Expand Up @@ -1542,8 +1541,8 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
}
break;
default:
/* All HAS_CONST opcodes should be handled with LOAD_CONST */
assert (!HAS_CONST(inst->i_opcode));
/* All OPCODE_HAS_CONST opcodes should be handled with LOAD_CONST */
assert (!OPCODE_HAS_CONST(inst->i_opcode));
}
}

Expand Down Expand Up @@ -1793,7 +1792,7 @@ remove_unused_consts(basicblock *entryblock, PyObject *consts)
/* mark used consts */
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
for (int i = 0; i < b->b_iused; i++) {
if (HAS_CONST(b->b_instr[i].i_opcode)) {
if (OPCODE_HAS_CONST(b->b_instr[i].i_opcode)) {
int index = b->b_instr[i].i_oparg;
index_map[index] = index;
}
Expand Down Expand Up @@ -1846,7 +1845,7 @@ remove_unused_consts(basicblock *entryblock, PyObject *consts)

for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
for (int i = 0; i < b->b_iused; i++) {
if (HAS_CONST(b->b_instr[i].i_opcode)) {
if (OPCODE_HAS_CONST(b->b_instr[i].i_opcode)) {
int index = b->b_instr[i].i_oparg;
assert(reverse_index_map[index] >= 0);
assert(reverse_index_map[index] < n_used_consts);
Expand Down
Loading