Skip to content

Commit 0332e56

Browse files
authored
bpo-42990: Further refactoring of PyEval_ functions. (GH-24368)
* Further refactoring of PyEval_EvalCode and friends. Break into make-frame, and eval-frame parts. * Simplify function vector call using new _PyEval_Vector. * Remove unused internal functions: _PyEval_EvalCodeWithName and _PyEval_EvalCode. * Don't use legacy function PyEval_EvalCodeEx.
1 parent 49926cf commit 0332e56

File tree

9 files changed

+247
-245
lines changed

9 files changed

+247
-245
lines changed

Include/cpython/frameobject.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *,
7171
PyObject *, PyObject *);
7272

7373
/* only internal use */
74-
PyFrameObject* _PyFrame_New_NoTrack(PyThreadState *, PyCodeObject *,
75-
PyObject *, PyObject *, PyObject *);
74+
PyFrameObject*
75+
_PyFrame_New_NoTrack(PyThreadState *, PyFrameConstructor *, PyObject *);
7676

7777

7878
/* The rest of the interface is specific for frame objects */

Include/eval.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,6 @@ PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyObject *co,
1818
PyObject *kwdefs, PyObject *closure);
1919

2020
#ifndef Py_LIMITED_API
21-
PyAPI_FUNC(PyObject *) _PyEval_EvalCodeWithName(
22-
PyObject *co,
23-
PyObject *globals, PyObject *locals,
24-
PyObject *const *args, Py_ssize_t argcount,
25-
PyObject *const *kwnames, PyObject *const *kwargs,
26-
Py_ssize_t kwcount, int kwstep,
27-
PyObject *const *defs, Py_ssize_t defcount,
28-
PyObject *kwdefs, PyObject *closure,
29-
PyObject *name, PyObject *qualname);
30-
3121
PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args);
3222
#endif
3323

Include/internal/pycore_ceval.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,11 @@ _PyEval_EvalFrame(PyThreadState *tstate, PyFrameObject *f, int throwflag)
4040
return tstate->interp->eval_frame(tstate, f, throwflag);
4141
}
4242

43-
extern PyObject *_PyEval_EvalCode(
44-
PyThreadState *tstate,
45-
PyFrameConstructor *desc, PyObject *locals,
46-
PyObject *const *args, Py_ssize_t argcount,
47-
PyObject *const *kwnames, PyObject *const *kwargs,
48-
Py_ssize_t kwcount, int kwstep);
43+
extern PyObject *
44+
_PyEval_Vector(PyThreadState *tstate,
45+
PyFrameConstructor *desc, PyObject *locals,
46+
PyObject* const* args, size_t argcount,
47+
PyObject *kwnames);
4948

5049
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
5150
extern int _PyEval_ThreadsInitialized(PyInterpreterState *interp);
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Refactor the ``PyEval_`` family of functions.
2+
3+
* An new function ``_PyEval_Vector`` is added to simplify calls to Python from C.
4+
* ``_PyEval_EvalCodeWithName`` is removed
5+
* ``PyEval_EvalCodeEx`` is retained as part of the API, but is not used internally

Objects/call.c

Lines changed: 7 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -328,87 +328,24 @@ PyCFunction_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
328328

329329
/* --- PyFunction call functions ---------------------------------- */
330330

331-
static PyObject* _Py_HOT_FUNCTION
332-
function_code_fastcall(PyThreadState *tstate, PyCodeObject *co,
333-
PyObject *const *args, Py_ssize_t nargs,
334-
PyFunctionObject *func)
335-
{
336-
assert(tstate != NULL);
337-
assert(func != NULL);
338-
339-
/* XXX Perhaps we should create a specialized
340-
_PyFrame_New_NoTrack() that doesn't take locals, but does
341-
take builtins without sanity checking them.
342-
*/
343-
PyFrameObject *f = _PyFrame_New_NoTrack(tstate, co, func->func_globals, func->func_builtins, NULL);
344-
if (f == NULL) {
345-
return NULL;
346-
}
347-
348-
PyObject **fastlocals = f->f_localsplus;
349-
350-
for (Py_ssize_t i = 0; i < nargs; i++) {
351-
Py_INCREF(*args);
352-
fastlocals[i] = *args++;
353-
}
354-
PyObject *result = _PyEval_EvalFrame(tstate, f, 0);
355-
356-
if (Py_REFCNT(f) > 1) {
357-
Py_DECREF(f);
358-
_PyObject_GC_TRACK(f);
359-
}
360-
else {
361-
++tstate->recursion_depth;
362-
Py_DECREF(f);
363-
--tstate->recursion_depth;
364-
}
365-
return result;
366-
}
367-
368-
369331
PyObject *
370332
_PyFunction_Vectorcall(PyObject *func, PyObject* const* stack,
371333
size_t nargsf, PyObject *kwnames)
372334
{
373335
assert(PyFunction_Check(func));
374-
assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
375-
336+
PyFrameConstructor *f = PyFunction_AS_FRAME_CONSTRUCTOR(func);
376337
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
377338
assert(nargs >= 0);
378-
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
379-
assert((nargs == 0 && nkwargs == 0) || stack != NULL);
380-
/* kwnames must only contain strings and all keys must be unique */
381-
382339
PyThreadState *tstate = _PyThreadState_GET();
383-
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
384-
PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
385-
386-
if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
387-
(co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
388-
{
389-
if (argdefs == NULL && co->co_argcount == nargs) {
390-
return function_code_fastcall(tstate, co, stack, nargs, (PyFunctionObject *)func);
391-
}
392-
else if (nargs == 0 && argdefs != NULL
393-
&& co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
394-
/* function called with no arguments, but all parameters have
395-
a default value: use default values as arguments .*/
396-
stack = _PyTuple_ITEMS(argdefs);
397-
return function_code_fastcall(tstate, co,
398-
stack, PyTuple_GET_SIZE(argdefs),
399-
(PyFunctionObject *)func);
400-
}
340+
assert(nargs == 0 || stack != NULL);
341+
if (((PyCodeObject *)f->fc_code)->co_flags & CO_OPTIMIZED) {
342+
return _PyEval_Vector(tstate, f, NULL, stack, nargs, kwnames);
343+
}
344+
else {
345+
return _PyEval_Vector(tstate, f, f->fc_globals, stack, nargs, kwnames);
401346
}
402-
403-
return _PyEval_EvalCode(tstate,
404-
PyFunction_AS_FRAME_CONSTRUCTOR(func), (PyObject *)NULL,
405-
stack, nargs,
406-
nkwargs ? _PyTuple_ITEMS(kwnames) : NULL,
407-
stack + nargs,
408-
nkwargs, 1);
409347
}
410348

411-
412349
/* --- More complex call functions -------------------------------- */
413350

414351
/* External interface to call any callable object.

Objects/frameobject.c

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -816,11 +816,10 @@ frame_alloc(PyCodeObject *code)
816816

817817

818818
PyFrameObject* _Py_HOT_FUNCTION
819-
_PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
820-
PyObject *globals, PyObject *builtins, PyObject *locals)
819+
_PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals)
821820
{
822821
#ifdef Py_DEBUG
823-
if (code == NULL || globals == NULL || builtins == NULL ||
822+
if (con == NULL || con->fc_code == NULL ||
824823
(locals != NULL && !PyMapping_Check(locals))) {
825824
PyErr_BadInternalCall();
826825
return NULL;
@@ -829,38 +828,21 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
829828

830829
PyFrameObject *back = tstate->frame;
831830

832-
PyFrameObject *f = frame_alloc(code);
831+
PyFrameObject *f = frame_alloc((PyCodeObject *)con->fc_code);
833832
if (f == NULL) {
834833
return NULL;
835834
}
836835

837836
f->f_stackdepth = 0;
838-
Py_INCREF(builtins);
839-
f->f_builtins = builtins;
837+
Py_INCREF(con->fc_builtins);
838+
f->f_builtins = con->fc_builtins;
840839
Py_XINCREF(back);
841840
f->f_back = back;
842-
Py_INCREF(code);
843-
Py_INCREF(globals);
844-
f->f_globals = globals;
845-
/* Most functions have CO_NEWLOCALS and CO_OPTIMIZED set. */
846-
if ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) ==
847-
(CO_NEWLOCALS | CO_OPTIMIZED))
848-
; /* f_locals = NULL; will be set by PyFrame_FastToLocals() */
849-
else if (code->co_flags & CO_NEWLOCALS) {
850-
locals = PyDict_New();
851-
if (locals == NULL) {
852-
Py_DECREF(f);
853-
return NULL;
854-
}
855-
f->f_locals = locals;
856-
}
857-
else {
858-
if (locals == NULL) {
859-
locals = globals;
860-
}
861-
Py_INCREF(locals);
862-
f->f_locals = locals;
863-
}
841+
Py_INCREF(con->fc_code);
842+
Py_INCREF(con->fc_globals);
843+
f->f_globals = con->fc_globals;
844+
Py_XINCREF(locals);
845+
f->f_locals = locals;
864846

865847
f->f_lasti = -1;
866848
f->f_lineno = 0;
@@ -875,12 +857,23 @@ _PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code,
875857
return f;
876858
}
877859

860+
/* Legacy API */
878861
PyFrameObject*
879862
PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
880863
PyObject *globals, PyObject *locals)
881864
{
882865
PyObject *builtins = _PyEval_BuiltinsFromGlobals(globals);
883-
PyFrameObject *f = _PyFrame_New_NoTrack(tstate, code, globals, builtins, locals);
866+
PyFrameConstructor desc = {
867+
.fc_globals = globals,
868+
.fc_builtins = builtins,
869+
.fc_name = code->co_name,
870+
.fc_qualname = code->co_name,
871+
.fc_code = (PyObject *)code,
872+
.fc_defaults = NULL,
873+
.fc_kwdefaults = NULL,
874+
.fc_closure = NULL
875+
};
876+
PyFrameObject *f = _PyFrame_New_NoTrack(tstate, &desc, locals);
884877
Py_DECREF(builtins);
885878
if (f)
886879
_PyObject_GC_TRACK(f);

Objects/funcobject.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,9 +575,9 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals,
575575

576576
newfunc = (PyFunctionObject *)PyFunction_New((PyObject *)code,
577577
globals);
578-
if (newfunc == NULL)
578+
if (newfunc == NULL) {
579579
return NULL;
580-
580+
}
581581
if (name != Py_None) {
582582
Py_INCREF(name);
583583
Py_SETREF(newfunc->func_name, name);

Python/bltinmodule.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "pycore_pyerrors.h" // _PyErr_NoMemory()
99
#include "pycore_pystate.h" // _PyThreadState_GET()
1010
#include "pycore_tuple.h" // _PyTuple_FromArray()
11+
#include "pycore_ceval.h" // _PyEval_Vector()
1112

1213
_Py_IDENTIFIER(__builtins__);
1314
_Py_IDENTIFIER(__dict__);
@@ -219,9 +220,9 @@ builtin___build_class__(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
219220
Py_TYPE(ns)->tp_name);
220221
goto error;
221222
}
222-
cell = PyEval_EvalCodeEx(PyFunction_GET_CODE(func), PyFunction_GET_GLOBALS(func), ns,
223-
NULL, 0, NULL, 0, NULL, 0, NULL,
224-
PyFunction_GET_CLOSURE(func));
223+
PyFrameConstructor *f = PyFunction_AS_FRAME_CONSTRUCTOR(func);
224+
PyThreadState *tstate = PyThreadState_GET();
225+
cell = _PyEval_Vector(tstate, f, ns, NULL, 0, NULL);
225226
if (cell != NULL) {
226227
if (bases != orig_bases) {
227228
if (PyMapping_SetItemString(ns, "__orig_bases__", orig_bases) < 0) {

0 commit comments

Comments
 (0)