bpo-45256: Rationalize code around Python-to-Python calls a bit. (GH-29235)

This commit is contained in:
Mark Shannon 2021-10-28 16:14:59 +01:00 committed by GitHub
parent 0a1a36b74b
commit 7f61d9d848
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 121 additions and 70 deletions

View file

@ -152,6 +152,21 @@ _PyFrame_LocalsToFast(InterpreterFrame *frame, int clear);
InterpreterFrame *_PyThreadState_PushFrame( InterpreterFrame *_PyThreadState_PushFrame(
PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals); PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals);
extern InterpreterFrame *
_PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size);
static inline InterpreterFrame *
_PyThreadState_BumpFramePointer(PyThreadState *tstate, size_t size)
{
PyObject **base = tstate->datastack_top;
PyObject **top = base + size;
if (top < tstate->datastack_limit) {
tstate->datastack_top = top;
return (InterpreterFrame *)base;
}
return _PyThreadState_BumpFramePointerSlow(tstate, size);
}
void _PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame *frame); void _PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame *frame);
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -786,16 +786,15 @@ allocate_heap_frame(PyFrameConstructor *con, PyObject *locals)
{ {
PyCodeObject *code = (PyCodeObject *)con->fc_code; PyCodeObject *code = (PyCodeObject *)con->fc_code;
int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE; int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE;
PyObject **localsarray = PyMem_Malloc(sizeof(PyObject *)*size); InterpreterFrame *frame = (InterpreterFrame *)PyMem_Malloc(sizeof(PyObject *)*size);
if (localsarray == NULL) { if (frame == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
return NULL; return NULL;
} }
for (Py_ssize_t i=0; i < code->co_nlocalsplus; i++) {
localsarray[i] = NULL;
}
InterpreterFrame *frame = (InterpreterFrame *)(localsarray + code->co_nlocalsplus);
_PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus); _PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus);
for (Py_ssize_t i = 0; i < code->co_nlocalsplus; i++) {
frame->localsplus[i] = NULL;
}
return frame; return frame;
} }

View file

@ -101,7 +101,7 @@ static int get_exception_handler(PyCodeObject *, int, int*, int*, int*);
static InterpreterFrame * static InterpreterFrame *
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con, _PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con,
PyObject *locals, PyObject* const* args, PyObject *locals, PyObject* const* args,
size_t argcount, PyObject *kwnames, int steal_args); size_t argcount, PyObject *kwnames);
static int static int
_PyEvalFrameClearAndPop(PyThreadState *tstate, InterpreterFrame * frame); _PyEvalFrameClearAndPop(PyThreadState *tstate, InterpreterFrame * frame);
@ -4633,7 +4633,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
InterpreterFrame *new_frame = _PyEvalFramePushAndInit( InterpreterFrame *new_frame = _PyEvalFramePushAndInit(
tstate, PyFunction_AS_FRAME_CONSTRUCTOR(function), locals, tstate, PyFunction_AS_FRAME_CONSTRUCTOR(function), locals,
stack_pointer, stack_pointer,
nargs, kwnames, 1); nargs, kwnames);
STACK_SHRINK(postcall_shrink); STACK_SHRINK(postcall_shrink);
// The frame has stolen all the arguments from the stack, // The frame has stolen all the arguments from the stack,
// so there is no need to clean them up. // so there is no need to clean them up.
@ -4708,11 +4708,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
/* PEP 523 */ /* PEP 523 */
DEOPT_IF(tstate->interp->eval_frame != NULL, CALL_FUNCTION); DEOPT_IF(tstate->interp->eval_frame != NULL, CALL_FUNCTION);
STAT_INC(CALL_FUNCTION, hit); STAT_INC(CALL_FUNCTION, hit);
InterpreterFrame *new_frame = _PyThreadState_PushFrame( PyCodeObject *code = (PyCodeObject *)func->func_code;
tstate, PyFunction_AS_FRAME_CONSTRUCTOR(func), NULL); size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
InterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size);
if (new_frame == NULL) { if (new_frame == NULL) {
goto error; goto error;
} }
_PyFrame_InitializeSpecials(new_frame, PyFunction_AS_FRAME_CONSTRUCTOR(func),
NULL, code->co_nlocalsplus);
STACK_SHRINK(argcount); STACK_SHRINK(argcount);
for (int i = 0; i < argcount; i++) { for (int i = 0; i < argcount; i++) {
new_frame->localsplus[i] = stack_pointer[i]; new_frame->localsplus[i] = stack_pointer[i];
@ -4723,6 +4726,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
Py_INCREF(def); Py_INCREF(def);
new_frame->localsplus[argcount+i] = def; new_frame->localsplus[argcount+i] = def;
} }
for (int i = argcount+deflen; i < code->co_nlocalsplus; i++) {
new_frame->localsplus[i] = NULL;
}
STACK_SHRINK(1); STACK_SHRINK(1);
Py_DECREF(func); Py_DECREF(func);
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
@ -5595,7 +5601,7 @@ get_exception_handler(PyCodeObject *code, int index, int *level, int *handler, i
static int static int
initialize_locals(PyThreadState *tstate, PyFrameConstructor *con, initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
PyObject **localsplus, PyObject *const *args, PyObject **localsplus, PyObject *const *args,
Py_ssize_t argcount, PyObject *kwnames, int steal_args) Py_ssize_t argcount, PyObject *kwnames)
{ {
PyCodeObject *co = (PyCodeObject*)con->fc_code; PyCodeObject *co = (PyCodeObject*)con->fc_code;
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount; const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
@ -5629,9 +5635,6 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
} }
for (j = 0; j < n; j++) { for (j = 0; j < n; j++) {
PyObject *x = args[j]; PyObject *x = args[j];
if (!steal_args) {
Py_INCREF(x);
}
assert(localsplus[j] == NULL); assert(localsplus[j] == NULL);
localsplus[j] = x; localsplus[j] = x;
} }
@ -5639,11 +5642,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
/* Pack other positional arguments into the *args argument */ /* Pack other positional arguments into the *args argument */
if (co->co_flags & CO_VARARGS) { if (co->co_flags & CO_VARARGS) {
PyObject *u = NULL; PyObject *u = NULL;
if (steal_args) { u = _PyTuple_FromArraySteal(args + n, argcount - n);
u = _PyTuple_FromArraySteal(args + n, argcount - n);
} else {
u = _PyTuple_FromArray(args + n, argcount - n);
}
if (u == NULL) { if (u == NULL) {
goto fail_post_positional; goto fail_post_positional;
} }
@ -5652,10 +5651,8 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
} }
else if (argcount > n) { else if (argcount > n) {
/* Too many postional args. Error is reported later */ /* Too many postional args. Error is reported later */
if (steal_args) { for (j = n; j < argcount; j++) {
for (j = n; j < argcount; j++) { Py_DECREF(args[j]);
Py_DECREF(args[j]);
}
} }
} }
@ -5717,19 +5714,15 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
if (PyDict_SetItem(kwdict, keyword, value) == -1) { if (PyDict_SetItem(kwdict, keyword, value) == -1) {
goto kw_fail; goto kw_fail;
} }
if (steal_args) { Py_DECREF(value);
Py_DECREF(value);
}
continue; continue;
kw_fail: kw_fail:
if (steal_args) { for (;i < kwcount; i++) {
for (;i < kwcount; i++) { PyObject *value = args[i+argcount];
PyObject *value = args[i+argcount]; Py_DECREF(value);
Py_DECREF(value);
}
} }
goto fail_noclean; goto fail_post_args;
kw_found: kw_found:
if (localsplus[j] != NULL) { if (localsplus[j] != NULL) {
@ -5738,9 +5731,6 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
con->fc_qualname, keyword); con->fc_qualname, keyword);
goto kw_fail; goto kw_fail;
} }
if (!steal_args) {
Py_INCREF(value);
}
localsplus[j] = value; localsplus[j] = value;
} }
} }
@ -5749,7 +5739,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) { if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) {
too_many_positional(tstate, co, argcount, con->fc_defaults, localsplus, too_many_positional(tstate, co, argcount, con->fc_defaults, localsplus,
con->fc_qualname); con->fc_qualname);
goto fail_noclean; goto fail_post_args;
} }
/* Add missing positional arguments (copy default values from defs) */ /* Add missing positional arguments (copy default values from defs) */
@ -5765,7 +5755,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
if (missing) { if (missing) {
missing_arguments(tstate, co, missing, defcount, localsplus, missing_arguments(tstate, co, missing, defcount, localsplus,
con->fc_qualname); con->fc_qualname);
goto fail_noclean; goto fail_post_args;
} }
if (n > m) if (n > m)
i = n - m; i = n - m;
@ -5798,7 +5788,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
continue; continue;
} }
else if (_PyErr_Occurred(tstate)) { else if (_PyErr_Occurred(tstate)) {
goto fail_noclean; goto fail_post_args;
} }
} }
missing++; missing++;
@ -5806,35 +5796,31 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
if (missing) { if (missing) {
missing_arguments(tstate, co, missing, -1, localsplus, missing_arguments(tstate, co, missing, -1, localsplus,
con->fc_qualname); con->fc_qualname);
goto fail_noclean; goto fail_post_args;
} }
} }
/* Copy closure variables to free variables */ /* Copy closure variables to free variables */
for (i = 0; i < co->co_nfreevars; ++i) { for (i = 0; i < co->co_nfreevars; ++i) {
PyObject *o = PyTuple_GET_ITEM(con->fc_closure, i); PyObject *o = PyTuple_GET_ITEM(con->fc_closure, i);
Py_INCREF(o); Py_INCREF(o);
localsplus[co->co_nlocals + co->co_nplaincellvars + i] = o; localsplus[co->co_nlocals + co->co_nplaincellvars + i] = o;
} }
return 0; return 0;
fail_pre_positional: fail_pre_positional:
if (steal_args) { for (j = 0; j < argcount; j++) {
for (j = 0; j < argcount; j++) { Py_DECREF(args[j]);
Py_DECREF(args[j]);
}
} }
/* fall through */ /* fall through */
fail_post_positional: fail_post_positional:
if (steal_args) { if (kwnames) {
Py_ssize_t kwcount = kwnames != NULL ? PyTuple_GET_SIZE(kwnames) : 0; Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames);
for (j = argcount; j < argcount+kwcount; j++) { for (j = argcount; j < argcount+kwcount; j++) {
Py_DECREF(args[j]); Py_DECREF(args[j]);
} }
} }
/* fall through */ /* fall through */
fail_noclean: fail_post_args:
return -1; return -1;
} }
@ -5850,21 +5836,34 @@ make_coro_frame(PyThreadState *tstate,
int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE; int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE;
InterpreterFrame *frame = (InterpreterFrame *)PyMem_Malloc(sizeof(PyObject *)*size); InterpreterFrame *frame = (InterpreterFrame *)PyMem_Malloc(sizeof(PyObject *)*size);
if (frame == NULL) { if (frame == NULL) {
PyErr_NoMemory(); goto fail_no_memory;
return NULL;
}
for (Py_ssize_t i=0; i < code->co_nlocalsplus; i++) {
frame->localsplus[i] = NULL;
} }
_PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus); _PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus);
for (int i = 0; i < code->co_nlocalsplus; i++) {
frame->localsplus[i] = NULL;
}
assert(frame->frame_obj == NULL); assert(frame->frame_obj == NULL);
if (initialize_locals(tstate, con, frame->localsplus, args, argcount, kwnames, 0)) { if (initialize_locals(tstate, con, frame->localsplus, args, argcount, kwnames)) {
_PyFrame_Clear(frame, 1); _PyFrame_Clear(frame, 1);
return NULL; return NULL;
} }
return frame; 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 */
static PyObject * static PyObject *
make_coro(PyThreadState *tstate, PyFrameConstructor *con, make_coro(PyThreadState *tstate, PyFrameConstructor *con,
PyObject *locals, PyObject *locals,
@ -5880,28 +5879,44 @@ make_coro(PyThreadState *tstate, PyFrameConstructor *con,
if (gen == NULL) { if (gen == NULL) {
return NULL; return NULL;
} }
return gen; return gen;
} }
// If *steal_args* is set, the function will steal the references to all the arguments. /* Consumes all the references to the args */
// In case of error, the function returns null and if *steal_args* is set, the caller
// will still own all the arguments.
static InterpreterFrame * static InterpreterFrame *
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con, _PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con,
PyObject *locals, PyObject* const* args, PyObject *locals, PyObject* const* args,
size_t argcount, PyObject *kwnames, int steal_args) size_t argcount, PyObject *kwnames)
{ {
InterpreterFrame * frame = _PyThreadState_PushFrame(tstate, con, locals); PyCodeObject * code = (PyCodeObject *)con->fc_code;
size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
InterpreterFrame *frame = _PyThreadState_BumpFramePointer(tstate, size);
if (frame == NULL) { if (frame == NULL) {
return NULL; goto fail;
} }
PyObject **localsarray = _PyFrame_GetLocalsArray(frame); _PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus);
if (initialize_locals(tstate, con, localsarray, args, argcount, kwnames, steal_args)) { PyObject **localsarray = &frame->localsplus[0];
for (int i = 0; i < code->co_nlocalsplus; i++) {
localsarray[i] = NULL;
}
if (initialize_locals(tstate, con, localsarray, args, argcount, kwnames)) {
_PyFrame_Clear(frame, 0); _PyFrame_Clear(frame, 0);
return NULL; return NULL;
} }
return frame; 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 int static int
@ -5925,13 +5940,25 @@ _PyEval_Vector(PyThreadState *tstate, PyFrameConstructor *con,
PyObject *kwnames) PyObject *kwnames)
{ {
PyCodeObject *code = (PyCodeObject *)con->fc_code; PyCodeObject *code = (PyCodeObject *)con->fc_code;
/* _PyEvalFramePushAndInit and make_coro consume
* all the references to their arguments
*/
for (size_t i = 0; i < argcount; i++) {
Py_INCREF(args[i]);
}
if (kwnames) {
Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames);
for (Py_ssize_t i = 0; i < kwcount; i++) {
Py_INCREF(args[i+argcount]);
}
}
int is_coro = code->co_flags & int is_coro = code->co_flags &
(CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR); (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR);
if (is_coro) { if (is_coro) {
return make_coro(tstate, con, locals, args, argcount, kwnames); return make_coro(tstate, con, locals, args, argcount, kwnames);
} }
InterpreterFrame *frame = _PyEvalFramePushAndInit( InterpreterFrame *frame = _PyEvalFramePushAndInit(
tstate, con, locals, args, argcount, kwnames, 0); tstate, con, locals, args, argcount, kwnames);
if (frame == NULL) { if (frame == NULL) {
return NULL; return NULL;
} }

View file

@ -2065,12 +2065,8 @@ push_chunk(PyThreadState *tstate, int size)
} }
InterpreterFrame * InterpreterFrame *
_PyThreadState_PushFrame(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals) _PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size)
{ {
PyCodeObject *code = (PyCodeObject *)con->fc_code;
int nlocalsplus = code->co_nlocalsplus;
size_t size = nlocalsplus + code->co_stacksize +
FRAME_SPECIALS_SIZE;
assert(size < INT_MAX/sizeof(PyObject *)); assert(size < INT_MAX/sizeof(PyObject *));
PyObject **base = tstate->datastack_top; PyObject **base = tstate->datastack_top;
PyObject **top = base + size; PyObject **top = base + size;
@ -2083,7 +2079,21 @@ _PyThreadState_PushFrame(PyThreadState *tstate, PyFrameConstructor *con, PyObjec
else { else {
tstate->datastack_top = top; tstate->datastack_top = top;
} }
InterpreterFrame *frame = (InterpreterFrame *)base; return (InterpreterFrame *)base;
}
InterpreterFrame *
_PyThreadState_PushFrame(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals)
{
PyCodeObject *code = (PyCodeObject *)con->fc_code;
int nlocalsplus = code->co_nlocalsplus;
size_t size = nlocalsplus + code->co_stacksize +
FRAME_SPECIALS_SIZE;
InterpreterFrame *frame = _PyThreadState_BumpFramePointer(tstate, size);
if (frame == NULL) {
return NULL;
}
_PyFrame_InitializeSpecials(frame, con, locals, nlocalsplus); _PyFrame_InitializeSpecials(frame, con, locals, nlocalsplus);
for (int i=0; i < nlocalsplus; i++) { for (int i=0; i < nlocalsplus; i++) {
frame->localsplus[i] = NULL; frame->localsplus[i] = NULL;