From 3e0689ccde1da4af820607eed7767af6fa1e0f00 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 21 Jun 2024 14:50:51 +0100 Subject: [PATCH 1/5] gh-120834: fix type of *_iframe field in _PyGenObject_HEAD declaration --- Include/cpython/genobject.h | 4 +++- Objects/genobject.c | 21 ++++++++++----------- Python/bytecodes.c | 8 ++++---- Python/executor_cases.c.h | 4 ++-- Python/generated_cases.c.h | 8 ++++---- 5 files changed, 23 insertions(+), 22 deletions(-) diff --git a/Include/cpython/genobject.h b/Include/cpython/genobject.h index 49e46c277d75ae..18cf8b59a4d56c 100644 --- a/Include/cpython/genobject.h +++ b/Include/cpython/genobject.h @@ -7,6 +7,8 @@ extern "C" { #endif +struct _PyInterpreterFrame; + /* --- Generators --------------------------------------------------------- */ /* _PyGenObject_HEAD defines the initial segment of generator @@ -26,7 +28,7 @@ extern "C" { char prefix##_running_async; \ /* The frame */ \ int8_t prefix##_frame_state; \ - PyObject *prefix##_iframe[1]; \ + struct _PyInterpreterFrame *prefix##_iframe[1]; \ typedef struct { /* The gi_ prefix is intended to remind of generator-iterator. */ diff --git a/Objects/genobject.c b/Objects/genobject.c index 662e644f8aeddd..4fce370e90c823 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -30,8 +30,7 @@ static const char *ASYNC_GEN_IGNORED_EXIT_MSG = /* Returns a borrowed reference */ static inline PyCodeObject * _PyGen_GetCode(PyGenObject *gen) { - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)(gen->gi_iframe); - return _PyFrame_GetCode(frame); + return _PyFrame_GetCode(gen->gi_iframe); } PyCodeObject * @@ -48,7 +47,7 @@ gen_traverse(PyGenObject *gen, visitproc visit, void *arg) Py_VISIT(gen->gi_name); Py_VISIT(gen->gi_qualname); if (gen->gi_frame_state != FRAME_CLEARED) { - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)(gen->gi_iframe); + _PyInterpreterFrame *frame = gen->gi_iframe; assert(frame->frame_obj == NULL || frame->frame_obj->f_frame->owner == FRAME_OWNED_BY_GENERATOR); int err = _PyFrame_Traverse(frame, visit, arg); @@ -141,7 +140,7 @@ gen_dealloc(PyGenObject *gen) Py_CLEAR(((PyAsyncGenObject*)gen)->ag_origin_or_finalizer); } if (gen->gi_frame_state != FRAME_CLEARED) { - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *frame = gen->gi_iframe; gen->gi_frame_state = FRAME_CLEARED; frame->previous = NULL; _PyFrame_ClearExceptCode(frame); @@ -163,7 +162,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, int exc, int closing) { PyThreadState *tstate = _PyThreadState_GET(); - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *frame = gen->gi_iframe; *presult = NULL; if (gen->gi_frame_state == FRAME_CREATED && arg && arg != Py_None) { @@ -342,7 +341,7 @@ PyObject * _PyGen_yf(PyGenObject *gen) { if (gen->gi_frame_state == FRAME_SUSPENDED_YIELD_FROM) { - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *frame = gen->gi_iframe; assert(is_resume(frame->instr_ptr)); assert((frame->instr_ptr->op.arg & RESUME_OPARG_LOCATION_MASK) >= RESUME_AFTER_YIELD_FROM); return Py_NewRef(_PyFrame_StackPeek(frame)); @@ -372,7 +371,7 @@ gen_close(PyGenObject *gen, PyObject *args) gen->gi_frame_state = state; Py_DECREF(yf); } - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *frame = gen->gi_iframe; if (is_resume(frame->instr_ptr)) { /* We can safely ignore the outermost try block * as it is automatically generated to handle @@ -382,7 +381,7 @@ gen_close(PyGenObject *gen, PyObject *args) // RESUME after YIELD_VALUE and exception depth is 1 assert((oparg & RESUME_OPARG_LOCATION_MASK) != RESUME_AT_FUNC_START); gen->gi_frame_state = FRAME_COMPLETED; - _PyFrame_ClearLocals((_PyInterpreterFrame *)gen->gi_iframe); + _PyFrame_ClearLocals(gen->gi_iframe); Py_RETURN_NONE; } } @@ -431,7 +430,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, PyObject *yf = _PyGen_yf(gen); if (yf) { - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *frame = gen->gi_iframe; PyObject *ret; int err; if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && @@ -739,7 +738,7 @@ _gen_getframe(PyGenObject *gen, const char *const name) if (FRAME_STATE_FINISHED(gen->gi_frame_state)) { Py_RETURN_NONE; } - return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject((_PyInterpreterFrame *)gen->gi_iframe)); + return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject(gen->gi_iframe)); } static PyObject * @@ -949,7 +948,7 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f, /* Copy the frame */ assert(f->f_frame->frame_obj == NULL); assert(f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT); - _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *frame = gen->gi_iframe; _PyFrame_Copy((_PyInterpreterFrame *)f->_f_frame_data, frame); gen->gi_frame_state = FRAME_CREATED; assert(frame->frame_obj == f); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 50444bcc0d200c..f8f22435faa9f2 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1015,7 +1015,7 @@ dummy_func( ((PyGenObject *)receiver)->gi_frame_state < FRAME_EXECUTING) { PyGenObject *gen = (PyGenObject *)receiver; - _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *gen_frame = gen->gi_iframe; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; @@ -1055,7 +1055,7 @@ dummy_func( DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING); STAT_INC(SEND, hit); - _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *gen_frame = gen->gi_iframe; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; @@ -2799,7 +2799,7 @@ dummy_func( DEOPT_IF(Py_TYPE(gen) != &PyGen_Type); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING); STAT_INC(FOR_ITER, hit); - gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + gen_frame = gen->gi_iframe; _PyFrame_StackPush(gen_frame, Py_None); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; @@ -3940,7 +3940,7 @@ dummy_func( } assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *gen_frame = gen->gi_iframe; frame->instr_ptr++; _PyFrame_Copy(frame, gen_frame); assert(frame->frame_obj == NULL); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index b4e5261f57ab8b..1f8e70be7cce56 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2871,7 +2871,7 @@ JUMP_TO_JUMP_TARGET(); } STAT_INC(FOR_ITER, hit); - gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + gen_frame = gen->gi_iframe; _PyFrame_StackPush(gen_frame, Py_None); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; @@ -4110,7 +4110,7 @@ } assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *gen_frame = gen->gi_iframe; frame->instr_ptr++; _PyFrame_Copy(frame, gen_frame); assert(frame->frame_obj == NULL); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 3980f9852e6396..7792649fbba600 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2747,7 +2747,7 @@ DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); STAT_INC(FOR_ITER, hit); - gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + gen_frame = gen->gi_iframe; _PyFrame_StackPush(gen_frame, Py_None); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; @@ -5180,7 +5180,7 @@ } assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *gen_frame = gen->gi_iframe; frame->instr_ptr++; _PyFrame_Copy(frame, gen_frame); assert(frame->frame_obj == NULL); @@ -5260,7 +5260,7 @@ ((PyGenObject *)receiver)->gi_frame_state < FRAME_EXECUTING) { PyGenObject *gen = (PyGenObject *)receiver; - _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *gen_frame = gen->gi_iframe; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; @@ -5310,7 +5310,7 @@ DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND); STAT_INC(SEND, hit); - _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; + _PyInterpreterFrame *gen_frame = gen->gi_iframe; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; From 04e18caa535b300a3b7b5ec25687a4be03bab162 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 21 Jun 2024 16:26:42 +0100 Subject: [PATCH 2/5] update includes --- Include/internal/pycore_genobject.h | 2 -- Include/internal/pycore_interp.h | 2 +- Objects/genobject.c | 2 +- Python/pylifecycle.c | 1 - 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_genobject.h b/Include/internal/pycore_genobject.h index 9463c822ad8669..a853b4b0587c6d 100644 --- a/Include/internal/pycore_genobject.h +++ b/Include/internal/pycore_genobject.h @@ -8,8 +8,6 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif -#include "pycore_freelist.h" - PyAPI_FUNC(PyObject *)_PyGen_yf(PyGenObject *); extern void _PyGen_Finalize(PyObject *self); diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 6b5f50b88f7b85..b40b63a2a25014 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -23,7 +23,7 @@ extern "C" { #include "pycore_floatobject.h" // struct _Py_float_state #include "pycore_function.h" // FUNC_MAX_WATCHERS #include "pycore_gc.h" // struct _gc_runtime_state -#include "pycore_genobject.h" // struct _Py_async_gen_state +#include "pycore_genobject.h" // _PyGen_FetchStopIterationValue #include "pycore_global_objects.h"// struct _Py_interp_cached_objects #include "pycore_import.h" // struct _import_state #include "pycore_instruments.h" // _PY_MONITORING_EVENTS diff --git a/Objects/genobject.c b/Objects/genobject.c index 4fce370e90c823..6ff16d8f4c2d5d 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -6,8 +6,8 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_EvalFrame() #include "pycore_frame.h" // _PyInterpreterFrame +#include "pycore_freelist.h" // struct _Py_async_gen_freelist #include "pycore_gc.h" // _PyGC_CLEAR_FINALIZED() -#include "pycore_genobject.h" // struct _Py_async_gen_freelist #include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_object.h" // _PyObject_GC_UNTRACK() #include "pycore_opcode_utils.h" // RESUME_AFTER_YIELD_FROM diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 3639cf6712053e..a7b4d7ecc7c3ad 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -10,7 +10,6 @@ #include "pycore_exceptions.h" // _PyExc_InitTypes() #include "pycore_fileutils.h" // _Py_ResetForceASCII() #include "pycore_floatobject.h" // _PyFloat_InitTypes() -#include "pycore_genobject.h" // _PyAsyncGen_Fini() #include "pycore_global_objects_fini_generated.h" // "_PyStaticObjects_CheckRefcnt() #include "pycore_import.h" // _PyImport_BootstrapImp() #include "pycore_initconfig.h" // _PyStatus_OK() From a76a5adfd4637cde35e73ddc7425b586f50d80f9 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 21 Jun 2024 17:22:34 +0100 Subject: [PATCH 3/5] move _PyInterpreterFrame to public header so it can be included in genobject --- Include/cpython/frame.h | 21 +++++++++++++++++++++ Include/cpython/genobject.h | 6 ++++-- Include/internal/pycore_frame.h | 16 ---------------- Objects/genobject.c | 20 ++++++++++---------- Python/bytecodes.c | 8 ++++---- Python/executor_cases.c.h | 4 ++-- Python/generated_cases.c.h | 8 ++++---- 7 files changed, 45 insertions(+), 38 deletions(-) create mode 100644 Include/cpython/frame.h diff --git a/Include/cpython/frame.h b/Include/cpython/frame.h new file mode 100644 index 00000000000000..39da6d549daebf --- /dev/null +++ b/Include/cpython/frame.h @@ -0,0 +1,21 @@ +/* Interpreter Frame */ + +#ifndef Py_CPYTHON_FRAME_H +# error "this header file must not be included directly" +#endif + +typedef struct _PyInterpreterFrame { + PyObject *f_executable; /* Strong reference (code object or None) */ + struct _PyInterpreterFrame *previous; + PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */ + PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */ + PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */ + PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */ + PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */ + _Py_CODEUNIT *instr_ptr; /* Instruction currently executing (or about to begin) */ + int stacktop; /* Offset of TOS from localsplus */ + uint16_t return_offset; /* Only relevant during a function call */ + char owner; + /* Locals and stack */ + PyObject *localsplus[1]; +} _PyInterpreterFrame; diff --git a/Include/cpython/genobject.h b/Include/cpython/genobject.h index 18cf8b59a4d56c..0a29843ac5e886 100644 --- a/Include/cpython/genobject.h +++ b/Include/cpython/genobject.h @@ -7,7 +7,9 @@ extern "C" { #endif -struct _PyInterpreterFrame; +#define Py_CPYTHON_FRAME_H +#include "cpython/frame.h" +#undef Py_CPYTHON_FRAME_H /* --- Generators --------------------------------------------------------- */ @@ -28,7 +30,7 @@ struct _PyInterpreterFrame; char prefix##_running_async; \ /* The frame */ \ int8_t prefix##_frame_state; \ - struct _PyInterpreterFrame *prefix##_iframe[1]; \ + struct _PyInterpreterFrame prefix##_iframe; \ typedef struct { /* The gi_ prefix is intended to remind of generator-iterator. */ diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index e4eb893263c42c..9e4e9781216d27 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -54,22 +54,6 @@ enum _frameowner { FRAME_OWNED_BY_CSTACK = 3, }; -typedef struct _PyInterpreterFrame { - PyObject *f_executable; /* Strong reference (code object or None) */ - struct _PyInterpreterFrame *previous; - PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */ - PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */ - PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */ - PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */ - PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */ - _Py_CODEUNIT *instr_ptr; /* Instruction currently executing (or about to begin) */ - int stacktop; /* Offset of TOS from localsplus */ - uint16_t return_offset; /* Only relevant during a function call */ - char owner; - /* Locals and stack */ - PyObject *localsplus[1]; -} _PyInterpreterFrame; - #define _PyInterpreterFrame_LASTI(IF) \ ((int)((IF)->instr_ptr - _PyCode_CODE(_PyFrame_GetCode(IF)))) diff --git a/Objects/genobject.c b/Objects/genobject.c index 6ff16d8f4c2d5d..ec2d17aab3cfd6 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -30,7 +30,7 @@ static const char *ASYNC_GEN_IGNORED_EXIT_MSG = /* Returns a borrowed reference */ static inline PyCodeObject * _PyGen_GetCode(PyGenObject *gen) { - return _PyFrame_GetCode(gen->gi_iframe); + return _PyFrame_GetCode(&gen->gi_iframe); } PyCodeObject * @@ -47,7 +47,7 @@ gen_traverse(PyGenObject *gen, visitproc visit, void *arg) Py_VISIT(gen->gi_name); Py_VISIT(gen->gi_qualname); if (gen->gi_frame_state != FRAME_CLEARED) { - _PyInterpreterFrame *frame = gen->gi_iframe; + _PyInterpreterFrame *frame = &gen->gi_iframe; assert(frame->frame_obj == NULL || frame->frame_obj->f_frame->owner == FRAME_OWNED_BY_GENERATOR); int err = _PyFrame_Traverse(frame, visit, arg); @@ -140,7 +140,7 @@ gen_dealloc(PyGenObject *gen) Py_CLEAR(((PyAsyncGenObject*)gen)->ag_origin_or_finalizer); } if (gen->gi_frame_state != FRAME_CLEARED) { - _PyInterpreterFrame *frame = gen->gi_iframe; + _PyInterpreterFrame *frame = &gen->gi_iframe; gen->gi_frame_state = FRAME_CLEARED; frame->previous = NULL; _PyFrame_ClearExceptCode(frame); @@ -162,7 +162,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, int exc, int closing) { PyThreadState *tstate = _PyThreadState_GET(); - _PyInterpreterFrame *frame = gen->gi_iframe; + _PyInterpreterFrame *frame = &gen->gi_iframe; *presult = NULL; if (gen->gi_frame_state == FRAME_CREATED && arg && arg != Py_None) { @@ -341,7 +341,7 @@ PyObject * _PyGen_yf(PyGenObject *gen) { if (gen->gi_frame_state == FRAME_SUSPENDED_YIELD_FROM) { - _PyInterpreterFrame *frame = gen->gi_iframe; + _PyInterpreterFrame *frame = &gen->gi_iframe; assert(is_resume(frame->instr_ptr)); assert((frame->instr_ptr->op.arg & RESUME_OPARG_LOCATION_MASK) >= RESUME_AFTER_YIELD_FROM); return Py_NewRef(_PyFrame_StackPeek(frame)); @@ -371,7 +371,7 @@ gen_close(PyGenObject *gen, PyObject *args) gen->gi_frame_state = state; Py_DECREF(yf); } - _PyInterpreterFrame *frame = gen->gi_iframe; + _PyInterpreterFrame *frame = &gen->gi_iframe; if (is_resume(frame->instr_ptr)) { /* We can safely ignore the outermost try block * as it is automatically generated to handle @@ -381,7 +381,7 @@ gen_close(PyGenObject *gen, PyObject *args) // RESUME after YIELD_VALUE and exception depth is 1 assert((oparg & RESUME_OPARG_LOCATION_MASK) != RESUME_AT_FUNC_START); gen->gi_frame_state = FRAME_COMPLETED; - _PyFrame_ClearLocals(gen->gi_iframe); + _PyFrame_ClearLocals(&gen->gi_iframe); Py_RETURN_NONE; } } @@ -430,7 +430,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, PyObject *yf = _PyGen_yf(gen); if (yf) { - _PyInterpreterFrame *frame = gen->gi_iframe; + _PyInterpreterFrame *frame = &gen->gi_iframe; PyObject *ret; int err; if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && @@ -738,7 +738,7 @@ _gen_getframe(PyGenObject *gen, const char *const name) if (FRAME_STATE_FINISHED(gen->gi_frame_state)) { Py_RETURN_NONE; } - return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject(gen->gi_iframe)); + return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject(&gen->gi_iframe)); } static PyObject * @@ -948,7 +948,7 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f, /* Copy the frame */ assert(f->f_frame->frame_obj == NULL); assert(f->f_frame->owner == FRAME_OWNED_BY_FRAME_OBJECT); - _PyInterpreterFrame *frame = gen->gi_iframe; + _PyInterpreterFrame *frame = &gen->gi_iframe; _PyFrame_Copy((_PyInterpreterFrame *)f->_f_frame_data, frame); gen->gi_frame_state = FRAME_CREATED; assert(frame->frame_obj == f); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index f8f22435faa9f2..c4927c8806cb58 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1015,7 +1015,7 @@ dummy_func( ((PyGenObject *)receiver)->gi_frame_state < FRAME_EXECUTING) { PyGenObject *gen = (PyGenObject *)receiver; - _PyInterpreterFrame *gen_frame = gen->gi_iframe; + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; @@ -1055,7 +1055,7 @@ dummy_func( DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING); STAT_INC(SEND, hit); - _PyInterpreterFrame *gen_frame = gen->gi_iframe; + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; @@ -2799,7 +2799,7 @@ dummy_func( DEOPT_IF(Py_TYPE(gen) != &PyGen_Type); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING); STAT_INC(FOR_ITER, hit); - gen_frame = gen->gi_iframe; + gen_frame = &gen->gi_iframe; _PyFrame_StackPush(gen_frame, Py_None); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; @@ -3940,7 +3940,7 @@ dummy_func( } assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = gen->gi_iframe; + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; frame->instr_ptr++; _PyFrame_Copy(frame, gen_frame); assert(frame->frame_obj == NULL); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 1f8e70be7cce56..66acf0dc8b6a41 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2871,7 +2871,7 @@ JUMP_TO_JUMP_TARGET(); } STAT_INC(FOR_ITER, hit); - gen_frame = gen->gi_iframe; + gen_frame = &gen->gi_iframe; _PyFrame_StackPush(gen_frame, Py_None); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; @@ -4110,7 +4110,7 @@ } assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = gen->gi_iframe; + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; frame->instr_ptr++; _PyFrame_Copy(frame, gen_frame); assert(frame->frame_obj == NULL); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 7792649fbba600..fe9f15ee107d7c 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -2747,7 +2747,7 @@ DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); STAT_INC(FOR_ITER, hit); - gen_frame = gen->gi_iframe; + gen_frame = &gen->gi_iframe; _PyFrame_StackPush(gen_frame, Py_None); gen->gi_frame_state = FRAME_EXECUTING; gen->gi_exc_state.previous_item = tstate->exc_info; @@ -5180,7 +5180,7 @@ } assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); - _PyInterpreterFrame *gen_frame = gen->gi_iframe; + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; frame->instr_ptr++; _PyFrame_Copy(frame, gen_frame); assert(frame->frame_obj == NULL); @@ -5260,7 +5260,7 @@ ((PyGenObject *)receiver)->gi_frame_state < FRAME_EXECUTING) { PyGenObject *gen = (PyGenObject *)receiver; - _PyInterpreterFrame *gen_frame = gen->gi_iframe; + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; @@ -5310,7 +5310,7 @@ DEOPT_IF(Py_TYPE(gen) != &PyGen_Type && Py_TYPE(gen) != &PyCoro_Type, SEND); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND); STAT_INC(SEND, hit); - _PyInterpreterFrame *gen_frame = gen->gi_iframe; + _PyInterpreterFrame *gen_frame = &gen->gi_iframe; STACK_SHRINK(1); _PyFrame_StackPush(gen_frame, v); gen->gi_frame_state = FRAME_EXECUTING; From dcd8ef2d8d46014058b506883be80e0cbef20380 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Fri, 21 Jun 2024 22:42:46 +0100 Subject: [PATCH 4/5] make _PyGenObject_HEAD private, etc --- Include/cpython/frame.h | 21 -------------- Include/cpython/genobject.h | 37 ++---------------------- Include/internal/pycore_frame.h | 24 ++++++++++------ Include/internal/pycore_genobject.h | 44 +++++++++++++++++++++++++++++ Objects/frameobject.c | 6 ++-- Python/bytecodes.c | 4 +-- Python/ceval.c | 2 +- Python/executor_cases.c.h | 2 +- Python/frame.c | 2 +- Python/generated_cases.c.h | 4 +-- 10 files changed, 73 insertions(+), 73 deletions(-) delete mode 100644 Include/cpython/frame.h diff --git a/Include/cpython/frame.h b/Include/cpython/frame.h deleted file mode 100644 index 39da6d549daebf..00000000000000 --- a/Include/cpython/frame.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Interpreter Frame */ - -#ifndef Py_CPYTHON_FRAME_H -# error "this header file must not be included directly" -#endif - -typedef struct _PyInterpreterFrame { - PyObject *f_executable; /* Strong reference (code object or None) */ - struct _PyInterpreterFrame *previous; - PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */ - PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */ - PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */ - PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */ - PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */ - _Py_CODEUNIT *instr_ptr; /* Instruction currently executing (or about to begin) */ - int stacktop; /* Offset of TOS from localsplus */ - uint16_t return_offset; /* Only relevant during a function call */ - char owner; - /* Locals and stack */ - PyObject *localsplus[1]; -} _PyInterpreterFrame; diff --git a/Include/cpython/genobject.h b/Include/cpython/genobject.h index 0a29843ac5e886..f75884e597e2c2 100644 --- a/Include/cpython/genobject.h +++ b/Include/cpython/genobject.h @@ -7,35 +7,9 @@ extern "C" { #endif -#define Py_CPYTHON_FRAME_H -#include "cpython/frame.h" -#undef Py_CPYTHON_FRAME_H - /* --- Generators --------------------------------------------------------- */ -/* _PyGenObject_HEAD defines the initial segment of generator - and coroutine objects. */ -#define _PyGenObject_HEAD(prefix) \ - PyObject_HEAD \ - /* List of weak reference. */ \ - PyObject *prefix##_weakreflist; \ - /* Name of the generator. */ \ - PyObject *prefix##_name; \ - /* Qualified name of the generator. */ \ - PyObject *prefix##_qualname; \ - _PyErr_StackItem prefix##_exc_state; \ - PyObject *prefix##_origin_or_finalizer; \ - char prefix##_hooks_inited; \ - char prefix##_closed; \ - char prefix##_running_async; \ - /* The frame */ \ - int8_t prefix##_frame_state; \ - struct _PyInterpreterFrame prefix##_iframe; \ - -typedef struct { - /* The gi_ prefix is intended to remind of generator-iterator. */ - _PyGenObject_HEAD(gi) -} PyGenObject; +typedef struct _PyGenObject PyGenObject; PyAPI_DATA(PyTypeObject) PyGen_Type; @@ -50,9 +24,7 @@ PyAPI_FUNC(PyCodeObject *) PyGen_GetCode(PyGenObject *gen); /* --- PyCoroObject ------------------------------------------------------- */ -typedef struct { - _PyGenObject_HEAD(cr) -} PyCoroObject; +typedef struct _PyCoroObject PyCoroObject; PyAPI_DATA(PyTypeObject) PyCoro_Type; @@ -63,9 +35,7 @@ PyAPI_FUNC(PyObject *) PyCoro_New(PyFrameObject *, /* --- Asynchronous Generators -------------------------------------------- */ -typedef struct { - _PyGenObject_HEAD(ag) -} PyAsyncGenObject; +typedef struct _PyAsyncGenObject PyAsyncGenObject; PyAPI_DATA(PyTypeObject) PyAsyncGen_Type; PyAPI_DATA(PyTypeObject) _PyAsyncGenASend_Type; @@ -77,7 +47,6 @@ PyAPI_FUNC(PyObject *) PyAsyncGen_New(PyFrameObject *, #define PyAsyncGenASend_CheckExact(op) Py_IS_TYPE((op), &_PyAsyncGenASend_Type) - #undef _PyGenObject_HEAD #ifdef __cplusplus diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 9e4e9781216d27..bab92c771a76b1 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -54,6 +54,22 @@ enum _frameowner { FRAME_OWNED_BY_CSTACK = 3, }; +typedef struct _PyInterpreterFrame { + PyObject *f_executable; /* Strong reference (code object or None) */ + struct _PyInterpreterFrame *previous; + PyObject *f_funcobj; /* Strong reference. Only valid if not on C stack */ + PyObject *f_globals; /* Borrowed reference. Only valid if not on C stack */ + PyObject *f_builtins; /* Borrowed reference. Only valid if not on C stack */ + PyObject *f_locals; /* Strong reference, may be NULL. Only valid if not on C stack */ + PyFrameObject *frame_obj; /* Strong reference, may be NULL. Only valid if not on C stack */ + _Py_CODEUNIT *instr_ptr; /* Instruction currently executing (or about to begin) */ + int stacktop; /* Offset of TOS from localsplus */ + uint16_t return_offset; /* Only relevant during a function call */ + char owner; + /* Locals and stack */ + PyObject *localsplus[1]; +} _PyInterpreterFrame; + #define _PyInterpreterFrame_LASTI(IF) \ ((int)((IF)->instr_ptr - _PyCode_CODE(_PyFrame_GetCode(IF)))) @@ -291,14 +307,6 @@ _PyFrame_PushTrampolineUnchecked(PyThreadState *tstate, PyCodeObject *code, int return frame; } -static inline -PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame) -{ - assert(frame->owner == FRAME_OWNED_BY_GENERATOR); - size_t offset_in_gen = offsetof(PyGenObject, gi_iframe); - return (PyGenObject *)(((char *)frame) - offset_in_gen); -} - PyAPI_FUNC(_PyInterpreterFrame *) _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func, PyObject *locals, PyObject* const* args, diff --git a/Include/internal/pycore_genobject.h b/Include/internal/pycore_genobject.h index a853b4b0587c6d..f6d7e6d367177b 100644 --- a/Include/internal/pycore_genobject.h +++ b/Include/internal/pycore_genobject.h @@ -8,6 +8,50 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +#include "pycore_frame.h" + +/* _PyGenObject_HEAD defines the initial segment of generator + and coroutine objects. */ +#define _PyGenObject_HEAD(prefix) \ + PyObject_HEAD \ + /* List of weak reference. */ \ + PyObject *prefix##_weakreflist; \ + /* Name of the generator. */ \ + PyObject *prefix##_name; \ + /* Qualified name of the generator. */ \ + PyObject *prefix##_qualname; \ + _PyErr_StackItem prefix##_exc_state; \ + PyObject *prefix##_origin_or_finalizer; \ + char prefix##_hooks_inited; \ + char prefix##_closed; \ + char prefix##_running_async; \ + /* The frame */ \ + int8_t prefix##_frame_state; \ + struct _PyInterpreterFrame prefix##_iframe; \ + +struct _PyGenObject { + /* The gi_ prefix is intended to remind of generator-iterator. */ + _PyGenObject_HEAD(gi) +}; + +struct _PyCoroObject { + _PyGenObject_HEAD(cr) +}; + +struct _PyAsyncGenObject { + _PyGenObject_HEAD(ag) +}; + +#undef _PyGenObject_HEAD + +static inline +PyGenObject *_PyGen_GetGeneratorFromFrame(_PyInterpreterFrame *frame) +{ + assert(frame->owner == FRAME_OWNED_BY_GENERATOR); + size_t offset_in_gen = offsetof(PyGenObject, gi_iframe); + return (PyGenObject *)(((char *)frame) - offset_in_gen); +} + PyAPI_FUNC(PyObject *)_PyGen_yf(PyGenObject *); extern void _PyGen_Finalize(PyObject *self); diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 860669cfb7d674..2cb113b3d01be1 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -1338,7 +1338,7 @@ static bool frame_is_suspended(PyFrameObject *frame) { assert(!_PyFrame_IsIncomplete(frame->f_frame)); if (frame->f_frame->owner == FRAME_OWNED_BY_GENERATOR) { - PyGenObject *gen = _PyFrame_GetGenerator(frame->f_frame); + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame->f_frame); return FRAME_STATE_SUSPENDED(gen->gi_frame_state); } return false; @@ -1665,7 +1665,7 @@ static PyObject * frame_clear(PyFrameObject *f, PyObject *Py_UNUSED(ignored)) { if (f->f_frame->owner == FRAME_OWNED_BY_GENERATOR) { - PyGenObject *gen = _PyFrame_GetGenerator(f->f_frame); + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(f->f_frame); if (gen->gi_frame_state == FRAME_EXECUTING) { goto running; } @@ -2097,7 +2097,7 @@ PyFrame_GetGenerator(PyFrameObject *frame) if (frame->f_frame->owner != FRAME_OWNED_BY_GENERATOR) { return NULL; } - PyGenObject *gen = _PyFrame_GetGenerator(frame->f_frame); + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame->f_frame); return Py_NewRef(gen); } diff --git a/Python/bytecodes.c b/Python/bytecodes.c index c4927c8806cb58..a6fb862a6d476e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -1069,7 +1069,7 @@ dummy_func( inst(INSTRUMENTED_YIELD_VALUE, (retval -- unused)) { assert(frame != &entry_frame); frame->instr_ptr = next_instr; - PyGenObject *gen = _PyFrame_GetGenerator(frame); + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); gen->gi_frame_state = FRAME_SUSPENDED + oparg; @@ -1099,7 +1099,7 @@ dummy_func( assert(frame != &entry_frame); #endif frame->instr_ptr++; - PyGenObject *gen = _PyFrame_GetGenerator(frame); + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); gen->gi_frame_state = FRAME_SUSPENDED + oparg; diff --git a/Python/ceval.c b/Python/ceval.c index a8df045799d3fd..d36e15e55f57ab 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1711,7 +1711,7 @@ static void clear_gen_frame(PyThreadState *tstate, _PyInterpreterFrame * frame) { assert(frame->owner == FRAME_OWNED_BY_GENERATOR); - PyGenObject *gen = _PyFrame_GetGenerator(frame); + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); gen->gi_frame_state = FRAME_CLEARED; assert(tstate->exc_info == &gen->gi_exc_state); tstate->exc_info = gen->gi_exc_state.previous_item; diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 66acf0dc8b6a41..cdfffcdec9726e 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -1125,7 +1125,7 @@ assert(frame != &entry_frame); #endif frame->instr_ptr++; - PyGenObject *gen = _PyFrame_GetGenerator(frame); + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); gen->gi_frame_state = FRAME_SUSPENDED + oparg; diff --git a/Python/frame.c b/Python/frame.c index 2bb12823572028..7299a395efad28 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -112,7 +112,7 @@ _PyFrame_ClearExceptCode(_PyInterpreterFrame *frame) /* It is the responsibility of the owning generator/coroutine * to have cleared the enclosing generator, if any. */ assert(frame->owner != FRAME_OWNED_BY_GENERATOR || - _PyFrame_GetGenerator(frame)->gi_frame_state == FRAME_CLEARED); + _PyGen_GetGeneratorFromFrame(frame)->gi_frame_state == FRAME_CLEARED); // GH-99729: Clearing this frame can expose the stack (via finalizers). It's // crucial that this frame has been unlinked, and is no longer visible: assert(_PyThreadState_GET()->current_frame != frame); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index fe9f15ee107d7c..327a704467b0ba 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3461,7 +3461,7 @@ retval = stack_pointer[-1]; assert(frame != &entry_frame); frame->instr_ptr = next_instr; - PyGenObject *gen = _PyFrame_GetGenerator(frame); + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); gen->gi_frame_state = FRAME_SUSPENDED + oparg; @@ -6198,7 +6198,7 @@ assert(frame != &entry_frame); #endif frame->instr_ptr++; - PyGenObject *gen = _PyFrame_GetGenerator(frame); + PyGenObject *gen = _PyGen_GetGeneratorFromFrame(frame); assert(FRAME_SUSPENDED_YIELD_FROM == FRAME_SUSPENDED + 1); assert(oparg == 0 || oparg == 1); gen->gi_frame_state = FRAME_SUSPENDED + oparg; From 6a7c2a97a4d3f6f2cc7cfb453e10623b7bd21e58 Mon Sep 17 00:00:00 2001 From: Irit Katriel Date: Sun, 23 Jun 2024 12:48:33 +0100 Subject: [PATCH 5/5] remove calculation of tp_basicsize --- Objects/genobject.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Objects/genobject.c b/Objects/genobject.c index ec2d17aab3cfd6..445622e878bc93 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -813,8 +813,7 @@ static PyAsyncMethods gen_as_async = { PyTypeObject PyGen_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "generator", /* tp_name */ - offsetof(PyGenObject, gi_iframe) + - offsetof(_PyInterpreterFrame, localsplus), /* tp_basicsize */ + sizeof(PyGenObject), /* tp_basicsize */ sizeof(PyObject *), /* tp_itemsize */ /* methods */ (destructor)gen_dealloc, /* tp_dealloc */ @@ -1165,8 +1164,7 @@ static PyAsyncMethods coro_as_async = { PyTypeObject PyCoro_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "coroutine", /* tp_name */ - offsetof(PyCoroObject, cr_iframe) + - offsetof(_PyInterpreterFrame, localsplus), /* tp_basicsize */ + sizeof(PyCoroObject), /* tp_basicsize */ sizeof(PyObject *), /* tp_itemsize */ /* methods */ (destructor)gen_dealloc, /* tp_dealloc */ @@ -1581,8 +1579,7 @@ static PyAsyncMethods async_gen_as_async = { PyTypeObject PyAsyncGen_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "async_generator", /* tp_name */ - offsetof(PyAsyncGenObject, ag_iframe) + - offsetof(_PyInterpreterFrame, localsplus), /* tp_basicsize */ + sizeof(PyAsyncGenObject), /* tp_basicsize */ sizeof(PyObject *), /* tp_itemsize */ /* methods */ (destructor)gen_dealloc, /* tp_dealloc */