gh-106581: Project through calls (#108067)

This finishes the work begun in gh-107760. When, while projecting a superblock, we encounter a call to a short, simple function, the superblock will now enter the function using `_PUSH_FRAME`, continue through it, and leave it using `_POP_FRAME`, and then continue through the original code. Multiple frame pushes and pops are even possible. It is also possible to stop appending to the superblock in the middle of a called function, when running out of space or encountering an unsupported bytecode.
This commit is contained in:
Guido van Rossum 2023-08-17 11:29:58 -07:00 committed by GitHub
parent 292a22bdc2
commit 61c7249759
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 409 additions and 109 deletions

View file

@ -171,6 +171,7 @@ void _PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *
PyObject *_PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type, Py_ssize_t nargs, PyObject *kwargs);
PyObject *_PyEval_MatchKeys(PyThreadState *tstate, PyObject *map, PyObject *keys);
int _PyEval_UnpackIterable(PyThreadState *tstate, PyObject *v, int argcnt, int argcntafter, PyObject **sp);
void _PyEval_FrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame);
#ifdef __cplusplus

View file

@ -16,13 +16,22 @@ extern PyObject* _PyFunction_Vectorcall(
#define FUNC_MAX_WATCHERS 8
#define FUNC_VERSION_CACHE_SIZE (1<<12) /* Must be a power of 2 */
struct _py_func_state {
uint32_t next_version;
// Borrowed references to function objects whose
// func_version % FUNC_VERSION_CACHE_SIZE
// once was equal to the index in the table.
// They are cleared when the function is deallocated.
PyFunctionObject *func_version_cache[FUNC_VERSION_CACHE_SIZE];
};
extern PyFunctionObject* _PyFunction_FromConstructor(PyFrameConstructor *constr);
extern uint32_t _PyFunction_GetVersionForCurrentState(PyFunctionObject *func);
extern void _PyFunction_SetVersion(PyFunctionObject *func, uint32_t version);
PyFunctionObject *_PyFunction_LookupByVersion(uint32_t version);
extern PyObject *_Py_set_function_type_params(
PyThreadState* unused, PyObject *func, PyObject *type_params);

View file

@ -33,35 +33,36 @@
#define _BINARY_OP_SUBTRACT_FLOAT 309
#define _GUARD_BOTH_UNICODE 310
#define _BINARY_OP_ADD_UNICODE 311
#define _LOAD_LOCALS 312
#define _LOAD_FROM_DICT_OR_GLOBALS 313
#define _GUARD_GLOBALS_VERSION 314
#define _GUARD_BUILTINS_VERSION 315
#define _LOAD_GLOBAL_MODULE 316
#define _LOAD_GLOBAL_BUILTINS 317
#define _GUARD_TYPE_VERSION 318
#define _CHECK_MANAGED_OBJECT_HAS_VALUES 319
#define _LOAD_ATTR_INSTANCE_VALUE 320
#define IS_NONE 321
#define _ITER_CHECK_LIST 322
#define _IS_ITER_EXHAUSTED_LIST 323
#define _ITER_NEXT_LIST 324
#define _ITER_CHECK_TUPLE 325
#define _IS_ITER_EXHAUSTED_TUPLE 326
#define _ITER_NEXT_TUPLE 327
#define _ITER_CHECK_RANGE 328
#define _IS_ITER_EXHAUSTED_RANGE 329
#define _ITER_NEXT_RANGE 330
#define _CHECK_PEP_523 331
#define _CHECK_FUNCTION_EXACT_ARGS 332
#define _CHECK_STACK_SPACE 333
#define _INIT_CALL_PY_EXACT_ARGS 334
#define _PUSH_FRAME 335
#define _POP_JUMP_IF_FALSE 336
#define _POP_JUMP_IF_TRUE 337
#define JUMP_TO_TOP 338
#define SAVE_CURRENT_IP 339
#define INSERT 340
#define _POP_FRAME 312
#define _LOAD_LOCALS 313
#define _LOAD_FROM_DICT_OR_GLOBALS 314
#define _GUARD_GLOBALS_VERSION 315
#define _GUARD_BUILTINS_VERSION 316
#define _LOAD_GLOBAL_MODULE 317
#define _LOAD_GLOBAL_BUILTINS 318
#define _GUARD_TYPE_VERSION 319
#define _CHECK_MANAGED_OBJECT_HAS_VALUES 320
#define _LOAD_ATTR_INSTANCE_VALUE 321
#define IS_NONE 322
#define _ITER_CHECK_LIST 323
#define _IS_ITER_EXHAUSTED_LIST 324
#define _ITER_NEXT_LIST 325
#define _ITER_CHECK_TUPLE 326
#define _IS_ITER_EXHAUSTED_TUPLE 327
#define _ITER_NEXT_TUPLE 328
#define _ITER_CHECK_RANGE 329
#define _IS_ITER_EXHAUSTED_RANGE 330
#define _ITER_NEXT_RANGE 331
#define _CHECK_PEP_523 332
#define _CHECK_FUNCTION_EXACT_ARGS 333
#define _CHECK_STACK_SPACE 334
#define _INIT_CALL_PY_EXACT_ARGS 335
#define _PUSH_FRAME 336
#define _POP_JUMP_IF_FALSE 337
#define _POP_JUMP_IF_TRUE 338
#define JUMP_TO_TOP 339
#define SAVE_CURRENT_IP 340
#define INSERT 341
extern int _PyOpcode_num_popped(int opcode, int oparg, bool jump);
#ifdef NEED_OPCODE_METADATA
@ -197,6 +198,8 @@ int _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return oparg;
case INTERPRETER_EXIT:
return 1;
case _POP_FRAME:
return 1;
case RETURN_VALUE:
return 1;
case INSTRUMENTED_RETURN_VALUE:
@ -723,6 +726,8 @@ int _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 0;
case INTERPRETER_EXIT:
return 0;
case _POP_FRAME:
return 0;
case RETURN_VALUE:
return 0;
case INSTRUMENTED_RETURN_VALUE:
@ -1191,7 +1196,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
[STORE_FAST_STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG },
[POP_TOP] = { true, INSTR_FMT_IX, 0 },
[PUSH_NULL] = { true, INSTR_FMT_IX, 0 },
[END_FOR] = { true, INSTR_FMT_IB, 0 },
[END_FOR] = { true, INSTR_FMT_IX, 0 },
[INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX, 0 },
[END_SEND] = { true, INSTR_FMT_IX, 0 },
[INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX, 0 },
@ -1205,14 +1210,14 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
[TO_BOOL_STR] = { true, INSTR_FMT_IXC00, 0 },
[TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, 0 },
[UNARY_INVERT] = { true, INSTR_FMT_IX, 0 },
[BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IBC, 0 },
[BINARY_OP_ADD_INT] = { true, INSTR_FMT_IBC, 0 },
[BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IBC, 0 },
[BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IBC, 0 },
[BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IBC, 0 },
[BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IBC, 0 },
[BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IBC, 0 },
[BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IB, HAS_LOCAL_FLAG },
[BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC, 0 },
[BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC, 0 },
[BINARY_OP_SUBTRACT_INT] = { true, INSTR_FMT_IXC, 0 },
[BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC, 0 },
[BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC, 0 },
[BINARY_OP_SUBTRACT_FLOAT] = { true, INSTR_FMT_IXC, 0 },
[BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC, 0 },
[BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IX, HAS_LOCAL_FLAG },
[BINARY_SUBSCR] = { true, INSTR_FMT_IXC, 0 },
[BINARY_SLICE] = { true, INSTR_FMT_IX, 0 },
[STORE_SLICE] = { true, INSTR_FMT_IX, 0 },
@ -1259,7 +1264,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
[DELETE_ATTR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG },
[STORE_GLOBAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG },
[DELETE_GLOBAL] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG },
[LOAD_LOCALS] = { true, INSTR_FMT_IB, 0 },
[LOAD_LOCALS] = { true, INSTR_FMT_IX, 0 },
[LOAD_NAME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG },
[LOAD_FROM_DICT_OR_GLOBALS] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG },
[LOAD_GLOBAL] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG },
@ -1400,6 +1405,7 @@ extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACR
#ifdef NEED_OPCODE_METADATA
const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPANSION_SIZE] = {
[NOP] = { .nuops = 1, .uops = { { NOP, 0, 0 } } },
[RESUME] = { .nuops = 1, .uops = { { RESUME, 0, 0 } } },
[LOAD_FAST_CHECK] = { .nuops = 1, .uops = { { LOAD_FAST_CHECK, 0, 0 } } },
[LOAD_FAST] = { .nuops = 1, .uops = { { LOAD_FAST, 0, 0 } } },
[LOAD_FAST_AND_CLEAR] = { .nuops = 1, .uops = { { LOAD_FAST_AND_CLEAR, 0, 0 } } },
@ -1444,6 +1450,8 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
[DELETE_SUBSCR] = { .nuops = 1, .uops = { { DELETE_SUBSCR, 0, 0 } } },
[CALL_INTRINSIC_1] = { .nuops = 1, .uops = { { CALL_INTRINSIC_1, 0, 0 } } },
[CALL_INTRINSIC_2] = { .nuops = 1, .uops = { { CALL_INTRINSIC_2, 0, 0 } } },
[RETURN_VALUE] = { .nuops = 3, .uops = { { SAVE_IP, 7, 0 }, { SAVE_CURRENT_IP, 0, 0 }, { _POP_FRAME, 0, 0 } } },
[RETURN_CONST] = { .nuops = 4, .uops = { { LOAD_CONST, 0, 0 }, { SAVE_IP, 7, 0 }, { SAVE_CURRENT_IP, 0, 0 }, { _POP_FRAME, 0, 0 } } },
[GET_AITER] = { .nuops = 1, .uops = { { GET_AITER, 0, 0 } } },
[GET_ANEXT] = { .nuops = 1, .uops = { { GET_ANEXT, 0, 0 } } },
[GET_AWAITABLE] = { .nuops = 1, .uops = { { GET_AWAITABLE, 0, 0 } } },
@ -1545,6 +1553,7 @@ const char * const _PyOpcode_uop_name[OPCODE_UOP_NAME_SIZE] = {
[_BINARY_OP_SUBTRACT_FLOAT] = "_BINARY_OP_SUBTRACT_FLOAT",
[_GUARD_BOTH_UNICODE] = "_GUARD_BOTH_UNICODE",
[_BINARY_OP_ADD_UNICODE] = "_BINARY_OP_ADD_UNICODE",
[_POP_FRAME] = "_POP_FRAME",
[_LOAD_LOCALS] = "_LOAD_LOCALS",
[_LOAD_FROM_DICT_OR_GLOBALS] = "_LOAD_FROM_DICT_OR_GLOBALS",
[_GUARD_GLOBALS_VERSION] = "_GUARD_GLOBALS_VERSION",