static const char *ASYNC_GEN_IGNORED_EXIT_MSG =
"async generator ignored GeneratorExit";
+/* Returns a borrowed reference */
+static inline PyCodeObject *
+_PyGen_GetCode(PyGenObject *gen) {
+ _PyInterpreterFrame *frame = (_PyInterpreterFrame *)(gen->gi_iframe);
+ return frame->f_code;
+}
+
+PyCodeObject *
+PyGen_GetCode(PyGenObject *gen) {
+ assert(PyGen_Check(gen));
+ PyCodeObject *res = _PyGen_GetCode(gen);
+ Py_INCREF(res);
+ return res;
+}
+
static inline int
exc_state_traverse(_PyErr_StackItem *exc_state, visitproc visit, void *arg)
{
static int
gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
{
- Py_VISIT(gen->gi_code);
Py_VISIT(gen->gi_name);
Py_VISIT(gen->gi_qualname);
if (gen->gi_frame_state < FRAME_CLEARED) {
/* If `gen` is a coroutine, and if it was never awaited on,
issue a RuntimeWarning. */
- if (gen->gi_code != NULL &&
- ((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE &&
+ assert(_PyGen_GetCode(gen) != NULL);
+ if (_PyGen_GetCode(gen)->co_flags & CO_COROUTINE &&
gen->gi_frame_state == FRAME_CREATED)
{
_PyErr_WarnUnawaitedCoroutine((PyObject *)gen);
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;
gen->gi_frame_state = FRAME_CLEARED;
frame->previous = NULL;
- _PyFrame_Clear(frame);
+ _PyFrame_ClearExceptCode(frame);
}
- if (((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE) {
+ if (_PyGen_GetCode(gen)->co_flags & CO_COROUTINE) {
Py_CLEAR(((PyCoroObject *)gen)->cr_origin_or_finalizer);
}
- Py_CLEAR(gen->gi_code);
+ Py_DECREF(_PyGen_GetCode(gen));
Py_CLEAR(gen->gi_name);
Py_CLEAR(gen->gi_qualname);
_PyErr_ClearExcState(&gen->gi_exc_state);
/* Return immediately if the frame didn't start yet. SEND
always come after LOAD_CONST: a code object should not start
with SEND */
- assert(_PyCode_CODE(gen->gi_code)[0].op.code != SEND);
+ assert(_PyCode_CODE(_PyGen_GetCode(gen))[0].op.code != SEND);
return NULL;
}
_Py_CODEUNIT next = frame->prev_instr[1];
return _gen_getframe(gen, "gi_frame");
}
+static PyObject *
+_gen_getcode(PyGenObject *gen, const char *const name)
+{
+ if (PySys_Audit("object.__getattr__", "Os", gen, name) < 0) {
+ return NULL;
+ }
+ return Py_NewRef(_PyGen_GetCode(gen));
+}
+
+static PyObject *
+gen_getcode(PyGenObject *gen, void *Py_UNUSED(ignored))
+{
+ return _gen_getcode(gen, "gi_code");
+}
+
static PyGetSetDef gen_getsetlist[] = {
{"__name__", (getter)gen_get_name, (setter)gen_set_name,
PyDoc_STR("name of the generator")},
{"gi_running", (getter)gen_getrunning, NULL, NULL},
{"gi_frame", (getter)gen_getframe, NULL, NULL},
{"gi_suspended", (getter)gen_getsuspended, NULL, NULL},
+ {"gi_code", (getter)gen_getcode, NULL, NULL},
{NULL} /* Sentinel */
};
static PyMemberDef gen_memberlist[] = {
- {"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY|PY_AUDIT_READ},
{NULL} /* Sentinel */
};
{
Py_ssize_t res;
res = offsetof(PyGenObject, gi_iframe) + offsetof(_PyInterpreterFrame, localsplus);
- PyCodeObject *code = gen->gi_code;
+ PyCodeObject *code = _PyGen_GetCode(gen);
res += _PyFrame_NumSlotsForCodeObject(code) * sizeof(PyObject *);
return PyLong_FromSsize_t(res);
}
return NULL;
}
gen->gi_frame_state = FRAME_CLEARED;
- gen->gi_code = (PyCodeObject *)Py_NewRef(func->func_code);
gen->gi_weakreflist = NULL;
gen->gi_exc_state.exc_value = NULL;
gen->gi_exc_state.previous_item = NULL;
f->f_frame = frame;
frame->owner = FRAME_OWNED_BY_GENERATOR;
assert(PyObject_GC_IsTracked((PyObject *)f));
- gen->gi_code = PyFrame_GetCode(f);
- Py_INCREF(gen->gi_code);
Py_DECREF(f);
gen->gi_weakreflist = NULL;
gen->gi_exc_state.exc_value = NULL;
if (name != NULL)
gen->gi_name = Py_NewRef(name);
else
- gen->gi_name = Py_NewRef(gen->gi_code->co_name);
+ gen->gi_name = Py_NewRef(_PyGen_GetCode(gen)->co_name);
if (qualname != NULL)
gen->gi_qualname = Py_NewRef(qualname);
else
- gen->gi_qualname = Py_NewRef(gen->gi_code->co_qualname);
+ gen->gi_qualname = Py_NewRef(_PyGen_GetCode(gen)->co_qualname);
_PyObject_GC_TRACK(gen);
return (PyObject *)gen;
}
gen_is_coroutine(PyObject *o)
{
if (PyGen_CheckExact(o)) {
- PyCodeObject *code = (PyCodeObject *)((PyGenObject*)o)->gi_code;
+ PyCodeObject *code = _PyGen_GetCode((PyGenObject*)o);
if (code->co_flags & CO_ITERABLE_COROUTINE) {
return 1;
}
return _gen_getframe((PyGenObject *)coro, "cr_frame");
}
+static PyObject *
+cr_getcode(PyCoroObject *coro, void *Py_UNUSED(ignored))
+{
+ return _gen_getcode((PyGenObject *)coro, "cr_code");
+}
+
static PyGetSetDef coro_getsetlist[] = {
{"__name__", (getter)gen_get_name, (setter)gen_set_name,
PyDoc_STR("object being awaited on, or None")},
{"cr_running", (getter)cr_getrunning, NULL, NULL},
{"cr_frame", (getter)cr_getframe, NULL, NULL},
+ {"cr_code", (getter)cr_getcode, NULL, NULL},
{"cr_suspended", (getter)cr_getsuspended, NULL, NULL},
{NULL} /* Sentinel */
};
static PyMemberDef coro_memberlist[] = {
- {"cr_code", T_OBJECT, offsetof(PyCoroObject, cr_code), READONLY|PY_AUDIT_READ},
{"cr_origin", T_OBJECT, offsetof(PyCoroObject, cr_origin_or_finalizer), READONLY},
{NULL} /* Sentinel */
};
return _gen_getframe((PyGenObject *)ag, "ag_frame");
}
+static PyObject *
+ag_getcode(PyGenObject *gen, void *Py_UNUSED(ignored))
+{
+ return _gen_getcode(gen, "ag__code");
+}
+
static PyGetSetDef async_gen_getsetlist[] = {
{"__name__", (getter)gen_get_name, (setter)gen_set_name,
PyDoc_STR("name of the async generator")},
{"ag_await", (getter)coro_get_cr_await, NULL,
PyDoc_STR("object being awaited on, or None")},
{"ag_frame", (getter)ag_getframe, NULL, NULL},
+ {"ag_code", (getter)ag_getcode, NULL, NULL},
{NULL} /* Sentinel */
};
static PyMemberDef async_gen_memberlist[] = {
{"ag_running", T_BOOL, offsetof(PyAsyncGenObject, ag_running_async),
READONLY},
- {"ag_code", T_OBJECT, offsetof(PyAsyncGenObject, ag_code), READONLY|PY_AUDIT_READ},
{NULL} /* Sentinel */
};
return -1;
}
-/* Consumes references to func, locals and all the args */
-static _PyInterpreterFrame *
-_PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
- PyObject *locals, PyObject* const* args,
- size_t argcount, PyObject *kwnames)
-{
- PyCodeObject * code = (PyCodeObject *)func->func_code;
- CALL_STAT_INC(frames_pushed);
- _PyInterpreterFrame *frame = _PyThreadState_PushFrame(tstate, code->co_framesize);
- if (frame == NULL) {
- goto fail;
- }
- _PyFrame_Initialize(frame, func, locals, code, 0);
- PyObject **localsarray = &frame->localsplus[0];
- if (initialize_locals(tstate, func, localsarray, args, argcount, kwnames)) {
- assert(frame->owner != FRAME_OWNED_BY_GENERATOR);
- _PyEvalFrameClearAndPop(tstate, frame);
- return NULL;
- }
- return frame;
-fail:
- /* Consume the references */
- for (size_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;
-}
-
static void
clear_thread_frame(PyThreadState *tstate, _PyInterpreterFrame * frame)
{
tstate->datastack_top);
tstate->c_recursion_remaining--;
assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame);
- _PyFrame_Clear(frame);
+ _PyFrame_ClearExceptCode(frame);
+ Py_DECREF(frame->f_code);
tstate->c_recursion_remaining++;
_PyThreadState_PopFrame(tstate, frame);
}
gen->gi_exc_state.previous_item = NULL;
tstate->c_recursion_remaining--;
assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame);
- _PyFrame_Clear(frame);
+ _PyFrame_ClearExceptCode(frame);
tstate->c_recursion_remaining++;
frame->previous = NULL;
}
}
}
+/* Consumes references to func, locals and all the args */
+static _PyInterpreterFrame *
+_PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
+ PyObject *locals, PyObject* const* args,
+ size_t argcount, PyObject *kwnames)
+{
+ PyCodeObject * code = (PyCodeObject *)func->func_code;
+ CALL_STAT_INC(frames_pushed);
+ _PyInterpreterFrame *frame = _PyThreadState_PushFrame(tstate, code->co_framesize);
+ if (frame == NULL) {
+ goto fail;
+ }
+ _PyFrame_Initialize(frame, func, locals, code, 0);
+ if (initialize_locals(tstate, func, frame->localsplus, args, argcount, kwnames)) {
+ assert(frame->owner == FRAME_OWNED_BY_THREAD);
+ clear_thread_frame(tstate, frame);
+ return NULL;
+ }
+ return frame;
+fail:
+ /* Consume the references */
+ for (size_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;
+}
PyObject *
_PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func,