Skip to content

Commit 997ba5d

Browse files
authored
bpo-47172: Compiler enhancements (GH-32200)
* Make virtual opcodes negative. * Make is_jump detect only actual jumps. * Use is_block_push for the exception block setup opcodes.
1 parent 04e07c2 commit 997ba5d

File tree

1 file changed

+41
-36
lines changed

1 file changed

+41
-36
lines changed

Python/compile.c

+41-36
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,26 @@
7272

7373
/* Pseudo-instructions used in the compiler,
7474
* but turned into NOPs by the assembler. */
75-
#define SETUP_FINALLY 255
76-
#define SETUP_CLEANUP 254
77-
#define SETUP_WITH 253
78-
#define POP_BLOCK 252
79-
#define JUMP 251
75+
#define SETUP_FINALLY -1
76+
#define SETUP_CLEANUP -2
77+
#define SETUP_WITH -3
78+
#define POP_BLOCK -4
79+
#define JUMP -5
80+
81+
#define MIN_VIRTUAL_OPCODE -5
82+
#define MAX_ALLOWED_OPCODE 254
83+
84+
#define IS_WITHIN_OPCODE_RANGE(opcode) \
85+
((opcode) >= MIN_VIRTUAL_OPCODE && (opcode) <= MAX_ALLOWED_OPCODE)
86+
87+
#define IS_VIRTUAL_OPCODE(opcode) ((opcode) < 0)
8088

8189
#define IS_TOP_LEVEL_AWAIT(c) ( \
8290
(c->c_flags->cf_flags & PyCF_ALLOW_TOP_LEVEL_AWAIT) \
8391
&& (c->u->u_ste->ste_type == ModuleBlock))
8492

8593
struct instr {
86-
unsigned char i_opcode;
94+
int i_opcode;
8795
int i_oparg;
8896
/* target block (if jump instruction) */
8997
struct basicblock_ *i_target;
@@ -115,8 +123,13 @@ is_bit_set_in_table(const uint32_t *table, int bitindex) {
115123
* Word is indexed by (bitindex>>ln(size of int in bits)).
116124
* Bit within word is the low bits of bitindex.
117125
*/
118-
uint32_t word = table[bitindex >> LOG_BITS_PER_INT];
119-
return (word >> (bitindex & MASK_LOW_LOG_BITS)) & 1;
126+
if (bitindex >= 0 && bitindex < 256) {
127+
uint32_t word = table[bitindex >> LOG_BITS_PER_INT];
128+
return (word >> (bitindex & MASK_LOW_LOG_BITS)) & 1;
129+
}
130+
else {
131+
return 0;
132+
}
120133
}
121134

122135
static inline int
@@ -125,18 +138,25 @@ is_relative_jump(struct instr *i)
125138
return is_bit_set_in_table(_PyOpcode_RelativeJump, i->i_opcode);
126139
}
127140

141+
static inline int
142+
is_block_push(struct instr *instr)
143+
{
144+
int opcode = instr->i_opcode;
145+
return opcode == SETUP_FINALLY || opcode == SETUP_WITH || opcode == SETUP_CLEANUP;
146+
}
147+
128148
static inline int
129149
is_jump(struct instr *i)
130150
{
131-
return i->i_opcode >= SETUP_WITH ||
132-
i->i_opcode == JUMP ||
151+
return i->i_opcode == JUMP ||
133152
is_bit_set_in_table(_PyOpcode_Jump, i->i_opcode);
134153
}
135154

136155
static int
137156
instr_size(struct instr *instruction)
138157
{
139158
int opcode = instruction->i_opcode;
159+
assert(!IS_VIRTUAL_OPCODE(opcode));
140160
int oparg = HAS_ARG(opcode) ? instruction->i_oparg : 0;
141161
int extended_args = (0xFFFFFF < oparg) + (0xFFFF < oparg) + (0xFF < oparg);
142162
int caches = _PyOpcode_Caches[opcode];
@@ -147,6 +167,7 @@ static void
147167
write_instr(_Py_CODEUNIT *codestr, struct instr *instruction, int ilen)
148168
{
149169
int opcode = instruction->i_opcode;
170+
assert(!IS_VIRTUAL_OPCODE(opcode));
150171
int oparg = HAS_ARG(opcode) ? instruction->i_oparg : 0;
151172
int caches = _PyOpcode_Caches[opcode];
152173
switch (ilen - caches) {
@@ -1177,6 +1198,7 @@ static int
11771198
compiler_addop_line(struct compiler *c, int opcode, int line,
11781199
int end_line, int col_offset, int end_col_offset)
11791200
{
1201+
assert(IS_WITHIN_OPCODE_RANGE(opcode));
11801202
assert(!HAS_ARG(opcode) || IS_ARTIFICIAL(opcode));
11811203

11821204
if (compiler_use_new_implicit_block_if_needed(c) < 0) {
@@ -1419,6 +1441,7 @@ compiler_addop_i_line(struct compiler *c, int opcode, Py_ssize_t oparg,
14191441
The argument of a concrete bytecode instruction is limited to 8-bit.
14201442
EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */
14211443

1444+
assert(IS_WITHIN_OPCODE_RANGE(opcode));
14221445
assert(HAS_ARG(opcode));
14231446
assert(0 <= oparg && oparg <= 2147483647);
14241447

@@ -1462,7 +1485,8 @@ static int add_jump_to_block(struct compiler *c, int opcode,
14621485
int col_offset, int end_col_offset,
14631486
basicblock *target)
14641487
{
1465-
assert(HAS_ARG(opcode));
1488+
assert(IS_WITHIN_OPCODE_RANGE(opcode));
1489+
assert(HAS_ARG(opcode) || IS_VIRTUAL_OPCODE(opcode));
14661490
assert(target != NULL);
14671491

14681492
if (compiler_use_new_implicit_block_if_needed(c) < 0) {
@@ -7040,7 +7064,7 @@ stackdepth(struct compiler *c)
70407064
maxdepth = new_depth;
70417065
}
70427066
assert(depth >= 0); /* invalid code or bug in stackdepth() */
7043-
if (is_jump(instr)) {
7067+
if (is_jump(instr) || is_block_push(instr)) {
70447068
effect = stack_effect(instr->i_opcode, instr->i_oparg, 1);
70457069
assert(effect != PY_INVALID_STACK_EFFECT);
70467070
int target_depth = depth + effect;
@@ -7159,13 +7183,6 @@ assemble_emit_table_pair(struct assembler* a, PyObject** table, int* offset,
71597183
return 1;
71607184
}
71617185

7162-
static int
7163-
is_block_push(struct instr *instr)
7164-
{
7165-
int opcode = instr->i_opcode;
7166-
return opcode == SETUP_FINALLY || opcode == SETUP_WITH || opcode == SETUP_CLEANUP;
7167-
}
7168-
71697186
static basicblock *
71707187
push_except_block(ExceptStack *stack, struct instr *setup) {
71717188
assert(is_block_push(setup));
@@ -8600,6 +8617,7 @@ apply_static_swaps(basicblock *block, int i)
86008617
static bool
86018618
jump_thread(struct instr *inst, struct instr *target, int opcode)
86028619
{
8620+
assert(!IS_VIRTUAL_OPCODE(opcode) || opcode == JUMP);
86038621
assert(is_jump(inst));
86048622
assert(is_jump(target));
86058623
// bpo-45773: If inst->i_target == target->i_target, then nothing actually
@@ -8629,7 +8647,7 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
86298647
struct instr *inst = &bb->b_instr[i];
86308648
int oparg = inst->i_oparg;
86318649
int nextop = i+1 < bb->b_iused ? bb->b_instr[i+1].i_opcode : 0;
8632-
if (is_jump(inst)) {
8650+
if (is_jump(inst) || is_block_push(inst)) {
86338651
/* Skip over empty basic blocks. */
86348652
while (inst->i_target->b_iused == 0) {
86358653
inst->i_target = inst->i_target->b_next;
@@ -8996,8 +9014,9 @@ mark_reachable(struct assembler *a) {
89969014
}
89979015
for (int i = 0; i < b->b_iused; i++) {
89989016
basicblock *target;
8999-
if (is_jump(&b->b_instr[i])) {
9000-
target = b->b_instr[i].i_target;
9017+
struct instr *instr = &b->b_instr[i];
9018+
if (is_jump(instr) || is_block_push(instr)) {
9019+
target = instr->i_target;
90019020
if (target->b_predecessors == 0) {
90029021
*sp++ = target;
90039022
}
@@ -9073,13 +9092,6 @@ propagate_line_numbers(struct assembler *a) {
90739092
}
90749093
}
90759094
if (is_jump(&b->b_instr[b->b_iused-1])) {
9076-
switch (b->b_instr[b->b_iused-1].i_opcode) {
9077-
/* Note: Only actual jumps, not exception handlers */
9078-
case SETUP_WITH:
9079-
case SETUP_FINALLY:
9080-
case SETUP_CLEANUP:
9081-
continue;
9082-
}
90839095
basicblock *target = b->b_instr[b->b_iused-1].i_target;
90849096
if (target->b_predecessors == 1) {
90859097
if (target->b_instr[0].i_lineno < 0) {
@@ -9205,13 +9217,6 @@ duplicate_exits_without_lineno(struct compiler *c)
92059217
*/
92069218
for (basicblock *b = c->u->u_blocks; b != NULL; b = b->b_list) {
92079219
if (b->b_iused > 0 && is_jump(&b->b_instr[b->b_iused-1])) {
9208-
switch (b->b_instr[b->b_iused-1].i_opcode) {
9209-
/* Note: Only actual jumps, not exception handlers */
9210-
case SETUP_WITH:
9211-
case SETUP_FINALLY:
9212-
case SETUP_CLEANUP:
9213-
continue;
9214-
}
92159220
basicblock *target = b->b_instr[b->b_iused-1].i_target;
92169221
if (is_exit_without_lineno(target) && target->b_predecessors > 1) {
92179222
basicblock *new_target = compiler_copy_block(c, target);

0 commit comments

Comments
 (0)