Skip to content

Commit a99eb5c

Browse files
authored
gh-101907: Stop using _Py_OPCODE and _Py_OPARG macros (GH-101912)
* gh-101907: Removes use of non-standard C++ extension from Include/cpython/code.h * Make cases_generator correct on Windows
1 parent c00faf7 commit a99eb5c

File tree

13 files changed

+200
-184
lines changed

13 files changed

+200
-184
lines changed

Include/cpython/code.h

+21-7
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,35 @@ extern "C" {
1919
typedef union {
2020
uint16_t cache;
2121
struct {
22-
uint8_t opcode;
23-
uint8_t oparg;
24-
};
22+
uint8_t code;
23+
uint8_t arg;
24+
} op;
2525
} _Py_CODEUNIT;
2626

27-
#define _Py_OPCODE(word) ((word).opcode)
28-
#define _Py_OPARG(word) ((word).oparg)
27+
28+
/* These macros only remain defined for compatibility. */
29+
#define _Py_OPCODE(word) ((word).op.code)
30+
#define _Py_OPARG(word) ((word).op.arg)
31+
32+
static inline _Py_CODEUNIT
33+
_py_make_codeunit(uint8_t opcode, uint8_t oparg)
34+
{
35+
// No designated initialisers because of C++ compat
36+
_Py_CODEUNIT word;
37+
word.op.code = opcode;
38+
word.op.arg = oparg;
39+
return word;
40+
}
2941

3042
static inline void
3143
_py_set_opcode(_Py_CODEUNIT *word, uint8_t opcode)
3244
{
33-
word->opcode = opcode;
45+
word->op.code = opcode;
3446
}
3547

36-
#define _Py_SET_OPCODE(word, opcode) _py_set_opocde(&(word), opcode)
48+
#define _Py_MAKE_CODEUNIT(opcode, oparg) _py_make_codeunit((opcode), (oparg))
49+
#define _Py_SET_OPCODE(word, opcode) _py_set_opcode(&(word), (opcode))
50+
3751

3852
typedef struct {
3953
PyObject *_co_code;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Removes use of non-standard C++ extension in public header files.

Objects/codeobject.c

+10-10
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
413413
PyBytes_GET_SIZE(con->code));
414414
int entry_point = 0;
415415
while (entry_point < Py_SIZE(co) &&
416-
_Py_OPCODE(_PyCode_CODE(co)[entry_point]) != RESUME) {
416+
_PyCode_CODE(co)[entry_point].op.code != RESUME) {
417417
entry_point++;
418418
}
419419
co->_co_firsttraceable = entry_point;
@@ -1505,12 +1505,12 @@ deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len)
15051505
{
15061506
for (int i = 0; i < len; i++) {
15071507
_Py_CODEUNIT instruction = instructions[i];
1508-
int opcode = _PyOpcode_Deopt[_Py_OPCODE(instruction)];
1508+
int opcode = _PyOpcode_Deopt[instruction.op.code];
15091509
int caches = _PyOpcode_Caches[opcode];
1510-
instructions[i].opcode = opcode;
1510+
instructions[i].op.code = opcode;
15111511
while (caches--) {
1512-
instructions[++i].opcode = CACHE;
1513-
instructions[i].oparg = 0;
1512+
instructions[++i].op.code = CACHE;
1513+
instructions[i].op.arg = 0;
15141514
}
15151515
}
15161516
}
@@ -1763,13 +1763,13 @@ code_richcompare(PyObject *self, PyObject *other, int op)
17631763
for (int i = 0; i < Py_SIZE(co); i++) {
17641764
_Py_CODEUNIT co_instr = _PyCode_CODE(co)[i];
17651765
_Py_CODEUNIT cp_instr = _PyCode_CODE(cp)[i];
1766-
co_instr.opcode = _PyOpcode_Deopt[_Py_OPCODE(co_instr)];
1767-
cp_instr.opcode =_PyOpcode_Deopt[_Py_OPCODE(cp_instr)];
1766+
co_instr.op.code = _PyOpcode_Deopt[co_instr.op.code];
1767+
cp_instr.op.code = _PyOpcode_Deopt[cp_instr.op.code];
17681768
eq = co_instr.cache == cp_instr.cache;
17691769
if (!eq) {
17701770
goto unequal;
17711771
}
1772-
i += _PyOpcode_Caches[_Py_OPCODE(co_instr)];
1772+
i += _PyOpcode_Caches[co_instr.op.code];
17731773
}
17741774

17751775
/* compare constants */
@@ -1848,9 +1848,9 @@ code_hash(PyCodeObject *co)
18481848
SCRAMBLE_IN(co->co_firstlineno);
18491849
SCRAMBLE_IN(Py_SIZE(co));
18501850
for (int i = 0; i < Py_SIZE(co); i++) {
1851-
int deop = _PyOpcode_Deopt[_Py_OPCODE(_PyCode_CODE(co)[i])];
1851+
int deop = _PyOpcode_Deopt[_PyCode_CODE(co)[i].op.code];
18521852
SCRAMBLE_IN(deop);
1853-
SCRAMBLE_IN(_Py_OPARG(_PyCode_CODE(co)[i]));
1853+
SCRAMBLE_IN(_PyCode_CODE(co)[i].op.arg);
18541854
i += _PyOpcode_Caches[deop];
18551855
}
18561856
if ((Py_hash_t)uhash == -1) {

Objects/frameobject.c

+12-12
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,13 @@ static unsigned int
111111
get_arg(const _Py_CODEUNIT *codestr, Py_ssize_t i)
112112
{
113113
_Py_CODEUNIT word;
114-
unsigned int oparg = _Py_OPARG(codestr[i]);
115-
if (i >= 1 && _Py_OPCODE(word = codestr[i-1]) == EXTENDED_ARG) {
116-
oparg |= _Py_OPARG(word) << 8;
117-
if (i >= 2 && _Py_OPCODE(word = codestr[i-2]) == EXTENDED_ARG) {
118-
oparg |= _Py_OPARG(word) << 16;
119-
if (i >= 3 && _Py_OPCODE(word = codestr[i-3]) == EXTENDED_ARG) {
120-
oparg |= _Py_OPARG(word) << 24;
114+
unsigned int oparg = codestr[i].op.arg;
115+
if (i >= 1 && (word = codestr[i-1]).op.code == EXTENDED_ARG) {
116+
oparg |= word.op.arg << 8;
117+
if (i >= 2 && (word = codestr[i-2]).op.code == EXTENDED_ARG) {
118+
oparg |= word.op.arg << 16;
119+
if (i >= 3 && (word = codestr[i-3]).op.code == EXTENDED_ARG) {
120+
oparg |= word.op.arg << 24;
121121
}
122122
}
123123
}
@@ -304,7 +304,7 @@ mark_stacks(PyCodeObject *code_obj, int len)
304304
if (next_stack == UNINITIALIZED) {
305305
continue;
306306
}
307-
opcode = _Py_OPCODE(code[i]);
307+
opcode = code[i].op.code;
308308
switch (opcode) {
309309
case JUMP_IF_FALSE_OR_POP:
310310
case JUMP_IF_TRUE_OR_POP:
@@ -610,7 +610,7 @@ _PyFrame_GetState(PyFrameObject *frame)
610610
if (_PyInterpreterFrame_LASTI(frame->f_frame) < 0) {
611611
return FRAME_CREATED;
612612
}
613-
switch (_Py_OPCODE(*frame->f_frame->prev_instr))
613+
switch (frame->f_frame->prev_instr->op.code)
614614
{
615615
case COPY_FREE_VARS:
616616
case MAKE_CELL:
@@ -1092,8 +1092,8 @@ _PyFrame_OpAlreadyRan(_PyInterpreterFrame *frame, int opcode, int oparg)
10921092
for (_Py_CODEUNIT *instruction = _PyCode_CODE(frame->f_code);
10931093
instruction < frame->prev_instr; instruction++)
10941094
{
1095-
int check_opcode = _PyOpcode_Deopt[_Py_OPCODE(*instruction)];
1096-
check_oparg |= _Py_OPARG(*instruction);
1095+
int check_opcode = _PyOpcode_Deopt[instruction->op.code];
1096+
check_oparg |= instruction->op.arg;
10971097
if (check_opcode == opcode && check_oparg == oparg) {
10981098
return 1;
10991099
}
@@ -1117,7 +1117,7 @@ frame_init_get_vars(_PyInterpreterFrame *frame)
11171117
// here:
11181118
PyCodeObject *co = frame->f_code;
11191119
int lasti = _PyInterpreterFrame_LASTI(frame);
1120-
if (!(lasti < 0 && _Py_OPCODE(_PyCode_CODE(co)[0]) == COPY_FREE_VARS
1120+
if (!(lasti < 0 && _PyCode_CODE(co)->op.code == COPY_FREE_VARS
11211121
&& PyFunction_Check(frame->f_funcobj)))
11221122
{
11231123
/* Free vars are initialized */

Objects/genobject.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -332,11 +332,11 @@ _PyGen_yf(PyGenObject *gen)
332332
/* Return immediately if the frame didn't start yet. SEND
333333
always come after LOAD_CONST: a code object should not start
334334
with SEND */
335-
assert(_Py_OPCODE(_PyCode_CODE(gen->gi_code)[0]) != SEND);
335+
assert(_PyCode_CODE(gen->gi_code)[0].op.code != SEND);
336336
return NULL;
337337
}
338338
_Py_CODEUNIT next = frame->prev_instr[1];
339-
if (_Py_OPCODE(next) != RESUME || _Py_OPARG(next) < 2)
339+
if (next.op.code != RESUME || next.op.arg < 2)
340340
{
341341
/* Not in a yield from */
342342
return NULL;
@@ -371,9 +371,9 @@ gen_close(PyGenObject *gen, PyObject *args)
371371
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
372372
/* It is possible for the previous instruction to not be a
373373
* YIELD_VALUE if the debugger has changed the lineno. */
374-
if (err == 0 && frame->prev_instr->opcode == YIELD_VALUE) {
375-
assert(frame->prev_instr[1].opcode == RESUME);
376-
int exception_handler_depth = frame->prev_instr->oparg;
374+
if (err == 0 && frame->prev_instr[0].op.code == YIELD_VALUE) {
375+
assert(frame->prev_instr[1].op.code == RESUME);
376+
int exception_handler_depth = frame->prev_instr[0].op.code;
377377
assert(exception_handler_depth > 0);
378378
/* We can safely ignore the outermost try block
379379
* as it automatically generated to handle

Objects/typeobject.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -9507,8 +9507,8 @@ super_init_without_args(_PyInterpreterFrame *cframe, PyCodeObject *co,
95079507
if (_PyInterpreterFrame_LASTI(cframe) >= 0) {
95089508
// MAKE_CELL and COPY_FREE_VARS have no quickened forms, so no need
95099509
// to use _PyOpcode_Deopt here:
9510-
assert(_Py_OPCODE(_PyCode_CODE(co)[0]) == MAKE_CELL ||
9511-
_Py_OPCODE(_PyCode_CODE(co)[0]) == COPY_FREE_VARS);
9510+
assert(_PyCode_CODE(co)[0].op.code == MAKE_CELL ||
9511+
_PyCode_CODE(co)[0].op.code == COPY_FREE_VARS);
95129512
assert(PyCell_Check(firstarg));
95139513
firstarg = PyCell_GET(firstarg);
95149514
}

Python/bytecodes.c

+17-17
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,9 @@ dummy_func(
246246
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
247247
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
248248
_Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP];
249-
assert(_Py_OPCODE(true_next) == STORE_FAST ||
250-
_Py_OPCODE(true_next) == STORE_FAST__LOAD_FAST);
251-
PyObject **target_local = &GETLOCAL(_Py_OPARG(true_next));
249+
assert(true_next.op.code == STORE_FAST ||
250+
true_next.op.code == STORE_FAST__LOAD_FAST);
251+
PyObject **target_local = &GETLOCAL(true_next.op.arg);
252252
DEOPT_IF(*target_local != left, BINARY_OP);
253253
STAT_INC(BINARY_OP, hit);
254254
/* Handle `left = left + right` or `left += right` for str.
@@ -1748,10 +1748,10 @@ dummy_func(
17481748
Py_DECREF(left);
17491749
Py_DECREF(right);
17501750
ERROR_IF(cond == NULL, error);
1751-
assert(_Py_OPCODE(next_instr[1]) == POP_JUMP_IF_FALSE ||
1752-
_Py_OPCODE(next_instr[1]) == POP_JUMP_IF_TRUE);
1753-
bool jump_on_true = _Py_OPCODE(next_instr[1]) == POP_JUMP_IF_TRUE;
1754-
int offset = _Py_OPARG(next_instr[1]);
1751+
assert(next_instr[1].op.code == POP_JUMP_IF_FALSE ||
1752+
next_instr[1].op.code == POP_JUMP_IF_TRUE);
1753+
bool jump_on_true = next_instr[1].op.code == POP_JUMP_IF_TRUE;
1754+
int offset = next_instr[1].op.arg;
17551755
int err = PyObject_IsTrue(cond);
17561756
Py_DECREF(cond);
17571757
if (err < 0) {
@@ -1774,7 +1774,7 @@ dummy_func(
17741774
_Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
17751775
_Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
17761776
if (sign_ish & oparg) {
1777-
int offset = _Py_OPARG(next_instr[1]);
1777+
int offset = next_instr[1].op.arg;
17781778
JUMPBY(offset);
17791779
}
17801780
}
@@ -1795,7 +1795,7 @@ dummy_func(
17951795
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
17961796
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
17971797
if (sign_ish & oparg) {
1798-
int offset = _Py_OPARG(next_instr[1]);
1798+
int offset = next_instr[1].op.arg;
17991799
JUMPBY(offset);
18001800
}
18011801
}
@@ -1814,7 +1814,7 @@ dummy_func(
18141814
assert((oparg & 0xf) == COMPARISON_NOT_EQUALS || (oparg & 0xf) == COMPARISON_EQUALS);
18151815
assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS);
18161816
if ((res + COMPARISON_NOT_EQUALS) & oparg) {
1817-
int offset = _Py_OPARG(next_instr[1]);
1817+
int offset = next_instr[1].op.arg;
18181818
JUMPBY(offset);
18191819
}
18201820
}
@@ -2122,7 +2122,7 @@ dummy_func(
21222122
_PyErr_Clear(tstate);
21232123
}
21242124
/* iterator ended normally */
2125-
assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg]) == END_FOR);
2125+
assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR);
21262126
Py_DECREF(iter);
21272127
STACK_SHRINK(1);
21282128
/* Jump forward oparg, then skip following END_FOR instruction */
@@ -2186,7 +2186,7 @@ dummy_func(
21862186
DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER);
21872187
STAT_INC(FOR_ITER, hit);
21882188
_Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER];
2189-
assert(_PyOpcode_Deopt[_Py_OPCODE(next)] == STORE_FAST);
2189+
assert(_PyOpcode_Deopt[next.op.code] == STORE_FAST);
21902190
if (r->len <= 0) {
21912191
STACK_SHRINK(1);
21922192
Py_DECREF(r);
@@ -2197,7 +2197,7 @@ dummy_func(
21972197
long value = r->start;
21982198
r->start = value + r->step;
21992199
r->len--;
2200-
if (_PyLong_AssignValue(&GETLOCAL(_Py_OPARG(next)), value) < 0) {
2200+
if (_PyLong_AssignValue(&GETLOCAL(next.op.arg), value) < 0) {
22012201
goto error;
22022202
}
22032203
// The STORE_FAST is already done.
@@ -2220,7 +2220,7 @@ dummy_func(
22202220
gen->gi_exc_state.previous_item = tstate->exc_info;
22212221
tstate->exc_info = &gen->gi_exc_state;
22222222
JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg);
2223-
assert(_Py_OPCODE(*next_instr) == END_FOR);
2223+
assert(next_instr->op.code == END_FOR);
22242224
DISPATCH_INLINED(gen_frame);
22252225
}
22262226

@@ -2809,7 +2809,7 @@ dummy_func(
28092809
STACK_SHRINK(3);
28102810
// CALL + POP_TOP
28112811
JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1);
2812-
assert(_Py_OPCODE(next_instr[-1]) == POP_TOP);
2812+
assert(next_instr[-1].op.code == POP_TOP);
28132813
DISPATCH();
28142814
}
28152815

@@ -3118,8 +3118,8 @@ dummy_func(
31183118
inst(EXTENDED_ARG, (--)) {
31193119
assert(oparg);
31203120
assert(cframe.use_tracing == 0);
3121-
opcode = _Py_OPCODE(*next_instr);
3122-
oparg = oparg << 8 | _Py_OPARG(*next_instr);
3121+
opcode = next_instr->op.code;
3122+
oparg = oparg << 8 | next_instr->op.arg;
31233123
PRE_DISPATCH_GOTO();
31243124
DISPATCH_GOTO();
31253125
}

Python/ceval.c

+6-6
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ lltrace_instruction(_PyInterpreterFrame *frame,
132132
objects enters the interpreter recursively. It is also slow.
133133
So you might want to comment it out. */
134134
dump_stack(frame, stack_pointer);
135-
int oparg = _Py_OPARG(*next_instr);
136-
int opcode = _Py_OPCODE(*next_instr);
135+
int oparg = next_instr->op.arg;
136+
int opcode = next_instr->op.code;
137137
const char *opname = _PyOpcode_OpName[opcode];
138138
assert(opname != NULL);
139139
int offset = (int)(next_instr - _PyCode_CODE(frame->f_code));
@@ -920,8 +920,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
920920
// CPython hasn't ever traced the instruction after an EXTENDED_ARG.
921921
// Inline the EXTENDED_ARG here, so we can avoid branching there:
922922
INSTRUCTION_START(EXTENDED_ARG);
923-
opcode = _Py_OPCODE(*next_instr);
924-
oparg = oparg << 8 | _Py_OPARG(*next_instr);
923+
opcode = next_instr->op.code;
924+
oparg = oparg << 8 | next_instr->op.arg;
925925
// Make sure the next instruction isn't a RESUME, since that needs
926926
// to trace properly (and shouldn't have an EXTENDED_ARG, anyways):
927927
assert(opcode != RESUME);
@@ -946,7 +946,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
946946
#endif
947947
/* Tell C compilers not to hold the opcode variable in the loop.
948948
next_instr points the current instruction without TARGET(). */
949-
opcode = _Py_OPCODE(*next_instr);
949+
opcode = next_instr->op.code;
950950
_PyErr_Format(tstate, PyExc_SystemError,
951951
"%U:%d: unknown opcode %d",
952952
frame->f_code->co_filename,
@@ -2196,7 +2196,7 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
21962196
(_PyInterpreterFrame_LASTI(frame) < instr_prev &&
21972197
// SEND has no quickened forms, so no need to use _PyOpcode_Deopt
21982198
// here:
2199-
_Py_OPCODE(*frame->prev_instr) != SEND);
2199+
frame->prev_instr->op.code != SEND);
22002200
if (trace) {
22012201
result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None);
22022202
}

Python/ceval_macros.h

+9-9
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100

101101
#define DISPATCH_SAME_OPARG() \
102102
{ \
103-
opcode = _Py_OPCODE(*next_instr); \
103+
opcode = next_instr->op.code; \
104104
PRE_DISPATCH_GOTO(); \
105105
opcode |= cframe.use_tracing OR_DTRACE_LINE; \
106106
DISPATCH_GOTO(); \
@@ -143,8 +143,8 @@ GETITEM(PyObject *v, Py_ssize_t i) {
143143
#define INSTR_OFFSET() ((int)(next_instr - _PyCode_CODE(frame->f_code)))
144144
#define NEXTOPARG() do { \
145145
_Py_CODEUNIT word = *next_instr; \
146-
opcode = _Py_OPCODE(word); \
147-
oparg = _Py_OPARG(word); \
146+
opcode = word.op.code; \
147+
oparg = word.op.arg; \
148148
} while (0)
149149
#define JUMPTO(x) (next_instr = _PyCode_CODE(frame->f_code) + (x))
150150
#define JUMPBY(x) (next_instr += (x))
@@ -180,14 +180,14 @@ GETITEM(PyObject *v, Py_ssize_t i) {
180180
#if USE_COMPUTED_GOTOS
181181
#define PREDICT(op) if (0) goto PREDICT_ID(op)
182182
#else
183-
#define PREDICT(op) \
183+
#define PREDICT(next_op) \
184184
do { \
185185
_Py_CODEUNIT word = *next_instr; \
186-
opcode = _Py_OPCODE(word) | cframe.use_tracing OR_DTRACE_LINE; \
187-
if (opcode == op) { \
188-
oparg = _Py_OPARG(word); \
189-
INSTRUCTION_START(op); \
190-
goto PREDICT_ID(op); \
186+
opcode = word.op.code | cframe.use_tracing OR_DTRACE_LINE; \
187+
if (opcode == next_op) { \
188+
oparg = word.op.arg; \
189+
INSTRUCTION_START(next_op); \
190+
goto PREDICT_ID(next_op); \
191191
} \
192192
} while(0)
193193
#endif

0 commit comments

Comments
 (0)