bpo-44525: Copy free variables in bytecode to allow calls to inner functions to be specialized (GH-29595)

* Make internal APIs that take PyFrameConstructor take a PyFunctionObject instead.

* Add reference to function to frame, borrow references to builtins and globals.

* Add COPY_FREE_VARS instruction to allow specialization of calls to inner functions.
This commit is contained in:
Mark Shannon 2021-11-23 09:53:24 +00:00 committed by GitHub
parent d82f2caf94
commit 135cabd328
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 268 additions and 156 deletions

View file

@ -52,7 +52,7 @@ _PyEval_EvalFrame(PyThreadState *tstate, struct _interpreter_frame *frame, int t
extern PyObject *
_PyEval_Vector(PyThreadState *tstate,
PyFrameConstructor *desc, PyObject *locals,
PyFunctionObject *func, PyObject *locals,
PyObject* const* args, size_t argcount,
PyObject *kwnames);
@ -113,7 +113,7 @@ static inline void _Py_LeaveRecursiveCall_inline(void) {
struct _interpreter_frame *_PyEval_GetFrame(void);
PyObject *_Py_MakeCoro(PyFrameConstructor *, struct _interpreter_frame *);
PyObject *_Py_MakeCoro(PyFunctionObject *func, struct _interpreter_frame *);
#ifdef __cplusplus
}

View file

@ -20,13 +20,13 @@ enum _framestate {
typedef signed char PyFrameState;
typedef struct _interpreter_frame {
PyObject *f_globals;
PyObject *f_builtins;
PyObject *f_locals;
PyCodeObject *f_code;
PyFrameObject *frame_obj;
/* Borrowed reference to a generator, or NULL */
PyObject *generator;
PyFunctionObject *f_func; /* Strong reference */
PyObject *f_globals; /* Borrowed reference */
PyObject *f_builtins; /* Borrowed reference */
PyObject *f_locals; /* Strong reference, may be NULL */
PyCodeObject *f_code; /* Strong reference */
PyFrameObject *frame_obj; /* Strong reference, may be NULL */
PyObject *generator; /* Borrowed reference, may be NULL */
struct _interpreter_frame *previous;
int f_lasti; /* Last instruction if called */
int stacktop; /* Offset of TOS from localsplus */
@ -70,16 +70,18 @@ static inline void _PyFrame_StackPush(InterpreterFrame *f, PyObject *value) {
#define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *))
InterpreterFrame *
_PyInterpreterFrame_HeapAlloc(PyFrameConstructor *con, PyObject *locals);
_PyInterpreterFrame_HeapAlloc(PyFunctionObject *func, PyObject *locals);
static inline void
_PyFrame_InitializeSpecials(
InterpreterFrame *frame, PyFrameConstructor *con,
InterpreterFrame *frame, PyFunctionObject *func,
PyObject *locals, int nlocalsplus)
{
frame->f_code = (PyCodeObject *)Py_NewRef(con->fc_code);
frame->f_builtins = Py_NewRef(con->fc_builtins);
frame->f_globals = Py_NewRef(con->fc_globals);
Py_INCREF(func);
frame->f_func = func;
frame->f_code = (PyCodeObject *)Py_NewRef(func->func_code);
frame->f_builtins = func->func_builtins;
frame->f_globals = func->func_globals;
frame->f_locals = Py_XNewRef(locals);
frame->stacktop = nlocalsplus;
frame->frame_obj = NULL;
@ -150,7 +152,7 @@ void
_PyFrame_LocalsToFast(InterpreterFrame *frame, int clear);
InterpreterFrame *_PyThreadState_PushFrame(
PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals);
PyThreadState *tstate, PyFunctionObject *func, PyObject *locals);
extern InterpreterFrame *
_PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size);

View file

@ -0,0 +1,11 @@
#ifndef Py_INTERNAL_FUNCTION_H
#define Py_INTERNAL_FUNCTION_H
#include "Python.h"
PyFunctionObject *
_PyFunction_FromConstructor(PyFrameConstructor *constr);
#endif /* !Py_INTERNAL_FUNCTION_H */