Skip to content

Commit 65b7b6b

Browse files
authored
gh-98831: Use opcode metadata for stack_effect() (#101704)
* Write output and metadata in a single run This halves the time to run the cases generator (most of the time goes into parsing the input). * Declare or define opcode metadata based on NEED_OPCODE_TABLES * Use generated metadata for stack_effect() * compile.o depends on opcode_metadata.h * Return -1 from _PyOpcode_num_popped/pushed for unknown opcode
1 parent 0e0c5d8 commit 65b7b6b

File tree

4 files changed

+88
-256
lines changed

4 files changed

+88
-256
lines changed

Makefile.pre.in

+7-10
Original file line numberDiff line numberDiff line change
@@ -1445,24 +1445,21 @@ regen-opcode-targets:
14451445

14461446
.PHONY: regen-cases
14471447
regen-cases:
1448-
# Regenerate Python/generated_cases.c.h from Python/bytecodes.c
1448+
# Regenerate Python/generated_cases.c.h
1449+
# and Python/opcode_metadata.h
1450+
# from Python/bytecodes.c
14491451
# using Tools/cases_generator/generate_cases.py
14501452
PYTHONPATH=$(srcdir)/Tools/cases_generator \
14511453
$(PYTHON_FOR_REGEN) \
14521454
$(srcdir)/Tools/cases_generator/generate_cases.py \
14531455
-i $(srcdir)/Python/bytecodes.c \
1454-
-o $(srcdir)/Python/generated_cases.c.h.new
1456+
-o $(srcdir)/Python/generated_cases.c.h.new \
1457+
-m $(srcdir)/Python/opcode_metadata.h.new
14551458
$(UPDATE_FILE) $(srcdir)/Python/generated_cases.c.h $(srcdir)/Python/generated_cases.c.h.new
1456-
# Regenerate Python/opcode_metadata.h from Python/bytecodes.c
1457-
# using Tools/cases_generator/generate_cases.py --metadata
1458-
PYTHONPATH=$(srcdir)/Tools/cases_generator \
1459-
$(PYTHON_FOR_REGEN) \
1460-
$(srcdir)/Tools/cases_generator/generate_cases.py \
1461-
--metadata \
1462-
-i $(srcdir)/Python/bytecodes.c \
1463-
-o $(srcdir)/Python/opcode_metadata.h.new
14641459
$(UPDATE_FILE) $(srcdir)/Python/opcode_metadata.h $(srcdir)/Python/opcode_metadata.h.new
14651460

1461+
Python/compile.o: $(srcdir)/Python/opcode_metadata.h
1462+
14661463
Python/ceval.o: \
14671464
$(srcdir)/Python/ceval_macros.h \
14681465
$(srcdir)/Python/condvar.h \

Python/compile.c

+38-220
Original file line numberDiff line numberDiff line change
@@ -1074,135 +1074,49 @@ basicblock_next_instr(basicblock *b)
10741074
static int
10751075
stack_effect(int opcode, int oparg, int jump)
10761076
{
1077-
switch (opcode) {
1078-
case NOP:
1079-
case EXTENDED_ARG:
1080-
case RESUME:
1081-
case CACHE:
1082-
return 0;
1083-
1084-
/* Stack manipulation */
1085-
case POP_TOP:
1086-
return -1;
1087-
case SWAP:
1088-
return 0;
1089-
case END_FOR:
1090-
return -2;
1091-
1092-
/* Unary operators */
1093-
case UNARY_NEGATIVE:
1094-
case UNARY_NOT:
1095-
case UNARY_INVERT:
1096-
return 0;
1097-
1098-
case SET_ADD:
1099-
case LIST_APPEND:
1100-
return -1;
1101-
case MAP_ADD:
1102-
return -2;
1103-
1104-
case BINARY_SUBSCR:
1105-
return -1;
1106-
case BINARY_SLICE:
1107-
return -2;
1108-
case STORE_SUBSCR:
1109-
return -3;
1110-
case STORE_SLICE:
1111-
return -4;
1112-
case DELETE_SUBSCR:
1113-
return -2;
1114-
1115-
case GET_ITER:
1116-
return 0;
1117-
1118-
case LOAD_BUILD_CLASS:
1119-
return 1;
1077+
if (0 <= opcode && opcode <= MAX_REAL_OPCODE) {
1078+
if (_PyOpcode_Deopt[opcode] != opcode) {
1079+
// Specialized instructions are not supported.
1080+
return PY_INVALID_STACK_EFFECT;
1081+
}
1082+
int popped, pushed;
1083+
if (jump > 0) {
1084+
popped = _PyOpcode_num_popped(opcode, oparg, true);
1085+
pushed = _PyOpcode_num_pushed(opcode, oparg, true);
1086+
}
1087+
else {
1088+
popped = _PyOpcode_num_popped(opcode, oparg, false);
1089+
pushed = _PyOpcode_num_pushed(opcode, oparg, false);
1090+
}
1091+
if (popped < 0 || pushed < 0) {
1092+
return PY_INVALID_STACK_EFFECT;
1093+
}
1094+
if (jump >= 0) {
1095+
return pushed - popped;
1096+
}
1097+
if (jump < 0) {
1098+
// Compute max(pushed - popped, alt_pushed - alt_popped)
1099+
int alt_popped = _PyOpcode_num_popped(opcode, oparg, true);
1100+
int alt_pushed = _PyOpcode_num_pushed(opcode, oparg, true);
1101+
if (alt_popped < 0 || alt_pushed < 0) {
1102+
return PY_INVALID_STACK_EFFECT;
1103+
}
1104+
int diff = pushed - popped;
1105+
int alt_diff = alt_pushed - alt_popped;
1106+
if (alt_diff > diff) {
1107+
return alt_diff;
1108+
}
1109+
return diff;
1110+
}
1111+
}
11201112

1121-
case RETURN_VALUE:
1122-
return -1;
1123-
case RETURN_CONST:
1124-
return 0;
1125-
case SETUP_ANNOTATIONS:
1126-
return 0;
1127-
case YIELD_VALUE:
1128-
return 0;
1113+
// Pseudo ops
1114+
switch (opcode) {
11291115
case POP_BLOCK:
1130-
return 0;
1131-
case POP_EXCEPT:
1132-
return -1;
1133-
1134-
case STORE_NAME:
1135-
return -1;
1136-
case DELETE_NAME:
1137-
return 0;
1138-
case UNPACK_SEQUENCE:
1139-
return oparg-1;
1140-
case UNPACK_EX:
1141-
return (oparg&0xFF) + (oparg>>8);
1142-
case FOR_ITER:
1143-
return 1;
1144-
case SEND:
1145-
return jump > 0 ? -1 : 0;
1146-
case STORE_ATTR:
1147-
return -2;
1148-
case DELETE_ATTR:
1149-
return -1;
1150-
case STORE_GLOBAL:
1151-
return -1;
1152-
case DELETE_GLOBAL:
1153-
return 0;
1154-
case LOAD_CONST:
1155-
return 1;
1156-
case LOAD_NAME:
1157-
return 1;
1158-
case BUILD_TUPLE:
1159-
case BUILD_LIST:
1160-
case BUILD_SET:
1161-
case BUILD_STRING:
1162-
return 1-oparg;
1163-
case BUILD_MAP:
1164-
return 1 - 2*oparg;
1165-
case BUILD_CONST_KEY_MAP:
1166-
return -oparg;
1167-
case LOAD_ATTR:
1168-
return (oparg & 1);
1169-
case COMPARE_OP:
1170-
case IS_OP:
1171-
case CONTAINS_OP:
1172-
return -1;
1173-
case CHECK_EXC_MATCH:
1174-
return 0;
1175-
case CHECK_EG_MATCH:
1176-
return 0;
1177-
case IMPORT_NAME:
1178-
return -1;
1179-
case IMPORT_FROM:
1180-
return 1;
1181-
1182-
/* Jumps */
1183-
case JUMP_FORWARD:
1184-
case JUMP_BACKWARD:
11851116
case JUMP:
1186-
case JUMP_BACKWARD_NO_INTERRUPT:
11871117
case JUMP_NO_INTERRUPT:
11881118
return 0;
11891119

1190-
case JUMP_IF_TRUE_OR_POP:
1191-
case JUMP_IF_FALSE_OR_POP:
1192-
return jump ? 0 : -1;
1193-
1194-
case POP_JUMP_IF_NONE:
1195-
case POP_JUMP_IF_NOT_NONE:
1196-
case POP_JUMP_IF_FALSE:
1197-
case POP_JUMP_IF_TRUE:
1198-
return -1;
1199-
1200-
case COMPARE_AND_BRANCH:
1201-
return -2;
1202-
1203-
case LOAD_GLOBAL:
1204-
return (oparg & 1) + 1;
1205-
12061120
/* Exception handling pseudo-instructions */
12071121
case SETUP_FINALLY:
12081122
/* 0 in the normal flow.
@@ -1218,109 +1132,13 @@ stack_effect(int opcode, int oparg, int jump)
12181132
* of __(a)enter__ and push 2 values before jumping to the handler
12191133
* if an exception be raised. */
12201134
return jump ? 1 : 0;
1221-
case PREP_RERAISE_STAR:
1222-
return -1;
1223-
case RERAISE:
1224-
return -1;
1225-
case PUSH_EXC_INFO:
1226-
return 1;
1227-
1228-
case WITH_EXCEPT_START:
1229-
return 1;
1230-
1231-
case LOAD_FAST:
1232-
case LOAD_FAST_CHECK:
1233-
return 1;
1234-
case STORE_FAST:
1235-
return -1;
1236-
case DELETE_FAST:
1237-
return 0;
1238-
1239-
case RETURN_GENERATOR:
1240-
return 0;
12411135

1242-
case RAISE_VARARGS:
1243-
return -oparg;
1244-
1245-
/* Functions and calls */
1246-
case KW_NAMES:
1247-
return 0;
1248-
case CALL:
1249-
return -1-oparg;
1250-
case CALL_INTRINSIC_1:
1251-
return 0;
1252-
case CALL_FUNCTION_EX:
1253-
return -2 - ((oparg & 0x01) != 0);
1254-
case MAKE_FUNCTION:
1255-
return 0 - ((oparg & 0x01) != 0) - ((oparg & 0x02) != 0) -
1256-
((oparg & 0x04) != 0) - ((oparg & 0x08) != 0);
1257-
case BUILD_SLICE:
1258-
if (oparg == 3)
1259-
return -2;
1260-
else
1261-
return -1;
1262-
1263-
/* Closures */
1264-
case MAKE_CELL:
1265-
case COPY_FREE_VARS:
1266-
return 0;
1267-
case LOAD_CLOSURE:
1268-
return 1;
1269-
case LOAD_DEREF:
1270-
case LOAD_CLASSDEREF:
1271-
return 1;
1272-
case STORE_DEREF:
1273-
return -1;
1274-
case DELETE_DEREF:
1275-
return 0;
1276-
1277-
/* Iterators and generators */
1278-
case GET_AWAITABLE:
1279-
return 0;
1280-
1281-
case BEFORE_ASYNC_WITH:
1282-
case BEFORE_WITH:
1283-
return 1;
1284-
case GET_AITER:
1285-
return 0;
1286-
case GET_ANEXT:
1287-
return 1;
1288-
case GET_YIELD_FROM_ITER:
1289-
return 0;
1290-
case END_ASYNC_FOR:
1291-
return -2;
1292-
case CLEANUP_THROW:
1293-
return -2;
1294-
case FORMAT_VALUE:
1295-
/* If there's a fmt_spec on the stack, we go from 2->1,
1296-
else 1->1. */
1297-
return (oparg & FVS_MASK) == FVS_HAVE_SPEC ? -1 : 0;
12981136
case LOAD_METHOD:
12991137
return 1;
1300-
case LOAD_ASSERTION_ERROR:
1301-
return 1;
1302-
case LIST_EXTEND:
1303-
case SET_UPDATE:
1304-
case DICT_MERGE:
1305-
case DICT_UPDATE:
1306-
return -1;
1307-
case MATCH_CLASS:
1308-
return -2;
1309-
case GET_LEN:
1310-
case MATCH_MAPPING:
1311-
case MATCH_SEQUENCE:
1312-
case MATCH_KEYS:
1313-
return 1;
1314-
case COPY:
1315-
case PUSH_NULL:
1316-
return 1;
1317-
case BINARY_OP:
1318-
return -1;
1319-
case INTERPRETER_EXIT:
1320-
return -1;
13211138
default:
13221139
return PY_INVALID_STACK_EFFECT;
13231140
}
1141+
13241142
return PY_INVALID_STACK_EFFECT; /* not reachable */
13251143
}
13261144

Python/opcode_metadata.h

+18-7
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
// from Python/bytecodes.c
33
// Do not edit!
44

5-
#ifndef NDEBUG
6-
static int
5+
#ifndef NEED_OPCODE_TABLES
6+
extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump);
7+
#else
8+
int
79
_PyOpcode_num_popped(int opcode, int oparg, bool jump) {
810
switch(opcode) {
911
case NOP:
@@ -345,13 +347,15 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
345347
case CACHE:
346348
return 0;
347349
default:
348-
Py_UNREACHABLE();
350+
return -1;
349351
}
350352
}
351353
#endif
352354

353-
#ifndef NDEBUG
354-
static int
355+
#ifndef NEED_OPCODE_TABLES
356+
extern int _PyOpcode_num_pushed(int opcode, int oparg, bool jump);
357+
#else
358+
int
355359
_PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
356360
switch(opcode) {
357361
case NOP:
@@ -693,10 +697,11 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
693697
case CACHE:
694698
return 0;
695699
default:
696-
Py_UNREACHABLE();
700+
return -1;
697701
}
698702
}
699703
#endif
704+
700705
enum Direction { DIR_NONE, DIR_READ, DIR_WRITE };
701706
enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC0, INSTR_FMT_IBC000, INSTR_FMT_IBC0000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 };
702707
struct opcode_metadata {
@@ -705,7 +710,12 @@ struct opcode_metadata {
705710
enum Direction dir_op3;
706711
bool valid_entry;
707712
enum InstructionFormat instr_format;
708-
} _PyOpcode_opcode_metadata[256] = {
713+
};
714+
715+
#ifndef NEED_OPCODE_TABLES
716+
extern const struct opcode_metadata _PyOpcode_opcode_metadata[256];
717+
#else
718+
const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
709719
[NOP] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
710720
[RESUME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
711721
[LOAD_CLOSURE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
@@ -876,3 +886,4 @@ struct opcode_metadata {
876886
[EXTENDED_ARG] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
877887
[CACHE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX },
878888
};
889+
#endif

0 commit comments

Comments
 (0)