@@ -463,18 +463,12 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
463463 if (pto_kw_merged == NULL ) {
464464 pto_kw_merged = PyDict_Copy (pto -> kw );
465465 if (pto_kw_merged == NULL ) {
466- if (stack != small_stack ) {
467- PyMem_Free (stack );
468- }
469- return NULL ;
466+ goto error ;
470467 }
471468 }
472469 if (PyDict_SetItem (pto_kw_merged , key , val ) < 0 ) {
473470 Py_DECREF (pto_kw_merged );
474- if (stack != small_stack ) {
475- PyMem_Free (stack );
476- }
477- return NULL ;
471+ goto error ;
478472 }
479473 }
480474 else {
@@ -489,10 +483,8 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
489483 /* Create total kwnames */
490484 tot_kwnames = PyTuple_New (tot_nkwds - n_merges );
491485 if (tot_kwnames == NULL ) {
492- if (stack != small_stack ) {
493- PyMem_Free (stack );
494- }
495- return NULL ;
486+ Py_XDECREF (pto_kw_merged );
487+ goto error ;
496488 }
497489 for (Py_ssize_t i = 0 ; i < n_tail ; ++ i ) {
498490 key = Py_NewRef (stack [tot_nargskw + i ]);
@@ -502,14 +494,17 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
502494 /* Copy pto_keywords with overlapping call keywords merged */
503495 Py_ssize_t pos = 0 , i = 0 ;
504496 while (PyDict_Next (n_merges ? pto_kw_merged : pto -> kw , & pos , & key , & val )) {
497+ assert (i < tot_nkwds - n_merges );
505498 PyTuple_SET_ITEM (tot_kwnames , i , Py_NewRef (key ));
506499 stack [tot_nargs + i ] = val ;
507500 i ++ ;
508501 }
502+ assert (i == tot_nkwds - n_merges );
509503 Py_XDECREF (pto_kw_merged );
510504
511- /* Resize Stack if the call has keywords */
512- if (nkwds && stack != small_stack ) {
505+ /* Resize Stack if the call has keywords
506+ * Only resize if nkwds > 6 (1% of github use cases have 7 or more kwds) */
507+ if (nkwds > 6 && stack != small_stack ) {
513508 tmp_stack = PyMem_Realloc (stack , (tot_nargskw - n_merges ) * sizeof (PyObject * ));
514509 if (tmp_stack == NULL ) {
515510 Py_DECREF (tot_kwnames );
@@ -526,7 +521,7 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
526521 if (pto_phcount ) {
527522 Py_ssize_t j = 0 ; // New args index
528523 for (Py_ssize_t i = 0 ; i < pto_nargs ; i ++ ) {
529- if (pto_args [i ] == pto -> placeholder ){
524+ if (pto_args [i ] == pto -> placeholder ) {
530525 stack [i ] = args [j ];
531526 j += 1 ;
532527 }
@@ -554,6 +549,12 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
554549 Py_DECREF (tot_kwnames );
555550 }
556551 return ret ;
552+
553+ error :
554+ if (stack != small_stack ) {
555+ PyMem_Free (stack );
556+ }
557+ return NULL ;
557558}
558559
559560/* Set pto->vectorcall depending on the parameters of the partial object */
0 commit comments