mirror of https://github.com/python/cpython
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
|
@ -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 @@ class SizeofTest(unittest.TestCase):
|
||||||
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 @@ fail_post_args:
|
||||||
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…
Reference in New Issue