Skip to content

Commit

Permalink
bpo-45963: Make space for the InterpreterFrame of a generator in that…
Browse files Browse the repository at this point in the history
… generator. (GH-29891)

* Make generator, coroutine and async gen structs all the same size.

* Store interpreter frame in generator (and coroutine). Reduces the number of allocations neeeded for a generator from two to one.
  • Loading branch information
markshannon authored Dec 6, 2021
1 parent f34d181 commit 299483c
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 144 deletions.
23 changes: 8 additions & 15 deletions Include/cpython/genobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ extern "C" {
#define _PyGenObject_HEAD(prefix) \
PyObject_HEAD \
/* Note: gi_frame can be NULL if the generator is "finished" */ \
struct _interpreter_frame *prefix##_xframe; \
/* The code object backing the generator */ \
PyCodeObject *prefix##_code; \
/* List of weak reference. */ \
Expand All @@ -23,7 +22,14 @@ extern "C" {
PyObject *prefix##_name; \
/* Qualified name of the generator. */ \
PyObject *prefix##_qualname; \
_PyErr_StackItem prefix##_exc_state;
_PyErr_StackItem prefix##_exc_state; \
PyObject *prefix##_origin_or_finalizer; \
char prefix##_hooks_inited; \
char prefix##_closed; \
char prefix##_running_async; \
/* The frame */ \
char prefix##_frame_valid; \
PyObject *prefix##_iframe[1];

typedef struct {
/* The gi_ prefix is intended to remind of generator-iterator. */
Expand All @@ -48,7 +54,6 @@ PyAPI_FUNC(void) _PyGen_Finalize(PyObject *self);

typedef struct {
_PyGenObject_HEAD(cr)
PyObject *cr_origin;
} PyCoroObject;

PyAPI_DATA(PyTypeObject) PyCoro_Type;
Expand All @@ -64,18 +69,6 @@ PyAPI_FUNC(PyObject *) PyCoro_New(PyFrameObject *,

typedef struct {
_PyGenObject_HEAD(ag)
PyObject *ag_finalizer;

/* Flag is set to 1 when hooks set up by sys.set_asyncgen_hooks
were called on the generator, to avoid calling them more
than once. */
int ag_hooks_inited;

/* Flag is set to 1 when aclose() is called for the first time, or
when a StopAsyncIteration exception is raised. */
int ag_closed;

int ag_running_async;
} PyAsyncGenObject;

PyAPI_DATA(PyTypeObject) PyAsyncGen_Type;
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ static inline void _Py_LeaveRecursiveCall_inline(void) {

struct _interpreter_frame *_PyEval_GetFrame(void);

PyObject *_Py_MakeCoro(PyFunctionObject *func, struct _interpreter_frame *);
PyObject *_Py_MakeCoro(PyFunctionObject *func);

#ifdef __cplusplus
}
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ static inline void _PyFrame_StackPush(InterpreterFrame *f, PyObject *value) {

#define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *))

InterpreterFrame *_PyFrame_Copy(InterpreterFrame *frame);
void _PyFrame_Copy(InterpreterFrame *src, InterpreterFrame *dest);

static inline void
_PyFrame_InitializeSpecials(
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -1340,7 +1340,7 @@ def bar(cls):
check(bar, size('PP'))
# generator
def get_gen(): yield 1
check(get_gen(), size('P2PPP4P'))
check(get_gen(), size('P2PPP4P4c8P2iciP'))
# iterator
check(iter('abc'), size('lP'))
# callable-iterator
Expand Down
Loading

0 comments on commit 299483c

Please sign in to comment.