Skip to content

Commit

Permalink
gh-101907: Stop using _Py_OPCODE and _Py_OPARG macros (GH-101912)
Browse files Browse the repository at this point in the history
* gh-101907: Removes use of non-standard C++ extension from Include/cpython/code.h

* Make cases_generator correct on Windows
  • Loading branch information
zooba authored Feb 20, 2023
1 parent c00faf7 commit a99eb5c
Show file tree
Hide file tree
Showing 13 changed files with 200 additions and 184 deletions.
28 changes: 21 additions & 7 deletions Include/cpython/code.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,35 @@ extern "C" {
typedef union {
uint16_t cache;
struct {
uint8_t opcode;
uint8_t oparg;
};
uint8_t code;
uint8_t arg;
} op;
} _Py_CODEUNIT;

#define _Py_OPCODE(word) ((word).opcode)
#define _Py_OPARG(word) ((word).oparg)

/* These macros only remain defined for compatibility. */
#define _Py_OPCODE(word) ((word).op.code)
#define _Py_OPARG(word) ((word).op.arg)

static inline _Py_CODEUNIT
_py_make_codeunit(uint8_t opcode, uint8_t oparg)
{
// No designated initialisers because of C++ compat
_Py_CODEUNIT word;
word.op.code = opcode;
word.op.arg = oparg;
return word;
}

static inline void
_py_set_opcode(_Py_CODEUNIT *word, uint8_t opcode)
{
word->opcode = opcode;
word->op.code = opcode;
}

#define _Py_SET_OPCODE(word, opcode) _py_set_opocde(&(word), opcode)
#define _Py_MAKE_CODEUNIT(opcode, oparg) _py_make_codeunit((opcode), (oparg))
#define _Py_SET_OPCODE(word, opcode) _py_set_opcode(&(word), (opcode))


typedef struct {
PyObject *_co_code;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Removes use of non-standard C++ extension in public header files.
20 changes: 10 additions & 10 deletions Objects/codeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
PyBytes_GET_SIZE(con->code));
int entry_point = 0;
while (entry_point < Py_SIZE(co) &&
_Py_OPCODE(_PyCode_CODE(co)[entry_point]) != RESUME) {
_PyCode_CODE(co)[entry_point].op.code != RESUME) {
entry_point++;
}
co->_co_firsttraceable = entry_point;
Expand Down Expand Up @@ -1505,12 +1505,12 @@ deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len)
{
for (int i = 0; i < len; i++) {
_Py_CODEUNIT instruction = instructions[i];
int opcode = _PyOpcode_Deopt[_Py_OPCODE(instruction)];
int opcode = _PyOpcode_Deopt[instruction.op.code];
int caches = _PyOpcode_Caches[opcode];
instructions[i].opcode = opcode;
instructions[i].op.code = opcode;
while (caches--) {
instructions[++i].opcode = CACHE;
instructions[i].oparg = 0;
instructions[++i].op.code = CACHE;
instructions[i].op.arg = 0;
}
}
}
Expand Down Expand Up @@ -1763,13 +1763,13 @@ code_richcompare(PyObject *self, PyObject *other, int op)
for (int i = 0; i < Py_SIZE(co); i++) {
_Py_CODEUNIT co_instr = _PyCode_CODE(co)[i];
_Py_CODEUNIT cp_instr = _PyCode_CODE(cp)[i];
co_instr.opcode = _PyOpcode_Deopt[_Py_OPCODE(co_instr)];
cp_instr.opcode =_PyOpcode_Deopt[_Py_OPCODE(cp_instr)];
co_instr.op.code = _PyOpcode_Deopt[co_instr.op.code];
cp_instr.op.code = _PyOpcode_Deopt[cp_instr.op.code];
eq = co_instr.cache == cp_instr.cache;
if (!eq) {
goto unequal;
}
i += _PyOpcode_Caches[_Py_OPCODE(co_instr)];
i += _PyOpcode_Caches[co_instr.op.code];
}

/* compare constants */
Expand Down Expand Up @@ -1848,9 +1848,9 @@ code_hash(PyCodeObject *co)
SCRAMBLE_IN(co->co_firstlineno);
SCRAMBLE_IN(Py_SIZE(co));
for (int i = 0; i < Py_SIZE(co); i++) {
int deop = _PyOpcode_Deopt[_Py_OPCODE(_PyCode_CODE(co)[i])];
int deop = _PyOpcode_Deopt[_PyCode_CODE(co)[i].op.code];
SCRAMBLE_IN(deop);
SCRAMBLE_IN(_Py_OPARG(_PyCode_CODE(co)[i]));
SCRAMBLE_IN(_PyCode_CODE(co)[i].op.arg);
i += _PyOpcode_Caches[deop];
}
if ((Py_hash_t)uhash == -1) {
Expand Down
24 changes: 12 additions & 12 deletions Objects/frameobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,13 @@ static unsigned int
get_arg(const _Py_CODEUNIT *codestr, Py_ssize_t i)
{
_Py_CODEUNIT word;
unsigned int oparg = _Py_OPARG(codestr[i]);
if (i >= 1 && _Py_OPCODE(word = codestr[i-1]) == EXTENDED_ARG) {
oparg |= _Py_OPARG(word) << 8;
if (i >= 2 && _Py_OPCODE(word = codestr[i-2]) == EXTENDED_ARG) {
oparg |= _Py_OPARG(word) << 16;
if (i >= 3 && _Py_OPCODE(word = codestr[i-3]) == EXTENDED_ARG) {
oparg |= _Py_OPARG(word) << 24;
unsigned int oparg = codestr[i].op.arg;
if (i >= 1 && (word = codestr[i-1]).op.code == EXTENDED_ARG) {
oparg |= word.op.arg << 8;
if (i >= 2 && (word = codestr[i-2]).op.code == EXTENDED_ARG) {
oparg |= word.op.arg << 16;
if (i >= 3 && (word = codestr[i-3]).op.code == EXTENDED_ARG) {
oparg |= word.op.arg << 24;
}
}
}
Expand Down Expand Up @@ -304,7 +304,7 @@ mark_stacks(PyCodeObject *code_obj, int len)
if (next_stack == UNINITIALIZED) {
continue;
}
opcode = _Py_OPCODE(code[i]);
opcode = code[i].op.code;
switch (opcode) {
case JUMP_IF_FALSE_OR_POP:
case JUMP_IF_TRUE_OR_POP:
Expand Down Expand Up @@ -610,7 +610,7 @@ _PyFrame_GetState(PyFrameObject *frame)
if (_PyInterpreterFrame_LASTI(frame->f_frame) < 0) {
return FRAME_CREATED;
}
switch (_Py_OPCODE(*frame->f_frame->prev_instr))
switch (frame->f_frame->prev_instr->op.code)
{
case COPY_FREE_VARS:
case MAKE_CELL:
Expand Down Expand Up @@ -1092,8 +1092,8 @@ _PyFrame_OpAlreadyRan(_PyInterpreterFrame *frame, int opcode, int oparg)
for (_Py_CODEUNIT *instruction = _PyCode_CODE(frame->f_code);
instruction < frame->prev_instr; instruction++)
{
int check_opcode = _PyOpcode_Deopt[_Py_OPCODE(*instruction)];
check_oparg |= _Py_OPARG(*instruction);
int check_opcode = _PyOpcode_Deopt[instruction->op.code];
check_oparg |= instruction->op.arg;
if (check_opcode == opcode && check_oparg == oparg) {
return 1;
}
Expand All @@ -1117,7 +1117,7 @@ frame_init_get_vars(_PyInterpreterFrame *frame)
// here:
PyCodeObject *co = frame->f_code;
int lasti = _PyInterpreterFrame_LASTI(frame);
if (!(lasti < 0 && _Py_OPCODE(_PyCode_CODE(co)[0]) == COPY_FREE_VARS
if (!(lasti < 0 && _PyCode_CODE(co)->op.code == COPY_FREE_VARS
&& PyFunction_Check(frame->f_funcobj)))
{
/* Free vars are initialized */
Expand Down
10 changes: 5 additions & 5 deletions Objects/genobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,11 +332,11 @@ _PyGen_yf(PyGenObject *gen)
/* Return immediately if the frame didn't start yet. SEND
always come after LOAD_CONST: a code object should not start
with SEND */
assert(_Py_OPCODE(_PyCode_CODE(gen->gi_code)[0]) != SEND);
assert(_PyCode_CODE(gen->gi_code)[0].op.code != SEND);
return NULL;
}
_Py_CODEUNIT next = frame->prev_instr[1];
if (_Py_OPCODE(next) != RESUME || _Py_OPARG(next) < 2)
if (next.op.code != RESUME || next.op.arg < 2)
{
/* Not in a yield from */
return NULL;
Expand Down Expand Up @@ -371,9 +371,9 @@ gen_close(PyGenObject *gen, PyObject *args)
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
/* It is possible for the previous instruction to not be a
* YIELD_VALUE if the debugger has changed the lineno. */
if (err == 0 && frame->prev_instr->opcode == YIELD_VALUE) {
assert(frame->prev_instr[1].opcode == RESUME);
int exception_handler_depth = frame->prev_instr->oparg;
if (err == 0 && frame->prev_instr[0].op.code == YIELD_VALUE) {
assert(frame->prev_instr[1].op.code == RESUME);
int exception_handler_depth = frame->prev_instr[0].op.code;
assert(exception_handler_depth > 0);
/* We can safely ignore the outermost try block
* as it automatically generated to handle
Expand Down
4 changes: 2 additions & 2 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -9507,8 +9507,8 @@ super_init_without_args(_PyInterpreterFrame *cframe, PyCodeObject *co,
if (_PyInterpreterFrame_LASTI(cframe) >= 0) {
// MAKE_CELL and COPY_FREE_VARS have no quickened forms, so no need
// to use _PyOpcode_Deopt here:
assert(_Py_OPCODE(_PyCode_CODE(co)[0]) == MAKE_CELL ||
_Py_OPCODE(_PyCode_CODE(co)[0]) == COPY_FREE_VARS);
assert(_PyCode_CODE(co)[0].op.code == MAKE_CELL ||
_PyCode_CODE(co)[0].op.code == COPY_FREE_VARS);
assert(PyCell_Check(firstarg));
firstarg = PyCell_GET(firstarg);
}
Expand Down
34 changes: 17 additions & 17 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,9 +246,9 @@ dummy_func(
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
_Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP];
assert(_Py_OPCODE(true_next) == STORE_FAST ||
_Py_OPCODE(true_next) == STORE_FAST__LOAD_FAST);
PyObject **target_local = &GETLOCAL(_Py_OPARG(true_next));
assert(true_next.op.code == STORE_FAST ||
true_next.op.code == STORE_FAST__LOAD_FAST);
PyObject **target_local = &GETLOCAL(true_next.op.arg);
DEOPT_IF(*target_local != left, BINARY_OP);
STAT_INC(BINARY_OP, hit);
/* Handle `left = left + right` or `left += right` for str.
Expand Down Expand Up @@ -1748,10 +1748,10 @@ dummy_func(
Py_DECREF(left);
Py_DECREF(right);
ERROR_IF(cond == NULL, error);
assert(_Py_OPCODE(next_instr[1]) == POP_JUMP_IF_FALSE ||
_Py_OPCODE(next_instr[1]) == POP_JUMP_IF_TRUE);
bool jump_on_true = _Py_OPCODE(next_instr[1]) == POP_JUMP_IF_TRUE;
int offset = _Py_OPARG(next_instr[1]);
assert(next_instr[1].op.code == POP_JUMP_IF_FALSE ||
next_instr[1].op.code == POP_JUMP_IF_TRUE);
bool jump_on_true = next_instr[1].op.code == POP_JUMP_IF_TRUE;
int offset = next_instr[1].op.arg;
int err = PyObject_IsTrue(cond);
Py_DECREF(cond);
if (err < 0) {
Expand All @@ -1774,7 +1774,7 @@ dummy_func(
_Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
_Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
if (sign_ish & oparg) {
int offset = _Py_OPARG(next_instr[1]);
int offset = next_instr[1].op.arg;
JUMPBY(offset);
}
}
Expand All @@ -1795,7 +1795,7 @@ dummy_func(
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
if (sign_ish & oparg) {
int offset = _Py_OPARG(next_instr[1]);
int offset = next_instr[1].op.arg;
JUMPBY(offset);
}
}
Expand All @@ -1814,7 +1814,7 @@ dummy_func(
assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS);
assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS);
if ((res + COMPARISON_NOT_EQUALS) & oparg) {
int offset = _Py_OPARG(next_instr[1]);
int offset = next_instr[1].op.arg;
JUMPBY(offset);
}
}
Expand Down Expand Up @@ -2122,7 +2122,7 @@ dummy_func(
_PyErr_Clear(tstate);
}
/* iterator ended normally */
assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg]) == END_FOR);
assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR);
Py_DECREF(iter);
STACK_SHRINK(1);
/* Jump forward oparg, then skip following END_FOR instruction */
Expand Down Expand Up @@ -2186,7 +2186,7 @@ dummy_func(
DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER);
STAT_INC(FOR_ITER, hit);
_Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER];
assert(_PyOpcode_Deopt[_Py_OPCODE(next)] == STORE_FAST);
assert(_PyOpcode_Deopt[next.op.code] == STORE_FAST);
if (r->len <= 0) {
STACK_SHRINK(1);
Py_DECREF(r);
Expand All @@ -2197,7 +2197,7 @@ dummy_func(
long value = r->start;
r->start = value + r->step;
r->len--;
if (_PyLong_AssignValue(&GETLOCAL(_Py_OPARG(next)), value) < 0) {
if (_PyLong_AssignValue(&GETLOCAL(next.op.arg), value) < 0) {
goto error;
}
// The STORE_FAST is already done.
Expand All @@ -2220,7 +2220,7 @@ dummy_func(
gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg);
assert(_Py_OPCODE(*next_instr) == END_FOR);
assert(next_instr->op.code == END_FOR);
DISPATCH_INLINED(gen_frame);
}

Expand Down Expand Up @@ -2809,7 +2809,7 @@ dummy_func(
STACK_SHRINK(3);
// CALL + POP_TOP
JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1);
assert(_Py_OPCODE(next_instr[-1]) == POP_TOP);
assert(next_instr[-1].op.code == POP_TOP);
DISPATCH();
}

Expand Down Expand Up @@ -3118,8 +3118,8 @@ dummy_func(
inst(EXTENDED_ARG, (--)) {
assert(oparg);
assert(cframe.use_tracing == 0);
opcode = _Py_OPCODE(*next_instr);
oparg = oparg << 8 | _Py_OPARG(*next_instr);
opcode = next_instr->op.code;
oparg = oparg << 8 | next_instr->op.arg;
PRE_DISPATCH_GOTO();
DISPATCH_GOTO();
}
Expand Down
12 changes: 6 additions & 6 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ lltrace_instruction(_PyInterpreterFrame *frame,
objects enters the interpreter recursively. It is also slow.
So you might want to comment it out. */
dump_stack(frame, stack_pointer);
int oparg = _Py_OPARG(*next_instr);
int opcode = _Py_OPCODE(*next_instr);
int oparg = next_instr->op.arg;
int opcode = next_instr->op.code;
const char *opname = _PyOpcode_OpName[opcode];
assert(opname != NULL);
int offset = (int)(next_instr - _PyCode_CODE(frame->f_code));
Expand Down Expand Up @@ -920,8 +920,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
// CPython hasn't ever traced the instruction after an EXTENDED_ARG.
// Inline the EXTENDED_ARG here, so we can avoid branching there:
INSTRUCTION_START(EXTENDED_ARG);
opcode = _Py_OPCODE(*next_instr);
oparg = oparg << 8 | _Py_OPARG(*next_instr);
opcode = next_instr->op.code;
oparg = oparg << 8 | next_instr->op.arg;
// Make sure the next instruction isn't a RESUME, since that needs
// to trace properly (and shouldn't have an EXTENDED_ARG, anyways):
assert(opcode != RESUME);
Expand All @@ -946,7 +946,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
#endif
/* Tell C compilers not to hold the opcode variable in the loop.
next_instr points the current instruction without TARGET(). */
opcode = _Py_OPCODE(*next_instr);
opcode = next_instr->op.code;
_PyErr_Format(tstate, PyExc_SystemError,
"%U:%d: unknown opcode %d",
frame->f_code->co_filename,
Expand Down Expand Up @@ -2196,7 +2196,7 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
(_PyInterpreterFrame_LASTI(frame) < instr_prev &&
// SEND has no quickened forms, so no need to use _PyOpcode_Deopt
// here:
_Py_OPCODE(*frame->prev_instr) != SEND);
frame->prev_instr->op.code != SEND);
if (trace) {
result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None);
}
Expand Down
18 changes: 9 additions & 9 deletions Python/ceval_macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@

#define DISPATCH_SAME_OPARG() \
{ \
opcode = _Py_OPCODE(*next_instr); \
opcode = next_instr->op.code; \
PRE_DISPATCH_GOTO(); \
opcode |= cframe.use_tracing OR_DTRACE_LINE; \
DISPATCH_GOTO(); \
Expand Down Expand Up @@ -143,8 +143,8 @@ GETITEM(PyObject *v, Py_ssize_t i) {
#define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(frame->f_code)))
#define NEXTOPARG() do { \
_Py_CODEUNIT word = *next_instr; \
opcode = _Py_OPCODE(word); \
oparg = _Py_OPARG(word); \
opcode = word.op.code; \
oparg = word.op.arg; \
} while (0)
#define JUMPTO(x) (next_instr = _PyCode_CODE(frame->f_code) + (x))
#define JUMPBY(x) (next_instr += (x))
Expand Down Expand Up @@ -180,14 +180,14 @@ GETITEM(PyObject *v, Py_ssize_t i) {
#if USE_COMPUTED_GOTOS
#define PREDICT(op) if (0) goto PREDICT_ID(op)
#else
#define PREDICT(op) \
#define PREDICT(next_op) \
do { \
_Py_CODEUNIT word = *next_instr; \
opcode = _Py_OPCODE(word) | cframe.use_tracing OR_DTRACE_LINE; \
if (opcode == op) { \
oparg = _Py_OPARG(word); \
INSTRUCTION_START(op); \
goto PREDICT_ID(op); \
opcode = word.op.code | cframe.use_tracing OR_DTRACE_LINE; \
if (opcode == next_op) { \
oparg = word.op.arg; \
INSTRUCTION_START(next_op); \
goto PREDICT_ID(next_op); \
} \
} while(0)
#endif
Expand Down
Loading

0 comments on commit a99eb5c

Please sign in to comment.