Skip to content

Commit 9cc3f1f

Browse files
committed
Tighten up Python-to-Python calls.
1 parent b5ee794 commit 9cc3f1f

File tree

4 files changed

+120
-69
lines changed

4 files changed

+120
-69
lines changed

Include/internal/pycore_frame.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,21 @@ _PyFrame_LocalsToFast(InterpreterFrame *frame, int clear);
152152
InterpreterFrame *_PyThreadState_PushFrame(
153153
PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals);
154154

155+
extern InterpreterFrame *
156+
_PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size);
157+
158+
static inline InterpreterFrame *
159+
_PyThreadState_BumpFramePointer(PyThreadState *tstate, size_t size)
160+
{
161+
PyObject **base = tstate->datastack_top;
162+
PyObject **top = base + size;
163+
if (top < tstate->datastack_limit) {
164+
tstate->datastack_top = top;
165+
return (InterpreterFrame *)base;
166+
}
167+
return _PyThreadState_BumpFramePointerSlow(tstate, size);
168+
}
169+
155170
void _PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame *frame);
156171

157172
#ifdef __cplusplus

Objects/frameobject.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -786,16 +786,15 @@ allocate_heap_frame(PyFrameConstructor *con, PyObject *locals)
786786
{
787787
PyCodeObject *code = (PyCodeObject *)con->fc_code;
788788
int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE;
789-
PyObject **localsarray = PyMem_Malloc(sizeof(PyObject *)*size);
790-
if (localsarray == NULL) {
789+
InterpreterFrame *frame = (InterpreterFrame *)PyMem_Malloc(sizeof(PyObject *)*size);
790+
if (frame == NULL) {
791791
PyErr_NoMemory();
792792
return NULL;
793793
}
794-
for (Py_ssize_t i=0; i < code->co_nlocalsplus; i++) {
795-
localsarray[i] = NULL;
796-
}
797-
InterpreterFrame *frame = (InterpreterFrame *)(localsarray + code->co_nlocalsplus);
798794
_PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus);
795+
for (Py_ssize_t i = 0; i < code->co_nlocalsplus; i++) {
796+
frame->localsplus[i] = NULL;
797+
}
799798
return frame;
800799
}
801800

Python/ceval.c

Lines changed: 84 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ static int get_exception_handler(PyCodeObject *, int, int*, int*, int*);
101101
static InterpreterFrame *
102102
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con,
103103
PyObject *locals, PyObject* const* args,
104-
size_t argcount, PyObject *kwnames, int steal_args);
104+
size_t argcount, PyObject *kwnames);
105105
static int
106106
_PyEvalFrameClearAndPop(PyThreadState *tstate, InterpreterFrame * frame);
107107

@@ -4646,7 +4646,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
46464646
InterpreterFrame *new_frame = _PyEvalFramePushAndInit(
46474647
tstate, PyFunction_AS_FRAME_CONSTRUCTOR(function), locals,
46484648
stack_pointer,
4649-
nargs, kwnames, 1);
4649+
nargs, kwnames);
46504650
STACK_SHRINK(postcall_shrink);
46514651
// The frame has stolen all the arguments from the stack,
46524652
// so there is no need to clean them up.
@@ -4720,11 +4720,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
47204720
/* PEP 523 */
47214721
DEOPT_IF(tstate->interp->eval_frame != NULL, CALL_FUNCTION);
47224722
STAT_INC(CALL_FUNCTION, hit);
4723-
InterpreterFrame *new_frame = _PyThreadState_PushFrame(
4724-
tstate, PyFunction_AS_FRAME_CONSTRUCTOR(func), NULL);
4723+
PyCodeObject *code = (PyCodeObject *)func->func_code;
4724+
size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
4725+
InterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size);
47254726
if (new_frame == NULL) {
47264727
goto error;
47274728
}
4729+
_PyFrame_InitializeSpecials(new_frame, PyFunction_AS_FRAME_CONSTRUCTOR(func),
4730+
NULL, code->co_nlocalsplus);
47284731
STACK_SHRINK(argcount);
47294732
for (int i = 0; i < argcount; i++) {
47304733
new_frame->localsplus[i] = stack_pointer[i];
@@ -4735,6 +4738,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
47354738
Py_INCREF(def);
47364739
new_frame->localsplus[argcount+i] = def;
47374740
}
4741+
for (int i = argcount+deflen; i < code->co_nlocalsplus; i++) {
4742+
new_frame->localsplus[i] = NULL;
4743+
}
47384744
STACK_SHRINK(1);
47394745
Py_DECREF(func);
47404746
_PyFrame_SetStackPointer(frame, stack_pointer);
@@ -5592,7 +5598,7 @@ get_exception_handler(PyCodeObject *code, int index, int *level, int *handler, i
55925598
static int
55935599
initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
55945600
PyObject **localsplus, PyObject *const *args,
5595-
Py_ssize_t argcount, PyObject *kwnames, int steal_args)
5601+
Py_ssize_t argcount, PyObject *kwnames)
55965602
{
55975603
PyCodeObject *co = (PyCodeObject*)con->fc_code;
55985604
const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
@@ -5626,21 +5632,14 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
56265632
}
56275633
for (j = 0; j < n; j++) {
56285634
PyObject *x = args[j];
5629-
if (!steal_args) {
5630-
Py_INCREF(x);
5631-
}
56325635
assert(localsplus[j] == NULL);
56335636
localsplus[j] = x;
56345637
}
56355638

56365639
/* Pack other positional arguments into the *args argument */
56375640
if (co->co_flags & CO_VARARGS) {
56385641
PyObject *u = NULL;
5639-
if (steal_args) {
5640-
u = _PyTuple_FromArraySteal(args + n, argcount - n);
5641-
} else {
5642-
u = _PyTuple_FromArray(args + n, argcount - n);
5643-
}
5642+
u = _PyTuple_FromArraySteal(args + n, argcount - n);
56445643
if (u == NULL) {
56455644
goto fail_post_positional;
56465645
}
@@ -5649,10 +5648,8 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
56495648
}
56505649
else if (argcount > n) {
56515650
/* Too many postional args. Error is reported later */
5652-
if (steal_args) {
5653-
for (j = n; j < argcount; j++) {
5654-
Py_DECREF(args[j]);
5655-
}
5651+
for (j = n; j < argcount; j++) {
5652+
Py_DECREF(args[j]);
56565653
}
56575654
}
56585655

@@ -5714,19 +5711,15 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
57145711
if (PyDict_SetItem(kwdict, keyword, value) == -1) {
57155712
goto kw_fail;
57165713
}
5717-
if (steal_args) {
5718-
Py_DECREF(value);
5719-
}
5714+
Py_DECREF(value);
57205715
continue;
57215716

57225717
kw_fail:
5723-
if (steal_args) {
5724-
for (;i < kwcount; i++) {
5725-
PyObject *value = args[i+argcount];
5726-
Py_DECREF(value);
5727-
}
5718+
for (;i < kwcount; i++) {
5719+
PyObject *value = args[i+argcount];
5720+
Py_DECREF(value);
57285721
}
5729-
goto fail_noclean;
5722+
goto fail_post_args;
57305723

57315724
kw_found:
57325725
if (localsplus[j] != NULL) {
@@ -5735,9 +5728,6 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
57355728
con->fc_qualname, keyword);
57365729
goto kw_fail;
57375730
}
5738-
if (!steal_args) {
5739-
Py_INCREF(value);
5740-
}
57415731
localsplus[j] = value;
57425732
}
57435733
}
@@ -5746,7 +5736,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
57465736
if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) {
57475737
too_many_positional(tstate, co, argcount, con->fc_defaults, localsplus,
57485738
con->fc_qualname);
5749-
goto fail_noclean;
5739+
goto fail_post_args;
57505740
}
57515741

57525742
/* Add missing positional arguments (copy default values from defs) */
@@ -5762,7 +5752,7 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
57625752
if (missing) {
57635753
missing_arguments(tstate, co, missing, defcount, localsplus,
57645754
con->fc_qualname);
5765-
goto fail_noclean;
5755+
goto fail_post_args;
57665756
}
57675757
if (n > m)
57685758
i = n - m;
@@ -5795,43 +5785,39 @@ initialize_locals(PyThreadState *tstate, PyFrameConstructor *con,
57955785
continue;
57965786
}
57975787
else if (_PyErr_Occurred(tstate)) {
5798-
goto fail_noclean;
5788+
goto fail_post_args;
57995789
}
58005790
}
58015791
missing++;
58025792
}
58035793
if (missing) {
58045794
missing_arguments(tstate, co, missing, -1, localsplus,
58055795
con->fc_qualname);
5806-
goto fail_noclean;
5796+
goto fail_post_args;
58075797
}
58085798
}
5809-
58105799
/* Copy closure variables to free variables */
58115800
for (i = 0; i < co->co_nfreevars; ++i) {
58125801
PyObject *o = PyTuple_GET_ITEM(con->fc_closure, i);
58135802
Py_INCREF(o);
58145803
localsplus[co->co_nlocals + co->co_nplaincellvars + i] = o;
58155804
}
5816-
58175805
return 0;
58185806

58195807
fail_pre_positional:
5820-
if (steal_args) {
5821-
for (j = 0; j < argcount; j++) {
5822-
Py_DECREF(args[j]);
5823-
}
5808+
for (j = 0; j < argcount; j++) {
5809+
Py_DECREF(args[j]);
58245810
}
58255811
/* fall through */
58265812
fail_post_positional:
5827-
if (steal_args) {
5828-
Py_ssize_t kwcount = kwnames != NULL ? PyTuple_GET_SIZE(kwnames) : 0;
5813+
if (kwnames) {
5814+
Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames);
58295815
for (j = argcount; j < argcount+kwcount; j++) {
58305816
Py_DECREF(args[j]);
58315817
}
58325818
}
58335819
/* fall through */
5834-
fail_noclean:
5820+
fail_post_args:
58355821
return -1;
58365822
}
58375823

@@ -5847,21 +5833,34 @@ make_coro_frame(PyThreadState *tstate,
58475833
int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE;
58485834
InterpreterFrame *frame = (InterpreterFrame *)PyMem_Malloc(sizeof(PyObject *)*size);
58495835
if (frame == NULL) {
5850-
PyErr_NoMemory();
5851-
return NULL;
5836+
goto fail;
58525837
}
5853-
for (Py_ssize_t i=0; i < code->co_nlocalsplus; i++) {
5838+
_PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus);
5839+
for (int i = 0; i < code->co_nlocalsplus; i++) {
58545840
frame->localsplus[i] = NULL;
58555841
}
5856-
_PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus);
58575842
assert(frame->frame_obj == NULL);
5858-
if (initialize_locals(tstate, con, frame->localsplus, args, argcount, kwnames, 0)) {
5843+
if (initialize_locals(tstate, con, frame->localsplus, args, argcount, kwnames)) {
58595844
_PyFrame_Clear(frame, 1);
58605845
return NULL;
58615846
}
58625847
return frame;
5848+
fail:
5849+
/* Consume the references */
5850+
for (Py_ssize_t i = 0; i < argcount; i++) {
5851+
Py_DECREF(args[i]);
5852+
}
5853+
if (kwnames) {
5854+
Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames);
5855+
for (Py_ssize_t i = 0; i < kwcount; i++) {
5856+
Py_DECREF(args[i+argcount]);
5857+
}
5858+
}
5859+
PyErr_NoMemory();
5860+
return NULL;
58635861
}
58645862

5863+
/* Consumes all the references to the args */
58655864
static PyObject *
58665865
make_coro(PyThreadState *tstate, PyFrameConstructor *con,
58675866
PyObject *locals,
@@ -5877,30 +5876,46 @@ make_coro(PyThreadState *tstate, PyFrameConstructor *con,
58775876
if (gen == NULL) {
58785877
return NULL;
58795878
}
5880-
58815879
return gen;
58825880
}
58835881

5884-
// If *steal_args* is set, the function will steal the references to all the arguments.
5885-
// In case of error, the function returns null and if *steal_args* is set, the caller
5886-
// will still own all the arguments.
5882+
/* Consumes all the references to the args */
58875883
static InterpreterFrame *
58885884
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con,
58895885
PyObject *locals, PyObject* const* args,
5890-
size_t argcount, PyObject *kwnames, int steal_args)
5886+
size_t argcount, PyObject *kwnames)
58915887
{
5892-
InterpreterFrame * frame = _PyThreadState_PushFrame(tstate, con, locals);
5888+
PyCodeObject * code = (PyCodeObject *)con->fc_code;
5889+
size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
5890+
InterpreterFrame *frame = _PyThreadState_BumpFramePointer(tstate, size);
58935891
if (frame == NULL) {
5894-
return NULL;
5892+
goto fail;
58955893
}
5896-
PyObject **localsarray = _PyFrame_GetLocalsArray(frame);
5897-
if (initialize_locals(tstate, con, localsarray, args, argcount, kwnames, steal_args)) {
5894+
_PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus);
5895+
PyObject **localsarray = &frame->localsplus[0];
5896+
for (int i = 0; i < code->co_nlocalsplus; i++) {
5897+
localsarray[i] = NULL;
5898+
}
5899+
if (initialize_locals(tstate, con, localsarray, args, argcount, kwnames)) {
58985900
_PyFrame_Clear(frame, 0);
58995901
return NULL;
59005902
}
59015903
frame->previous = tstate->frame;
59025904
tstate->frame = frame;
59035905
return frame;
5906+
fail:
5907+
/* Consume the references */
5908+
for (size_t i = 0; i < argcount; i++) {
5909+
Py_DECREF(args[i]);
5910+
}
5911+
if (kwnames) {
5912+
Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames);
5913+
for (Py_ssize_t i = 0; i < kwcount; i++) {
5914+
Py_DECREF(args[i+argcount]);
5915+
}
5916+
}
5917+
PyErr_NoMemory();
5918+
return NULL;
59045919
}
59055920

59065921
static int
@@ -5925,13 +5940,25 @@ _PyEval_Vector(PyThreadState *tstate, PyFrameConstructor *con,
59255940
PyObject *kwnames)
59265941
{
59275942
PyCodeObject *code = (PyCodeObject *)con->fc_code;
5943+
/* _PyEvalFramePushAndInit and make_coro consume
5944+
* all the references to their arguments
5945+
*/
5946+
for (size_t i = 0; i < argcount; i++) {
5947+
Py_INCREF(args[i]);
5948+
}
5949+
if (kwnames) {
5950+
Py_ssize_t kwcount = PyTuple_GET_SIZE(kwnames);
5951+
for (Py_ssize_t i = 0; i < kwcount; i++) {
5952+
Py_INCREF(args[i+argcount]);
5953+
}
5954+
}
59285955
int is_coro = code->co_flags &
59295956
(CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR);
59305957
if (is_coro) {
59315958
return make_coro(tstate, con, locals, args, argcount, kwnames);
59325959
}
59335960
InterpreterFrame *frame = _PyEvalFramePushAndInit(
5934-
tstate, con, locals, args, argcount, kwnames, 0);
5961+
tstate, con, locals, args, argcount, kwnames);
59355962
if (frame == NULL) {
59365963
return NULL;
59375964
}

Python/pystate.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2065,12 +2065,8 @@ push_chunk(PyThreadState *tstate, int size)
20652065
}
20662066

20672067
InterpreterFrame *
2068-
_PyThreadState_PushFrame(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals)
2068+
_PyThreadState_BumpFramePointerSlow(PyThreadState *tstate, size_t size)
20692069
{
2070-
PyCodeObject *code = (PyCodeObject *)con->fc_code;
2071-
int nlocalsplus = code->co_nlocalsplus;
2072-
size_t size = nlocalsplus + code->co_stacksize +
2073-
FRAME_SPECIALS_SIZE;
20742070
assert(size < INT_MAX/sizeof(PyObject *));
20752071
PyObject **base = tstate->datastack_top;
20762072
PyObject **top = base + size;
@@ -2083,7 +2079,21 @@ _PyThreadState_PushFrame(PyThreadState *tstate, PyFrameConstructor *con, PyObjec
20832079
else {
20842080
tstate->datastack_top = top;
20852081
}
2086-
InterpreterFrame *frame = (InterpreterFrame *)base;
2082+
return (InterpreterFrame *)base;
2083+
}
2084+
2085+
2086+
InterpreterFrame *
2087+
_PyThreadState_PushFrame(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals)
2088+
{
2089+
PyCodeObject *code = (PyCodeObject *)con->fc_code;
2090+
int nlocalsplus = code->co_nlocalsplus;
2091+
size_t size = nlocalsplus + code->co_stacksize +
2092+
FRAME_SPECIALS_SIZE;
2093+
InterpreterFrame *frame = _PyThreadState_BumpFramePointer(tstate, size);
2094+
if (frame == NULL) {
2095+
return NULL;
2096+
}
20872097
_PyFrame_InitializeSpecials(frame, con, locals, nlocalsplus);
20882098
for (int i=0; i < nlocalsplus; i++) {
20892099
frame->localsplus[i] = NULL;

0 commit comments

Comments
 (0)