mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									f34d181fa1
								
							
						
					
					
						commit
						299483c95d
					
				
					 7 changed files with 128 additions and 145 deletions
				
			
		|  | @ -14,7 +14,6 @@ extern "C" { | ||||||
| #define _PyGenObject_HEAD(prefix)                                           \ | #define _PyGenObject_HEAD(prefix)                                           \ | ||||||
|     PyObject_HEAD                                                           \ |     PyObject_HEAD                                                           \ | ||||||
|     /* Note: gi_frame can be NULL if the generator is "finished" */         \ |     /* Note: gi_frame can be NULL if the generator is "finished" */         \ | ||||||
|     struct _interpreter_frame *prefix##_xframe;                             \ |  | ||||||
|     /* The code object backing the generator */                             \ |     /* The code object backing the generator */                             \ | ||||||
|     PyCodeObject *prefix##_code;                                            \ |     PyCodeObject *prefix##_code;                                            \ | ||||||
|     /* List of weak reference. */                                           \ |     /* List of weak reference. */                                           \ | ||||||
|  | @ -23,7 +22,14 @@ extern "C" { | ||||||
|     PyObject *prefix##_name;                                                \ |     PyObject *prefix##_name;                                                \ | ||||||
|     /* Qualified name of the generator. */                                  \ |     /* Qualified name of the generator. */                                  \ | ||||||
|     PyObject *prefix##_qualname;                                            \ |     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 { | typedef struct { | ||||||
|     /* The gi_ prefix is intended to remind of generator-iterator. */ |     /* The gi_ prefix is intended to remind of generator-iterator. */ | ||||||
|  | @ -48,7 +54,6 @@ PyAPI_FUNC(void) _PyGen_Finalize(PyObject *self); | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     _PyGenObject_HEAD(cr) |     _PyGenObject_HEAD(cr) | ||||||
|     PyObject *cr_origin; |  | ||||||
| } PyCoroObject; | } PyCoroObject; | ||||||
| 
 | 
 | ||||||
| PyAPI_DATA(PyTypeObject) PyCoro_Type; | PyAPI_DATA(PyTypeObject) PyCoro_Type; | ||||||
|  | @ -64,18 +69,6 @@ PyAPI_FUNC(PyObject *) PyCoro_New(PyFrameObject *, | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     _PyGenObject_HEAD(ag) |     _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; | } PyAsyncGenObject; | ||||||
| 
 | 
 | ||||||
| PyAPI_DATA(PyTypeObject) PyAsyncGen_Type; | PyAPI_DATA(PyTypeObject) PyAsyncGen_Type; | ||||||
|  |  | ||||||
|  | @ -113,7 +113,7 @@ static inline void _Py_LeaveRecursiveCall_inline(void)  { | ||||||
| 
 | 
 | ||||||
| struct _interpreter_frame *_PyEval_GetFrame(void); | struct _interpreter_frame *_PyEval_GetFrame(void); | ||||||
| 
 | 
 | ||||||
| PyObject *_Py_MakeCoro(PyFunctionObject *func, struct _interpreter_frame *); | PyObject *_Py_MakeCoro(PyFunctionObject *func); | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -74,7 +74,7 @@ static inline void _PyFrame_StackPush(InterpreterFrame *f, PyObject *value) { | ||||||
| 
 | 
 | ||||||
| #define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *)) | #define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *)) | ||||||
| 
 | 
 | ||||||
| InterpreterFrame *_PyFrame_Copy(InterpreterFrame *frame); | void _PyFrame_Copy(InterpreterFrame *src, InterpreterFrame *dest); | ||||||
| 
 | 
 | ||||||
| static inline void | static inline void | ||||||
| _PyFrame_InitializeSpecials( | _PyFrame_InitializeSpecials( | ||||||
|  |  | ||||||
|  | @ -1340,7 +1340,7 @@ def bar(cls): | ||||||
|             check(bar, size('PP')) |             check(bar, size('PP')) | ||||||
|         # generator |         # generator | ||||||
|         def get_gen(): yield 1 |         def get_gen(): yield 1 | ||||||
|         check(get_gen(), size('P2PPP4P')) |         check(get_gen(), size('P2PPP4P4c8P2iciP')) | ||||||
|         # iterator |         # iterator | ||||||
|         check(iter('abc'), size('lP')) |         check(iter('abc'), size('lP')) | ||||||
|         # callable-iterator |         # callable-iterator | ||||||
|  |  | ||||||
|  | @ -36,8 +36,8 @@ gen_traverse(PyGenObject *gen, visitproc visit, void *arg) | ||||||
|     Py_VISIT(gen->gi_code); |     Py_VISIT(gen->gi_code); | ||||||
|     Py_VISIT(gen->gi_name); |     Py_VISIT(gen->gi_name); | ||||||
|     Py_VISIT(gen->gi_qualname); |     Py_VISIT(gen->gi_qualname); | ||||||
|     InterpreterFrame *frame = gen->gi_xframe; |     if (gen->gi_frame_valid) { | ||||||
|     if (frame != NULL) { |         InterpreterFrame *frame = (InterpreterFrame *)(gen->gi_iframe); | ||||||
|         assert(frame->frame_obj == NULL || frame->frame_obj->f_owns_frame == 0); |         assert(frame->frame_obj == NULL || frame->frame_obj->f_owns_frame == 0); | ||||||
|         int err = _PyFrame_Traverse(frame, visit, arg); |         int err = _PyFrame_Traverse(frame, visit, arg); | ||||||
|         if (err) { |         if (err) { | ||||||
|  | @ -56,14 +56,14 @@ _PyGen_Finalize(PyObject *self) | ||||||
|     PyObject *res = NULL; |     PyObject *res = NULL; | ||||||
|     PyObject *error_type, *error_value, *error_traceback; |     PyObject *error_type, *error_value, *error_traceback; | ||||||
| 
 | 
 | ||||||
|     if (gen->gi_xframe == NULL ||  _PyFrameHasCompleted(gen->gi_xframe)) { |     if (gen->gi_frame_valid == 0 || _PyFrameHasCompleted((InterpreterFrame *)gen->gi_iframe)) { | ||||||
|         /* Generator isn't paused, so no need to close */ |         /* Generator isn't paused, so no need to close */ | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (PyAsyncGen_CheckExact(self)) { |     if (PyAsyncGen_CheckExact(self)) { | ||||||
|         PyAsyncGenObject *agen = (PyAsyncGenObject*)self; |         PyAsyncGenObject *agen = (PyAsyncGenObject*)self; | ||||||
|         PyObject *finalizer = agen->ag_finalizer; |         PyObject *finalizer = agen->ag_origin_or_finalizer; | ||||||
|         if (finalizer && !agen->ag_closed) { |         if (finalizer && !agen->ag_closed) { | ||||||
|             /* Save the current exception, if any. */ |             /* Save the current exception, if any. */ | ||||||
|             PyErr_Fetch(&error_type, &error_value, &error_traceback); |             PyErr_Fetch(&error_type, &error_value, &error_traceback); | ||||||
|  | @ -88,7 +88,7 @@ _PyGen_Finalize(PyObject *self) | ||||||
|        issue a RuntimeWarning. */ |        issue a RuntimeWarning. */ | ||||||
|     if (gen->gi_code != NULL && |     if (gen->gi_code != NULL && | ||||||
|         ((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE && |         ((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE && | ||||||
|         gen->gi_xframe->f_lasti == -1) |         ((InterpreterFrame *)gen->gi_iframe)->f_lasti == -1) | ||||||
|     { |     { | ||||||
|         _PyErr_WarnUnawaitedCoroutine((PyObject *)gen); |         _PyErr_WarnUnawaitedCoroutine((PyObject *)gen); | ||||||
|     } |     } | ||||||
|  | @ -129,18 +129,17 @@ gen_dealloc(PyGenObject *gen) | ||||||
|         /* We have to handle this case for asynchronous generators
 |         /* We have to handle this case for asynchronous generators
 | ||||||
|            right here, because this code has to be between UNTRACK |            right here, because this code has to be between UNTRACK | ||||||
|            and GC_Del. */ |            and GC_Del. */ | ||||||
|         Py_CLEAR(((PyAsyncGenObject*)gen)->ag_finalizer); |         Py_CLEAR(((PyAsyncGenObject*)gen)->ag_origin_or_finalizer); | ||||||
|     } |     } | ||||||
|     InterpreterFrame *frame = gen->gi_xframe; |     if (gen->gi_frame_valid) { | ||||||
|     if (frame != NULL) { |         InterpreterFrame *frame = (InterpreterFrame *)gen->gi_iframe; | ||||||
|         gen->gi_xframe = NULL; |         gen->gi_frame_valid = 0; | ||||||
|         frame->generator = NULL; |         frame->generator = NULL; | ||||||
|         frame->previous = NULL; |         frame->previous = NULL; | ||||||
|         _PyFrame_Clear(frame); |         _PyFrame_Clear(frame); | ||||||
|         PyMem_Free(frame); |  | ||||||
|     } |     } | ||||||
|     if (((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE) { |     if (((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE) { | ||||||
|         Py_CLEAR(((PyCoroObject *)gen)->cr_origin); |         Py_CLEAR(((PyCoroObject *)gen)->cr_origin_or_finalizer); | ||||||
|     } |     } | ||||||
|     Py_CLEAR(gen->gi_code); |     Py_CLEAR(gen->gi_code); | ||||||
|     Py_CLEAR(gen->gi_name); |     Py_CLEAR(gen->gi_name); | ||||||
|  | @ -154,11 +153,11 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, | ||||||
|              int exc, int closing) |              int exc, int closing) | ||||||
| { | { | ||||||
|     PyThreadState *tstate = _PyThreadState_GET(); |     PyThreadState *tstate = _PyThreadState_GET(); | ||||||
|     InterpreterFrame *frame = gen->gi_xframe; |     InterpreterFrame *frame = (InterpreterFrame *)gen->gi_iframe; | ||||||
|     PyObject *result; |     PyObject *result; | ||||||
| 
 | 
 | ||||||
|     *presult = NULL; |     *presult = NULL; | ||||||
|     if (frame != NULL && _PyFrame_IsExecuting(frame)) { |     if (gen->gi_frame_valid && _PyFrame_IsExecuting(frame)) { | ||||||
|         const char *msg = "generator already executing"; |         const char *msg = "generator already executing"; | ||||||
|         if (PyCoro_CheckExact(gen)) { |         if (PyCoro_CheckExact(gen)) { | ||||||
|             msg = "coroutine already executing"; |             msg = "coroutine already executing"; | ||||||
|  | @ -169,7 +168,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, | ||||||
|         PyErr_SetString(PyExc_ValueError, msg); |         PyErr_SetString(PyExc_ValueError, msg); | ||||||
|         return PYGEN_ERROR; |         return PYGEN_ERROR; | ||||||
|     } |     } | ||||||
|     if (frame == NULL || _PyFrameHasCompleted(frame)) { |     if (gen->gi_frame_valid == 0 || _PyFrameHasCompleted(frame)) { | ||||||
|         if (PyCoro_CheckExact(gen) && !closing) { |         if (PyCoro_CheckExact(gen) && !closing) { | ||||||
|             /* `gen` is an exhausted coroutine: raise an error,
 |             /* `gen` is an exhausted coroutine: raise an error,
 | ||||||
|                except when called from gen_close(), which should |                except when called from gen_close(), which should | ||||||
|  | @ -188,6 +187,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, | ||||||
|         return PYGEN_ERROR; |         return PYGEN_ERROR; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     assert(gen->gi_frame_valid); | ||||||
|     assert(_PyFrame_IsRunnable(frame)); |     assert(_PyFrame_IsRunnable(frame)); | ||||||
|     /* Push arg onto the frame's value stack */ |     /* Push arg onto the frame's value stack */ | ||||||
|     result = arg ? arg : Py_None; |     result = arg ? arg : Py_None; | ||||||
|  | @ -254,9 +254,8 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, | ||||||
|     _PyErr_ClearExcState(&gen->gi_exc_state); |     _PyErr_ClearExcState(&gen->gi_exc_state); | ||||||
| 
 | 
 | ||||||
|     frame->generator = NULL; |     frame->generator = NULL; | ||||||
|     gen->gi_xframe = NULL; |     gen->gi_frame_valid = 0; | ||||||
|     _PyFrame_Clear(frame); |     _PyFrame_Clear(frame); | ||||||
|     PyMem_Free(frame); |  | ||||||
|     *presult = result; |     *presult = result; | ||||||
|     return result ? PYGEN_RETURN : PYGEN_ERROR; |     return result ? PYGEN_RETURN : PYGEN_ERROR; | ||||||
| } | } | ||||||
|  | @ -337,8 +336,8 @@ _PyGen_yf(PyGenObject *gen) | ||||||
| { | { | ||||||
|     PyObject *yf = NULL; |     PyObject *yf = NULL; | ||||||
| 
 | 
 | ||||||
|     if (gen->gi_xframe) { |     if (gen->gi_frame_valid) { | ||||||
|         InterpreterFrame *frame = gen->gi_xframe; |         InterpreterFrame *frame = (InterpreterFrame *)gen->gi_iframe; | ||||||
|         PyObject *bytecode = gen->gi_code->co_code; |         PyObject *bytecode = gen->gi_code->co_code; | ||||||
|         unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode); |         unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode); | ||||||
| 
 | 
 | ||||||
|  | @ -367,10 +366,11 @@ gen_close(PyGenObject *gen, PyObject *args) | ||||||
|     int err = 0; |     int err = 0; | ||||||
| 
 | 
 | ||||||
|     if (yf) { |     if (yf) { | ||||||
|         PyFrameState state = gen->gi_xframe->f_state; |         InterpreterFrame *frame = (InterpreterFrame *)gen->gi_iframe; | ||||||
|         gen->gi_xframe->f_state = FRAME_EXECUTING; |         PyFrameState state = frame->f_state; | ||||||
|  |         frame->f_state = FRAME_EXECUTING; | ||||||
|         err = gen_close_iter(yf); |         err = gen_close_iter(yf); | ||||||
|         gen->gi_xframe->f_state = state; |         frame->f_state = state; | ||||||
|         Py_DECREF(yf); |         Py_DECREF(yf); | ||||||
|     } |     } | ||||||
|     if (err == 0) |     if (err == 0) | ||||||
|  | @ -408,6 +408,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, | ||||||
|     _Py_IDENTIFIER(throw); |     _Py_IDENTIFIER(throw); | ||||||
| 
 | 
 | ||||||
|     if (yf) { |     if (yf) { | ||||||
|  |         InterpreterFrame *frame = (InterpreterFrame *)gen->gi_iframe; | ||||||
|         PyObject *ret; |         PyObject *ret; | ||||||
|         int err; |         int err; | ||||||
|         if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && |         if (PyErr_GivenExceptionMatches(typ, PyExc_GeneratorExit) && | ||||||
|  | @ -417,10 +418,10 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, | ||||||
|                We have to allow some awaits to work it through, hence the |                We have to allow some awaits to work it through, hence the | ||||||
|                `close_on_genexit` parameter here. |                `close_on_genexit` parameter here. | ||||||
|             */ |             */ | ||||||
|             PyFrameState state = gen->gi_xframe->f_state; |             PyFrameState state = frame->f_state; | ||||||
|             gen->gi_xframe->f_state = FRAME_EXECUTING; |             frame->f_state = FRAME_EXECUTING; | ||||||
|             err = gen_close_iter(yf); |             err = gen_close_iter(yf); | ||||||
|             gen->gi_xframe->f_state = state; |             frame->f_state = state; | ||||||
|             Py_DECREF(yf); |             Py_DECREF(yf); | ||||||
|             if (err < 0) |             if (err < 0) | ||||||
|                 return gen_send_ex(gen, Py_None, 1, 0); |                 return gen_send_ex(gen, Py_None, 1, 0); | ||||||
|  | @ -429,9 +430,6 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, | ||||||
|         if (PyGen_CheckExact(yf) || PyCoro_CheckExact(yf)) { |         if (PyGen_CheckExact(yf) || PyCoro_CheckExact(yf)) { | ||||||
|             /* `yf` is a generator or a coroutine. */ |             /* `yf` is a generator or a coroutine. */ | ||||||
|             PyThreadState *tstate = _PyThreadState_GET(); |             PyThreadState *tstate = _PyThreadState_GET(); | ||||||
|             InterpreterFrame *frame = gen->gi_xframe; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|             /* Since we are fast-tracking things by skipping the eval loop,
 |             /* Since we are fast-tracking things by skipping the eval loop,
 | ||||||
|                we need to update the current frame so the stack trace |                we need to update the current frame so the stack trace | ||||||
|                will be reported correctly to the user. */ |                will be reported correctly to the user. */ | ||||||
|  | @ -442,11 +440,11 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, | ||||||
|             tstate->cframe->current_frame = frame; |             tstate->cframe->current_frame = frame; | ||||||
|             /* Close the generator that we are currently iterating with
 |             /* Close the generator that we are currently iterating with
 | ||||||
|                'yield from' or awaiting on with 'await'. */ |                'yield from' or awaiting on with 'await'. */ | ||||||
|             PyFrameState state = gen->gi_xframe->f_state; |             PyFrameState state = frame->f_state; | ||||||
|             gen->gi_xframe->f_state = FRAME_EXECUTING; |             frame->f_state = FRAME_EXECUTING; | ||||||
|             ret = _gen_throw((PyGenObject *)yf, close_on_genexit, |             ret = _gen_throw((PyGenObject *)yf, close_on_genexit, | ||||||
|                              typ, val, tb); |                              typ, val, tb); | ||||||
|             gen->gi_xframe->f_state = state; |             frame->f_state = state; | ||||||
|             tstate->cframe->current_frame = prev; |             tstate->cframe->current_frame = prev; | ||||||
|             frame->previous = NULL; |             frame->previous = NULL; | ||||||
|         } else { |         } else { | ||||||
|  | @ -460,22 +458,23 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, | ||||||
|                 Py_DECREF(yf); |                 Py_DECREF(yf); | ||||||
|                 goto throw_here; |                 goto throw_here; | ||||||
|             } |             } | ||||||
|             PyFrameState state = gen->gi_xframe->f_state; |             PyFrameState state = frame->f_state; | ||||||
|             gen->gi_xframe->f_state = FRAME_EXECUTING; |             frame->f_state = FRAME_EXECUTING; | ||||||
|             ret = PyObject_CallFunctionObjArgs(meth, typ, val, tb, NULL); |             ret = PyObject_CallFunctionObjArgs(meth, typ, val, tb, NULL); | ||||||
|             gen->gi_xframe->f_state = state; |             frame->f_state = state; | ||||||
|             Py_DECREF(meth); |             Py_DECREF(meth); | ||||||
|         } |         } | ||||||
|         Py_DECREF(yf); |         Py_DECREF(yf); | ||||||
|         if (!ret) { |         if (!ret) { | ||||||
|             PyObject *val; |             PyObject *val; | ||||||
|             /* Pop subiterator from stack */ |             /* Pop subiterator from stack */ | ||||||
|             ret = _PyFrame_StackPop(gen->gi_xframe); |             assert(gen->gi_frame_valid); | ||||||
|  |             ret = _PyFrame_StackPop((InterpreterFrame *)gen->gi_iframe); | ||||||
|             assert(ret == yf); |             assert(ret == yf); | ||||||
|             Py_DECREF(ret); |             Py_DECREF(ret); | ||||||
|             /* Termination repetition of YIELD_FROM */ |             /* Termination repetition of YIELD_FROM */ | ||||||
|             assert(gen->gi_xframe->f_lasti >= 0); |             assert(frame->f_lasti >= 0); | ||||||
|             gen->gi_xframe->f_lasti += 1; |             frame->f_lasti += 1; | ||||||
|             if (_PyGen_FetchStopIterationValue(&val) == 0) { |             if (_PyGen_FetchStopIterationValue(&val) == 0) { | ||||||
|                 ret = gen_send(gen, val); |                 ret = gen_send(gen, val); | ||||||
|                 Py_DECREF(val); |                 Py_DECREF(val); | ||||||
|  | @ -732,10 +731,10 @@ gen_getyieldfrom(PyGenObject *gen, void *Py_UNUSED(ignored)) | ||||||
| static PyObject * | static PyObject * | ||||||
| gen_getrunning(PyGenObject *gen, void *Py_UNUSED(ignored)) | gen_getrunning(PyGenObject *gen, void *Py_UNUSED(ignored)) | ||||||
| { | { | ||||||
|     if (gen->gi_xframe == NULL) { |     if (gen->gi_frame_valid == 0) { | ||||||
|         Py_RETURN_FALSE; |         Py_RETURN_FALSE; | ||||||
|     } |     } | ||||||
|     return PyBool_FromLong(_PyFrame_IsExecuting(gen->gi_xframe)); |     return PyBool_FromLong(_PyFrame_IsExecuting((InterpreterFrame *)gen->gi_iframe)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
|  | @ -744,10 +743,10 @@ _gen_getframe(PyGenObject *gen, const char *const name) | ||||||
|     if (PySys_Audit("object.__getattr__", "Os", gen, name) < 0) { |     if (PySys_Audit("object.__getattr__", "Os", gen, name) < 0) { | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|     if (gen->gi_xframe == NULL) { |     if (gen->gi_frame_valid == 0) { | ||||||
|         Py_RETURN_NONE; |         Py_RETURN_NONE; | ||||||
|     } |     } | ||||||
|     return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject(gen->gi_xframe)); |     return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject((InterpreterFrame *)gen->gi_iframe)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
|  | @ -773,10 +772,24 @@ static PyMemberDef gen_memberlist[] = { | ||||||
|     {NULL}      /* Sentinel */ |     {NULL}      /* Sentinel */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static PyObject * | ||||||
|  | gen_sizeof(PyGenObject *gen, PyObject *Py_UNUSED(ignored)) | ||||||
|  | { | ||||||
|  |     Py_ssize_t res; | ||||||
|  |     res = offsetof(PyGenObject, gi_iframe) + offsetof(InterpreterFrame, localsplus); | ||||||
|  |     PyCodeObject *code = gen->gi_code; | ||||||
|  |     res += (code->co_nlocalsplus+code->co_stacksize) * sizeof(PyObject *); | ||||||
|  |     return PyLong_FromSsize_t(res); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PyDoc_STRVAR(sizeof__doc__, | ||||||
|  | "gen.__sizeof__() -> size of gen in memory, in bytes"); | ||||||
|  | 
 | ||||||
| static PyMethodDef gen_methods[] = { | static PyMethodDef gen_methods[] = { | ||||||
|     {"send",(PyCFunction)gen_send, METH_O, send_doc}, |     {"send",(PyCFunction)gen_send, METH_O, send_doc}, | ||||||
|     {"throw",(PyCFunction)gen_throw, METH_VARARGS, throw_doc}, |     {"throw",(PyCFunction)gen_throw, METH_VARARGS, throw_doc}, | ||||||
|     {"close",(PyCFunction)gen_close, METH_NOARGS, close_doc}, |     {"close",(PyCFunction)gen_close, METH_NOARGS, close_doc}, | ||||||
|  |     {"__sizeof__", (PyCFunction)gen_sizeof, METH_NOARGS, sizeof__doc__}, | ||||||
|     {NULL, NULL}        /* Sentinel */ |     {NULL, NULL}        /* Sentinel */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -791,8 +804,9 @@ static PyAsyncMethods gen_as_async = { | ||||||
| PyTypeObject PyGen_Type = { | PyTypeObject PyGen_Type = { | ||||||
|     PyVarObject_HEAD_INIT(&PyType_Type, 0) |     PyVarObject_HEAD_INIT(&PyType_Type, 0) | ||||||
|     "generator",                                /* tp_name */ |     "generator",                                /* tp_name */ | ||||||
|     sizeof(PyGenObject),                        /* tp_basicsize */ |     offsetof(PyGenObject, gi_iframe) + | ||||||
|     0,                                          /* tp_itemsize */ |     offsetof(InterpreterFrame, localsplus),       /* tp_basicsize */ | ||||||
|  |     sizeof(PyObject *),                         /* tp_itemsize */ | ||||||
|     /* methods */ |     /* methods */ | ||||||
|     (destructor)gen_dealloc,                    /* tp_dealloc */ |     (destructor)gen_dealloc,                    /* tp_dealloc */ | ||||||
|     0,                                          /* tp_vectorcall_offset */ |     0,                                          /* tp_vectorcall_offset */ | ||||||
|  | @ -842,18 +856,16 @@ PyTypeObject PyGen_Type = { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| make_gen(PyTypeObject *type, PyFunctionObject *func, InterpreterFrame *frame) | make_gen(PyTypeObject *type, PyFunctionObject *func) | ||||||
| { | { | ||||||
|     PyGenObject *gen = PyObject_GC_New(PyGenObject, type); |     PyCodeObject *code = (PyCodeObject *)func->func_code; | ||||||
|  |     int slots = code->co_nlocalsplus + code->co_stacksize; | ||||||
|  |     PyGenObject *gen = PyObject_GC_NewVar(PyGenObject, type, slots); | ||||||
|     if (gen == NULL) { |     if (gen == NULL) { | ||||||
|         assert(frame->frame_obj == NULL); |  | ||||||
|         _PyFrame_Clear(frame); |  | ||||||
|         PyMem_Free(frame); |  | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|     gen->gi_xframe = frame; |     gen->gi_frame_valid = 0; | ||||||
|     frame->generator = (PyObject *)gen; |     gen->gi_code = (PyCodeObject *)func->func_code; | ||||||
|     gen->gi_code = frame->f_code; |  | ||||||
|     Py_INCREF(gen->gi_code); |     Py_INCREF(gen->gi_code); | ||||||
|     gen->gi_weakreflist = NULL; |     gen->gi_weakreflist = NULL; | ||||||
|     gen->gi_exc_state.exc_type = NULL; |     gen->gi_exc_state.exc_type = NULL; | ||||||
|  | @ -878,28 +890,28 @@ static PyObject * | ||||||
| compute_cr_origin(int origin_depth); | compute_cr_origin(int origin_depth); | ||||||
| 
 | 
 | ||||||
| PyObject * | PyObject * | ||||||
| _Py_MakeCoro(PyFunctionObject *func, InterpreterFrame *frame) | _Py_MakeCoro(PyFunctionObject *func) | ||||||
| { | { | ||||||
|     int coro_flags = ((PyCodeObject *)func->func_code)->co_flags & |     int coro_flags = ((PyCodeObject *)func->func_code)->co_flags & | ||||||
|         (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR); |         (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR); | ||||||
|     assert(coro_flags); |     assert(coro_flags); | ||||||
|     if (coro_flags == CO_GENERATOR) { |     if (coro_flags == CO_GENERATOR) { | ||||||
|         return make_gen(&PyGen_Type, func, frame); |         return make_gen(&PyGen_Type, func); | ||||||
|     } |     } | ||||||
|     if (coro_flags == CO_ASYNC_GENERATOR) { |     if (coro_flags == CO_ASYNC_GENERATOR) { | ||||||
|         PyAsyncGenObject *o; |         PyAsyncGenObject *o; | ||||||
|         o = (PyAsyncGenObject *)make_gen(&PyAsyncGen_Type, func, frame); |         o = (PyAsyncGenObject *)make_gen(&PyAsyncGen_Type, func); | ||||||
|         if (o == NULL) { |         if (o == NULL) { | ||||||
|             return NULL; |             return NULL; | ||||||
|         } |         } | ||||||
|         o->ag_finalizer = NULL; |         o->ag_origin_or_finalizer = NULL; | ||||||
|         o->ag_closed = 0; |         o->ag_closed = 0; | ||||||
|         o->ag_hooks_inited = 0; |         o->ag_hooks_inited = 0; | ||||||
|         o->ag_running_async = 0; |         o->ag_running_async = 0; | ||||||
|         return (PyObject*)o; |         return (PyObject*)o; | ||||||
|     } |     } | ||||||
|     assert (coro_flags == CO_COROUTINE); |     assert (coro_flags == CO_COROUTINE); | ||||||
|     PyObject *coro = make_gen(&PyCoro_Type, func, frame); |     PyObject *coro = make_gen(&PyCoro_Type, func); | ||||||
|     if (!coro) { |     if (!coro) { | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|  | @ -907,16 +919,15 @@ _Py_MakeCoro(PyFunctionObject *func, InterpreterFrame *frame) | ||||||
|     int origin_depth = tstate->coroutine_origin_tracking_depth; |     int origin_depth = tstate->coroutine_origin_tracking_depth; | ||||||
| 
 | 
 | ||||||
|     if (origin_depth == 0) { |     if (origin_depth == 0) { | ||||||
|         ((PyCoroObject *)coro)->cr_origin = NULL; |         ((PyCoroObject *)coro)->cr_origin_or_finalizer = NULL; | ||||||
|     } else { |     } else { | ||||||
|         PyObject *cr_origin = compute_cr_origin(origin_depth); |         PyObject *cr_origin = compute_cr_origin(origin_depth); | ||||||
|         ((PyCoroObject *)coro)->cr_origin = cr_origin; |         ((PyCoroObject *)coro)->cr_origin_or_finalizer = cr_origin; | ||||||
|         if (!cr_origin) { |         if (!cr_origin) { | ||||||
|             Py_DECREF(coro); |             Py_DECREF(coro); | ||||||
|             return NULL; |             return NULL; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     return coro; |     return coro; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -924,27 +935,27 @@ static PyObject * | ||||||
| gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f, | gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f, | ||||||
|                       PyObject *name, PyObject *qualname) |                       PyObject *name, PyObject *qualname) | ||||||
| { | { | ||||||
|     PyGenObject *gen = PyObject_GC_New(PyGenObject, type); |     PyCodeObject *code = f->f_frame->f_code; | ||||||
|  |     int size = code->co_nlocalsplus + code->co_stacksize; | ||||||
|  |     PyGenObject *gen = PyObject_GC_NewVar(PyGenObject, type, size); | ||||||
|     if (gen == NULL) { |     if (gen == NULL) { | ||||||
|         Py_DECREF(f); |         Py_DECREF(f); | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
| 
 |     /* Copy the frame */ | ||||||
|     /* Take ownership of the frame */ |  | ||||||
|     assert(f->f_frame->frame_obj == NULL); |     assert(f->f_frame->frame_obj == NULL); | ||||||
|     assert(f->f_owns_frame); |     assert(f->f_owns_frame); | ||||||
|     gen->gi_xframe = _PyFrame_Copy((InterpreterFrame *)f->_f_frame_data); |     InterpreterFrame *frame = (InterpreterFrame *)gen->gi_iframe; | ||||||
|     if (gen->gi_xframe == NULL) { |     _PyFrame_Copy((InterpreterFrame *)f->_f_frame_data, frame); | ||||||
|         Py_DECREF(f); |     gen->gi_frame_valid = 1; | ||||||
|         Py_DECREF(gen); |     assert(frame->frame_obj == f); | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|     gen->gi_xframe->frame_obj = f; |  | ||||||
|     f->f_owns_frame = 0; |     f->f_owns_frame = 0; | ||||||
|     gen->gi_xframe->generator = (PyObject *) gen; |     f->f_frame = frame; | ||||||
|  |     frame->generator = (PyObject *) gen; | ||||||
|     assert(PyObject_GC_IsTracked((PyObject *)f)); |     assert(PyObject_GC_IsTracked((PyObject *)f)); | ||||||
| 
 |  | ||||||
|     gen->gi_code = PyFrame_GetCode(f); |     gen->gi_code = PyFrame_GetCode(f); | ||||||
|  |     Py_INCREF(gen->gi_code); | ||||||
|  |     Py_DECREF(f); | ||||||
|     gen->gi_weakreflist = NULL; |     gen->gi_weakreflist = NULL; | ||||||
|     gen->gi_exc_state.exc_type = NULL; |     gen->gi_exc_state.exc_type = NULL; | ||||||
|     gen->gi_exc_state.exc_value = NULL; |     gen->gi_exc_state.exc_value = NULL; | ||||||
|  | @ -1077,10 +1088,10 @@ coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored)) | ||||||
| static PyObject * | static PyObject * | ||||||
| cr_getrunning(PyCoroObject *coro, void *Py_UNUSED(ignored)) | cr_getrunning(PyCoroObject *coro, void *Py_UNUSED(ignored)) | ||||||
| { | { | ||||||
|     if (coro->cr_xframe == NULL) { |     if (coro->cr_frame_valid == 0) { | ||||||
|         Py_RETURN_FALSE; |         Py_RETURN_FALSE; | ||||||
|     } |     } | ||||||
|     return PyBool_FromLong(_PyFrame_IsExecuting(coro->cr_xframe)); |     return PyBool_FromLong(_PyFrame_IsExecuting((InterpreterFrame *)coro->cr_iframe)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
|  | @ -1104,7 +1115,7 @@ static PyGetSetDef coro_getsetlist[] = { | ||||||
| 
 | 
 | ||||||
| static PyMemberDef coro_memberlist[] = { | static PyMemberDef coro_memberlist[] = { | ||||||
|     {"cr_code",      T_OBJECT, offsetof(PyCoroObject, cr_code),     READONLY|PY_AUDIT_READ}, |     {"cr_code",      T_OBJECT, offsetof(PyCoroObject, cr_code),     READONLY|PY_AUDIT_READ}, | ||||||
|     {"cr_origin",    T_OBJECT, offsetof(PyCoroObject, cr_origin),   READONLY}, |     {"cr_origin",    T_OBJECT, offsetof(PyCoroObject, cr_origin_or_finalizer),   READONLY}, | ||||||
|     {NULL}      /* Sentinel */ |     {NULL}      /* Sentinel */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -1123,6 +1134,7 @@ static PyMethodDef coro_methods[] = { | ||||||
|     {"send",(PyCFunction)gen_send, METH_O, coro_send_doc}, |     {"send",(PyCFunction)gen_send, METH_O, coro_send_doc}, | ||||||
|     {"throw",(PyCFunction)gen_throw, METH_VARARGS, coro_throw_doc}, |     {"throw",(PyCFunction)gen_throw, METH_VARARGS, coro_throw_doc}, | ||||||
|     {"close",(PyCFunction)gen_close, METH_NOARGS, coro_close_doc}, |     {"close",(PyCFunction)gen_close, METH_NOARGS, coro_close_doc}, | ||||||
|  |     {"__sizeof__", (PyCFunction)gen_sizeof, METH_NOARGS, sizeof__doc__}, | ||||||
|     {NULL, NULL}        /* Sentinel */ |     {NULL, NULL}        /* Sentinel */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -1136,8 +1148,9 @@ static PyAsyncMethods coro_as_async = { | ||||||
| PyTypeObject PyCoro_Type = { | PyTypeObject PyCoro_Type = { | ||||||
|     PyVarObject_HEAD_INIT(&PyType_Type, 0) |     PyVarObject_HEAD_INIT(&PyType_Type, 0) | ||||||
|     "coroutine",                                /* tp_name */ |     "coroutine",                                /* tp_name */ | ||||||
|     sizeof(PyCoroObject),                       /* tp_basicsize */ |     offsetof(PyCoroObject, cr_iframe) + | ||||||
|     0,                                          /* tp_itemsize */ |     offsetof(InterpreterFrame, localsplus),       /* tp_basicsize */ | ||||||
|  |     sizeof(PyObject *),                         /* tp_itemsize */ | ||||||
|     /* methods */ |     /* methods */ | ||||||
|     (destructor)gen_dealloc,                    /* tp_dealloc */ |     (destructor)gen_dealloc,                    /* tp_dealloc */ | ||||||
|     0,                                          /* tp_vectorcall_offset */ |     0,                                          /* tp_vectorcall_offset */ | ||||||
|  | @ -1318,10 +1331,10 @@ PyCoro_New(PyFrameObject *f, PyObject *name, PyObject *qualname) | ||||||
|     int origin_depth = tstate->coroutine_origin_tracking_depth; |     int origin_depth = tstate->coroutine_origin_tracking_depth; | ||||||
| 
 | 
 | ||||||
|     if (origin_depth == 0) { |     if (origin_depth == 0) { | ||||||
|         ((PyCoroObject *)coro)->cr_origin = NULL; |         ((PyCoroObject *)coro)->cr_origin_or_finalizer = NULL; | ||||||
|     } else { |     } else { | ||||||
|         PyObject *cr_origin = compute_cr_origin(origin_depth); |         PyObject *cr_origin = compute_cr_origin(origin_depth); | ||||||
|         ((PyCoroObject *)coro)->cr_origin = cr_origin; |         ((PyCoroObject *)coro)->cr_origin_or_finalizer = cr_origin; | ||||||
|         if (!cr_origin) { |         if (!cr_origin) { | ||||||
|             Py_DECREF(coro); |             Py_DECREF(coro); | ||||||
|             return NULL; |             return NULL; | ||||||
|  | @ -1382,7 +1395,7 @@ typedef struct _PyAsyncGenWrappedValue { | ||||||
| static int | static int | ||||||
| async_gen_traverse(PyAsyncGenObject *gen, visitproc visit, void *arg) | async_gen_traverse(PyAsyncGenObject *gen, visitproc visit, void *arg) | ||||||
| { | { | ||||||
|     Py_VISIT(gen->ag_finalizer); |     Py_VISIT(gen->ag_origin_or_finalizer); | ||||||
|     return gen_traverse((PyGenObject*)gen, visit, arg); |     return gen_traverse((PyGenObject*)gen, visit, arg); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1413,7 +1426,7 @@ async_gen_init_hooks(PyAsyncGenObject *o) | ||||||
|     finalizer = tstate->async_gen_finalizer; |     finalizer = tstate->async_gen_finalizer; | ||||||
|     if (finalizer) { |     if (finalizer) { | ||||||
|         Py_INCREF(finalizer); |         Py_INCREF(finalizer); | ||||||
|         o->ag_finalizer = finalizer; |         o->ag_origin_or_finalizer = finalizer; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     firstiter = tstate->async_gen_firstiter; |     firstiter = tstate->async_gen_firstiter; | ||||||
|  | @ -1508,6 +1521,7 @@ static PyMethodDef async_gen_methods[] = { | ||||||
|     {"asend", (PyCFunction)async_gen_asend, METH_O, async_asend_doc}, |     {"asend", (PyCFunction)async_gen_asend, METH_O, async_asend_doc}, | ||||||
|     {"athrow",(PyCFunction)async_gen_athrow, METH_VARARGS, async_athrow_doc}, |     {"athrow",(PyCFunction)async_gen_athrow, METH_VARARGS, async_athrow_doc}, | ||||||
|     {"aclose", (PyCFunction)async_gen_aclose, METH_NOARGS, async_aclose_doc}, |     {"aclose", (PyCFunction)async_gen_aclose, METH_NOARGS, async_aclose_doc}, | ||||||
|  |     {"__sizeof__", (PyCFunction)gen_sizeof, METH_NOARGS, sizeof__doc__}, | ||||||
|     {"__class_getitem__",    Py_GenericAlias, |     {"__class_getitem__",    Py_GenericAlias, | ||||||
|     METH_O|METH_CLASS,       PyDoc_STR("See PEP 585")}, |     METH_O|METH_CLASS,       PyDoc_STR("See PEP 585")}, | ||||||
|     {NULL, NULL}        /* Sentinel */ |     {NULL, NULL}        /* Sentinel */ | ||||||
|  | @ -1525,8 +1539,9 @@ static PyAsyncMethods async_gen_as_async = { | ||||||
| PyTypeObject PyAsyncGen_Type = { | PyTypeObject PyAsyncGen_Type = { | ||||||
|     PyVarObject_HEAD_INIT(&PyType_Type, 0) |     PyVarObject_HEAD_INIT(&PyType_Type, 0) | ||||||
|     "async_generator",                          /* tp_name */ |     "async_generator",                          /* tp_name */ | ||||||
|     sizeof(PyAsyncGenObject),                   /* tp_basicsize */ |     offsetof(PyAsyncGenObject, ag_iframe) + | ||||||
|     0,                                          /* tp_itemsize */ |     offsetof(InterpreterFrame, localsplus),       /* tp_basicsize */ | ||||||
|  |     sizeof(PyObject *),                         /* tp_itemsize */ | ||||||
|     /* methods */ |     /* methods */ | ||||||
|     (destructor)gen_dealloc,                    /* tp_dealloc */ |     (destructor)gen_dealloc,                    /* tp_dealloc */ | ||||||
|     0,                                          /* tp_vectorcall_offset */ |     0,                                          /* tp_vectorcall_offset */ | ||||||
|  | @ -1594,7 +1609,7 @@ PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname) | ||||||
|     if (o == NULL) { |     if (o == NULL) { | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|     o->ag_finalizer = NULL; |     o->ag_origin_or_finalizer = NULL; | ||||||
|     o->ag_closed = 0; |     o->ag_closed = 0; | ||||||
|     o->ag_hooks_inited = 0; |     o->ag_hooks_inited = 0; | ||||||
|     o->ag_running_async = 0; |     o->ag_running_async = 0; | ||||||
|  | @ -2011,7 +2026,7 @@ static PyObject * | ||||||
| async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg) | async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg) | ||||||
| { | { | ||||||
|     PyGenObject *gen = (PyGenObject*)o->agt_gen; |     PyGenObject *gen = (PyGenObject*)o->agt_gen; | ||||||
|     InterpreterFrame *frame = gen->gi_xframe; |     InterpreterFrame *frame = (InterpreterFrame *)gen->gi_iframe; | ||||||
|     PyObject *retval; |     PyObject *retval; | ||||||
| 
 | 
 | ||||||
|     if (o->agt_state == AWAITABLE_STATE_CLOSED) { |     if (o->agt_state == AWAITABLE_STATE_CLOSED) { | ||||||
|  | @ -2021,7 +2036,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg) | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (frame == NULL || _PyFrameHasCompleted(frame)) { |     if (gen->gi_frame_valid == 0 || _PyFrameHasCompleted(frame)) { | ||||||
|         o->agt_state = AWAITABLE_STATE_CLOSED; |         o->agt_state = AWAITABLE_STATE_CLOSED; | ||||||
|         PyErr_SetNone(PyExc_StopIteration); |         PyErr_SetNone(PyExc_StopIteration); | ||||||
|         return NULL; |         return NULL; | ||||||
|  |  | ||||||
|  | @ -5854,8 +5854,8 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func, | ||||||
|     return -1; |     return -1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static InterpreterFrame * | static int | ||||||
| make_coro_frame(PyThreadState *tstate, | initialize_coro_frame(InterpreterFrame *frame, PyThreadState *tstate, | ||||||
|            PyFunctionObject *func, PyObject *locals, |            PyFunctionObject *func, PyObject *locals, | ||||||
|            PyObject *const *args, Py_ssize_t argcount, |            PyObject *const *args, Py_ssize_t argcount, | ||||||
|            PyObject *kwnames) |            PyObject *kwnames) | ||||||
|  | @ -5863,37 +5863,15 @@ make_coro_frame(PyThreadState *tstate, | ||||||
|     assert(is_tstate_valid(tstate)); |     assert(is_tstate_valid(tstate)); | ||||||
|     assert(func->func_defaults == NULL || PyTuple_CheckExact(func->func_defaults)); |     assert(func->func_defaults == NULL || PyTuple_CheckExact(func->func_defaults)); | ||||||
|     PyCodeObject *code = (PyCodeObject *)func->func_code; |     PyCodeObject *code = (PyCodeObject *)func->func_code; | ||||||
|     int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE; |  | ||||||
|     InterpreterFrame *frame = (InterpreterFrame *)PyMem_Malloc(sizeof(PyObject *)*size); |  | ||||||
|     if (frame == NULL) { |  | ||||||
|         goto fail_no_memory; |  | ||||||
|     } |  | ||||||
|     _PyFrame_InitializeSpecials(frame, func, locals, code->co_nlocalsplus); |     _PyFrame_InitializeSpecials(frame, func, locals, code->co_nlocalsplus); | ||||||
|     for (int i = 0; i < code->co_nlocalsplus; i++) { |     for (int i = 0; i < code->co_nlocalsplus; i++) { | ||||||
|         frame->localsplus[i] = NULL; |         frame->localsplus[i] = NULL; | ||||||
|     } |     } | ||||||
|     assert(frame->frame_obj == NULL); |     assert(frame->frame_obj == NULL); | ||||||
|     if (initialize_locals(tstate, func, frame->localsplus, args, argcount, kwnames)) { |     return initialize_locals(tstate, func, frame->localsplus, args, argcount, kwnames); | ||||||
|         _PyFrame_Clear(frame); |  | ||||||
|         PyMem_Free(frame); |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|     return frame; |  | ||||||
| fail_no_memory: |  | ||||||
|     /* Consume the references */ |  | ||||||
|     for (Py_ssize_t i = 0; i < argcount; i++) { |  | ||||||
|         Py_DECREF(args[i]); |  | ||||||
|     } |  | ||||||
|     if (kwnames) { |  | ||||||
|         Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames); |  | ||||||
|         for (Py_ssize_t i = 0; i < kwcount; i++) { |  | ||||||
|             Py_DECREF(args[i+argcount]); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     PyErr_NoMemory(); |  | ||||||
|     return NULL; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /* Consumes all the references to the args */ | /* Consumes all the references to the args */ | ||||||
| static PyObject * | static PyObject * | ||||||
| make_coro(PyThreadState *tstate, PyFunctionObject *func, | make_coro(PyThreadState *tstate, PyFunctionObject *func, | ||||||
|  | @ -5902,14 +5880,17 @@ make_coro(PyThreadState *tstate, PyFunctionObject *func, | ||||||
|           PyObject *kwnames) |           PyObject *kwnames) | ||||||
| { | { | ||||||
|     assert (((PyCodeObject *)func->func_code)->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)); |     assert (((PyCodeObject *)func->func_code)->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)); | ||||||
|     InterpreterFrame *frame = make_coro_frame(tstate, func, locals, args, argcount, kwnames); |     PyObject *gen = _Py_MakeCoro(func); | ||||||
|     if (frame == NULL) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|     PyObject *gen = _Py_MakeCoro(func, frame); |  | ||||||
|     if (gen == NULL) { |     if (gen == NULL) { | ||||||
|         return NULL; |         return NULL; | ||||||
|     } |     } | ||||||
|  |     InterpreterFrame *frame = (InterpreterFrame *)((PyGenObject *)gen)->gi_iframe; | ||||||
|  |     if (initialize_coro_frame(frame, tstate, func, locals, args, argcount, kwnames)) { | ||||||
|  |         Py_DECREF(gen); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |     frame->generator = gen; | ||||||
|  |     ((PyGenObject *)gen)->gi_frame_valid = 1; | ||||||
|     return gen; |     return gen; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -43,18 +43,12 @@ _PyFrame_MakeAndSetFrameObject(InterpreterFrame *frame) | ||||||
|     return f; |     return f; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| InterpreterFrame * | void | ||||||
| _PyFrame_Copy(InterpreterFrame *frame) | _PyFrame_Copy(InterpreterFrame *src, InterpreterFrame *dest) | ||||||
| { | { | ||||||
|     assert(frame->stacktop >= frame->f_code->co_nlocalsplus); |     assert(src->stacktop >= src->f_code->co_nlocalsplus); | ||||||
|     Py_ssize_t size = ((char*)&frame->localsplus[frame->stacktop]) - (char *)frame; |     Py_ssize_t size = ((char*)&src->localsplus[src->stacktop]) - (char *)src; | ||||||
|     InterpreterFrame *copy = PyMem_Malloc(size); |     memcpy(dest, src, size); | ||||||
|     if (copy == NULL) { |  | ||||||
|         PyErr_NoMemory(); |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
|     memcpy(copy, frame, size); |  | ||||||
|     return copy; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static inline void | static inline void | ||||||
|  | @ -112,7 +106,7 @@ _PyFrame_Clear(InterpreterFrame * frame) | ||||||
|         } |         } | ||||||
|         Py_DECREF(f); |         Py_DECREF(f); | ||||||
|     } |     } | ||||||
|     assert(_PyFrame_GetStackPointer(frame) >= _PyFrame_Stackbase(frame)); |     assert(frame->stacktop >= 0); | ||||||
|     for (int i = 0; i < frame->stacktop; i++) { |     for (int i = 0; i < frame->stacktop; i++) { | ||||||
|         Py_XDECREF(frame->localsplus[i]); |         Py_XDECREF(frame->localsplus[i]); | ||||||
|     } |     } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Mark Shannon
						Mark Shannon