Skip to content

Commit 6997e77

Browse files
authored
GH-100222: Redefine _Py_CODEUNIT as a union to clarify structure of code unit. (GH-100223)
1 parent 985a710 commit 6997e77

File tree

9 files changed

+151
-135
lines changed

9 files changed

+151
-135
lines changed

Include/cpython/code.h

+17-14
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,24 @@ extern "C" {
1616
* 2**32 - 1, rather than INT_MAX.
1717
*/
1818

19-
typedef uint16_t _Py_CODEUNIT;
20-
21-
#ifdef WORDS_BIGENDIAN
22-
# define _Py_OPCODE(word) ((word) >> 8)
23-
# define _Py_OPARG(word) ((word) & 255)
24-
# define _Py_MAKECODEUNIT(opcode, oparg) (((opcode)<<8)|(oparg))
25-
#else
26-
# define _Py_OPCODE(word) ((word) & 255)
27-
# define _Py_OPARG(word) ((word) >> 8)
28-
# define _Py_MAKECODEUNIT(opcode, oparg) ((opcode)|((oparg)<<8))
29-
#endif
19+
typedef union {
20+
uint16_t cache;
21+
struct {
22+
uint8_t opcode;
23+
uint8_t oparg;
24+
};
25+
} _Py_CODEUNIT;
26+
27+
#define _Py_OPCODE(word) ((word).opcode)
28+
#define _Py_OPARG(word) ((word).oparg)
29+
30+
static inline void
31+
_py_set_opocde(_Py_CODEUNIT *word, uint8_t opcode)
32+
{
33+
word->opcode = opcode;
34+
}
3035

31-
// Use "unsigned char" instead of "uint8_t" here to avoid illegal aliasing:
32-
#define _Py_SET_OPCODE(word, opcode) \
33-
do { ((unsigned char *)&(word))[0] = (opcode); } while (0)
36+
#define _Py_SET_OPCODE(word, opcode) _py_set_opocde(&(word), opcode)
3437

3538
typedef struct {
3639
PyObject *_co_code;

Include/internal/pycore_code.h

+24-24
Original file line numberDiff line numberDiff line change
@@ -18,53 +18,53 @@ extern "C" {
1818
#define CACHE_ENTRIES(cache) (sizeof(cache)/sizeof(_Py_CODEUNIT))
1919

2020
typedef struct {
21-
_Py_CODEUNIT counter;
22-
_Py_CODEUNIT index;
23-
_Py_CODEUNIT module_keys_version[2];
24-
_Py_CODEUNIT builtin_keys_version;
21+
uint16_t counter;
22+
uint16_t index;
23+
uint16_t module_keys_version[2];
24+
uint16_t builtin_keys_version;
2525
} _PyLoadGlobalCache;
2626

2727
#define INLINE_CACHE_ENTRIES_LOAD_GLOBAL CACHE_ENTRIES(_PyLoadGlobalCache)
2828

2929
typedef struct {
30-
_Py_CODEUNIT counter;
30+
uint16_t counter;
3131
} _PyBinaryOpCache;
3232

3333
#define INLINE_CACHE_ENTRIES_BINARY_OP CACHE_ENTRIES(_PyBinaryOpCache)
3434

3535
typedef struct {
36-
_Py_CODEUNIT counter;
36+
uint16_t counter;
3737
} _PyUnpackSequenceCache;
3838

3939
#define INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE \
4040
CACHE_ENTRIES(_PyUnpackSequenceCache)
4141

4242
typedef struct {
43-
_Py_CODEUNIT counter;
44-
_Py_CODEUNIT mask;
43+
uint16_t counter;
44+
uint16_t mask;
4545
} _PyCompareOpCache;
4646

4747
#define INLINE_CACHE_ENTRIES_COMPARE_OP CACHE_ENTRIES(_PyCompareOpCache)
4848

4949
typedef struct {
50-
_Py_CODEUNIT counter;
51-
_Py_CODEUNIT type_version[2];
52-
_Py_CODEUNIT func_version;
50+
uint16_t counter;
51+
uint16_t type_version[2];
52+
uint16_t func_version;
5353
} _PyBinarySubscrCache;
5454

5555
#define INLINE_CACHE_ENTRIES_BINARY_SUBSCR CACHE_ENTRIES(_PyBinarySubscrCache)
5656

5757
typedef struct {
58-
_Py_CODEUNIT counter;
59-
_Py_CODEUNIT version[2];
60-
_Py_CODEUNIT index;
58+
uint16_t counter;
59+
uint16_t version[2];
60+
uint16_t index;
6161
} _PyAttrCache;
6262

6363
typedef struct {
64-
_Py_CODEUNIT counter;
65-
_Py_CODEUNIT type_version[2];
66-
_Py_CODEUNIT keys_version[2];
67-
_Py_CODEUNIT descr[4];
64+
uint16_t counter;
65+
uint16_t type_version[2];
66+
uint16_t keys_version[2];
67+
uint16_t descr[4];
6868
} _PyLoadMethodCache;
6969

7070

@@ -74,21 +74,21 @@ typedef struct {
7474
#define INLINE_CACHE_ENTRIES_STORE_ATTR CACHE_ENTRIES(_PyAttrCache)
7575

7676
typedef struct {
77-
_Py_CODEUNIT counter;
78-
_Py_CODEUNIT func_version[2];
79-
_Py_CODEUNIT min_args;
77+
uint16_t counter;
78+
uint16_t func_version[2];
79+
uint16_t min_args;
8080
} _PyCallCache;
8181

8282
#define INLINE_CACHE_ENTRIES_CALL CACHE_ENTRIES(_PyCallCache)
8383

8484
typedef struct {
85-
_Py_CODEUNIT counter;
85+
uint16_t counter;
8686
} _PyStoreSubscrCache;
8787

8888
#define INLINE_CACHE_ENTRIES_STORE_SUBSCR CACHE_ENTRIES(_PyStoreSubscrCache)
8989

9090
typedef struct {
91-
_Py_CODEUNIT counter;
91+
uint16_t counter;
9292
} _PyForIterCache;
9393

9494
#define INLINE_CACHE_ENTRIES_FOR_ITER CACHE_ENTRIES(_PyForIterCache)
@@ -409,7 +409,7 @@ write_location_entry_start(uint8_t *ptr, int code, int length)
409409
static inline uint16_t
410410
adaptive_counter_bits(int value, int backoff) {
411411
return (value << ADAPTIVE_BACKOFF_BITS) |
412-
(backoff & ((1<<ADAPTIVE_BACKOFF_BITS)-1));
412+
(backoff & ((1<<ADAPTIVE_BACKOFF_BITS)-1));
413413
}
414414

415415
static inline uint16_t
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Redefine the ``_Py_CODEUNIT`` typedef as a union to describe its layout to
2+
the C compiler, avoiding type punning and improving clarity.

Objects/codeobject.c

+6-5
Original file line numberDiff line numberDiff line change
@@ -1520,9 +1520,10 @@ deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len)
15201520
_Py_CODEUNIT instruction = instructions[i];
15211521
int opcode = _PyOpcode_Deopt[_Py_OPCODE(instruction)];
15221522
int caches = _PyOpcode_Caches[opcode];
1523-
instructions[i] = _Py_MAKECODEUNIT(opcode, _Py_OPARG(instruction));
1523+
instructions[i].opcode = opcode;
15241524
while (caches--) {
1525-
instructions[++i] = _Py_MAKECODEUNIT(CACHE, 0);
1525+
instructions[++i].opcode = CACHE;
1526+
instructions[i].oparg = 0;
15261527
}
15271528
}
15281529
}
@@ -1775,9 +1776,9 @@ code_richcompare(PyObject *self, PyObject *other, int op)
17751776
for (int i = 0; i < Py_SIZE(co); i++) {
17761777
_Py_CODEUNIT co_instr = _PyCode_CODE(co)[i];
17771778
_Py_CODEUNIT cp_instr = _PyCode_CODE(cp)[i];
1778-
_Py_SET_OPCODE(co_instr, _PyOpcode_Deopt[_Py_OPCODE(co_instr)]);
1779-
_Py_SET_OPCODE(cp_instr, _PyOpcode_Deopt[_Py_OPCODE(cp_instr)]);
1780-
eq = co_instr == cp_instr;
1779+
co_instr.opcode = _PyOpcode_Deopt[_Py_OPCODE(co_instr)];
1780+
cp_instr.opcode =_PyOpcode_Deopt[_Py_OPCODE(cp_instr)];
1781+
eq = co_instr.cache == cp_instr.cache;
17811782
if (!eq) {
17821783
goto unequal;
17831784
}

Python/ceval.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
864864
STAT_INC(opcode, miss); \
865865
STAT_INC((INSTNAME), miss); \
866866
/* The counter is always the first cache entry: */ \
867-
if (ADAPTIVE_COUNTER_IS_ZERO(*next_instr)) { \
867+
if (ADAPTIVE_COUNTER_IS_ZERO(next_instr->cache)) { \
868868
STAT_INC((INSTNAME), deopt); \
869869
} \
870870
else { \
@@ -1289,7 +1289,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
12891289
}
12901290
opcode = _PyOpcode_Deopt[opcode];
12911291
if (_PyOpcode_Caches[opcode]) {
1292-
_Py_CODEUNIT *counter = &next_instr[1];
1292+
uint16_t *counter = &next_instr[1].cache;
12931293
// The instruction is going to decrement the counter, so we need to
12941294
// increment it here to make sure it doesn't try to specialize:
12951295
if (!ADAPTIVE_COUNTER_IS_MAX(*counter)) {

Python/compile.c

+15-5
Original file line numberDiff line numberDiff line change
@@ -263,22 +263,32 @@ write_instr(_Py_CODEUNIT *codestr, struct instr *instruction, int ilen)
263263
int caches = _PyOpcode_Caches[opcode];
264264
switch (ilen - caches) {
265265
case 4:
266-
*codestr++ = _Py_MAKECODEUNIT(EXTENDED_ARG, (oparg >> 24) & 0xFF);
266+
codestr->opcode = EXTENDED_ARG;
267+
codestr->oparg = (oparg >> 24) & 0xFF;
268+
codestr++;
267269
/* fall through */
268270
case 3:
269-
*codestr++ = _Py_MAKECODEUNIT(EXTENDED_ARG, (oparg >> 16) & 0xFF);
271+
codestr->opcode = EXTENDED_ARG;
272+
codestr->oparg = (oparg >> 16) & 0xFF;
273+
codestr++;
270274
/* fall through */
271275
case 2:
272-
*codestr++ = _Py_MAKECODEUNIT(EXTENDED_ARG, (oparg >> 8) & 0xFF);
276+
codestr->opcode = EXTENDED_ARG;
277+
codestr->oparg = (oparg >> 8) & 0xFF;
278+
codestr++;
273279
/* fall through */
274280
case 1:
275-
*codestr++ = _Py_MAKECODEUNIT(opcode, oparg & 0xFF);
281+
codestr->opcode = opcode;
282+
codestr->oparg = oparg & 0xFF;
283+
codestr++;
276284
break;
277285
default:
278286
Py_UNREACHABLE();
279287
}
280288
while (caches--) {
281-
*codestr++ = _Py_MAKECODEUNIT(CACHE, 0);
289+
codestr->opcode = CACHE;
290+
codestr->oparg = 0;
291+
codestr++;
282292
}
283293
}
284294

Python/generated_cases.c.h

+13-13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)