@@ -382,18 +382,24 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
382382 return NULL ;
383383 }
384384
385- PyObject * * pto_args = _PyTuple_ITEMS (pto -> args );
386- Py_ssize_t pto_nargs = PyTuple_GET_SIZE (pto -> args );
387- Py_ssize_t pto_nkwds = PyDict_GET_SIZE (pto -> kw );
385+ PyObject * result = NULL ;
386+ PyObject * partial_function = Py_NewRef (pto -> fn );
387+ PyObject * partial_args = Py_NewRef (pto -> args );
388+ PyObject * partial_keywords = Py_NewRef (pto -> kw );
389+
390+ PyObject * * pto_args = _PyTuple_ITEMS (partial_args );
391+ Py_ssize_t pto_nargs = PyTuple_GET_SIZE (partial_args );
392+ Py_ssize_t pto_nkwds = PyDict_GET_SIZE (partial_keywords );
388393 Py_ssize_t nkwds = kwnames == NULL ? 0 : PyTuple_GET_SIZE (kwnames );
389394 Py_ssize_t nargskw = nargs + nkwds ;
390395
391396 /* Special cases */
392397 if (!pto_nkwds ) {
393398 /* Fast path if we're called without arguments */
394399 if (nargskw == 0 ) {
395- return _PyObject_VectorcallTstate (tstate , pto -> fn , pto_args ,
396- pto_nargs , NULL );
400+ result = _PyObject_VectorcallTstate (tstate , partial_function , pto_args ,
401+ pto_nargs , NULL );
402+ goto done ;
397403 }
398404
399405 /* Use PY_VECTORCALL_ARGUMENTS_OFFSET to prepend a single
@@ -402,10 +408,10 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
402408 PyObject * * newargs = (PyObject * * )args - 1 ;
403409 PyObject * tmp = newargs [0 ];
404410 newargs [0 ] = pto_args [0 ];
405- PyObject * ret = _PyObject_VectorcallTstate (tstate , pto -> fn , newargs ,
406- nargs + 1 , kwnames );
411+ result = _PyObject_VectorcallTstate (tstate , partial_function , newargs ,
412+ nargs + 1 , kwnames );
407413 newargs [0 ] = tmp ;
408- return ret ;
414+ goto done ;
409415 }
410416 }
411417
@@ -435,7 +441,8 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
435441 else {
436442 stack = PyMem_Malloc (init_stack_size * sizeof (PyObject * ));
437443 if (stack == NULL ) {
438- return PyErr_NoMemory ();
444+ PyErr_NoMemory ();
445+ goto done ;
439446 }
440447 }
441448
@@ -457,20 +464,20 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
457464 for (Py_ssize_t i = 0 ; i < nkwds ; ++ i ) {
458465 key = PyTuple_GET_ITEM (kwnames , i );
459466 val = args [nargs + i ];
460- int contains = PyDict_Contains (pto -> kw , key );
467+ int contains = PyDict_Contains (partial_keywords , key );
461468 if (contains < 0 ) {
462- goto error ;
469+ goto clean_stack ;
463470 }
464471 else if (contains == 1 ) {
465472 if (pto_kw_merged == NULL ) {
466- pto_kw_merged = PyDict_Copy (pto -> kw );
473+ pto_kw_merged = PyDict_Copy (partial_keywords );
467474 if (pto_kw_merged == NULL ) {
468- goto error ;
475+ goto clean_stack ;
469476 }
470477 }
471478 if (PyDict_SetItem (pto_kw_merged , key , val ) < 0 ) {
472479 Py_DECREF (pto_kw_merged );
473- goto error ;
480+ goto clean_stack ;
474481 }
475482 }
476483 else {
@@ -486,7 +493,7 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
486493 tot_kwnames = PyTuple_New (tot_nkwds - n_merges );
487494 if (tot_kwnames == NULL ) {
488495 Py_XDECREF (pto_kw_merged );
489- goto error ;
496+ goto clean_stack ;
490497 }
491498 for (Py_ssize_t i = 0 ; i < n_tail ; ++ i ) {
492499 key = Py_NewRef (stack [tot_nargskw + i ]);
@@ -496,7 +503,7 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
496503 /* Copy pto_keywords with overlapping call keywords merged
497504 * Note, tail is already coppied. */
498505 Py_ssize_t pos = 0 , i = 0 ;
499- PyObject * keyword_dict = n_merges ? pto_kw_merged : pto -> kw ;
506+ PyObject * keyword_dict = n_merges ? pto_kw_merged : partial_keywords ;
500507 Py_BEGIN_CRITICAL_SECTION (keyword_dict );
501508 while (PyDict_Next (keyword_dict , & pos , & key , & val )) {
502509 assert (i < pto_nkwds );
@@ -515,10 +522,8 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
515522 tmp_stack = PyMem_Realloc (stack , (tot_nargskw - n_merges ) * sizeof (PyObject * ));
516523 if (tmp_stack == NULL ) {
517524 Py_DECREF (tot_kwnames );
518- if (stack != small_stack ) {
519- PyMem_Free (stack );
520- }
521- return PyErr_NoMemory ();
525+ PyErr_NoMemory ();
526+ goto clean_stack ;
522527 }
523528 stack = tmp_stack ;
524529 }
@@ -547,21 +552,22 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
547552 memcpy (stack + pto_nargs , args , nargs * sizeof (PyObject * ));
548553 }
549554
550- PyObject * ret = _PyObject_VectorcallTstate (tstate , pto -> fn , stack ,
551- tot_nargs , tot_kwnames );
552- if (stack != small_stack ) {
553- PyMem_Free (stack );
554- }
555+ result = _PyObject_VectorcallTstate (tstate , partial_function , stack ,
556+ tot_nargs , tot_kwnames );
555557 if (pto_nkwds ) {
556558 Py_DECREF (tot_kwnames );
557559 }
558- return ret ;
559560
560- error :
561+ clean_stack :
561562 if (stack != small_stack ) {
562563 PyMem_Free (stack );
563564 }
564- return NULL ;
565+
566+ done :
567+ Py_DECREF (partial_function );
568+ Py_DECREF (partial_args );
569+ Py_DECREF (partial_keywords );
570+ return result ;
565571}
566572
567573/* Set pto->vectorcall depending on the parameters of the partial object */
0 commit comments