Skip to content

Commit 299483c

Browse files
authored
bpo-45963: Make space for the InterpreterFrame of a generator in that 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.
1 parent f34d181 commit 299483c

File tree

7 files changed

+127
-144
lines changed

7 files changed

+127
-144
lines changed

Include/cpython/genobject.h

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ extern "C" {
1414
#define _PyGenObject_HEAD(prefix) \
1515
PyObject_HEAD \
1616
/* Note: gi_frame can be NULL if the generator is "finished" */ \
17-
struct _interpreter_frame *prefix##_xframe; \
1817
/* The code object backing the generator */ \
1918
PyCodeObject *prefix##_code; \
2019
/* List of weak reference. */ \
@@ -23,7 +22,14 @@ extern "C" {
2322
PyObject *prefix##_name; \
2423
/* Qualified name of the generator. */ \
2524
PyObject *prefix##_qualname; \
26-
_PyErr_StackItem prefix##_exc_state;
25+
_PyErr_StackItem prefix##_exc_state; \
26+
PyObject *prefix##_origin_or_finalizer; \
27+
char prefix##_hooks_inited; \
28+
char prefix##_closed; \
29+
char prefix##_running_async; \
30+
/* The frame */ \
31+
char prefix##_frame_valid; \
32+
PyObject *prefix##_iframe[1];
2733

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

4955
typedef struct {
5056
_PyGenObject_HEAD(cr)
51-
PyObject *cr_origin;
5257
} PyCoroObject;
5358

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

6570
typedef struct {
6671
_PyGenObject_HEAD(ag)
67-
PyObject *ag_finalizer;
68-
69-
/* Flag is set to 1 when hooks set up by sys.set_asyncgen_hooks
70-
were called on the generator, to avoid calling them more
71-
than once. */
72-
int ag_hooks_inited;
73-
74-
/* Flag is set to 1 when aclose() is called for the first time, or
75-
when a StopAsyncIteration exception is raised. */
76-
int ag_closed;
77-
78-
int ag_running_async;
7972
} PyAsyncGenObject;
8073

8174
PyAPI_DATA(PyTypeObject) PyAsyncGen_Type;

Include/internal/pycore_ceval.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ static inline void _Py_LeaveRecursiveCall_inline(void) {
113113

114114
struct _interpreter_frame *_PyEval_GetFrame(void);
115115

116-
PyObject *_Py_MakeCoro(PyFunctionObject *func, struct _interpreter_frame *);
116+
PyObject *_Py_MakeCoro(PyFunctionObject *func);
117117

118118
#ifdef __cplusplus
119119
}

Include/internal/pycore_frame.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ static inline void _PyFrame_StackPush(InterpreterFrame *f, PyObject *value) {
7474

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

77-
InterpreterFrame *_PyFrame_Copy(InterpreterFrame *frame);
77+
void _PyFrame_Copy(InterpreterFrame *src, InterpreterFrame *dest);
7878

7979
static inline void
8080
_PyFrame_InitializeSpecials(

Lib/test/test_sys.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,7 @@ def bar(cls):
13401340
check(bar, size('PP'))
13411341
# generator
13421342
def get_gen(): yield 1
1343-
check(get_gen(), size('P2PPP4P'))
1343+
check(get_gen(), size('P2PPP4P4c8P2iciP'))
13441344
# iterator
13451345
check(iter('abc'), size('lP'))
13461346
# callable-iterator

0 commit comments

Comments
 (0)