@@ -416,34 +416,39 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
416416 Py_ssize_t tot_nkwds = pto_nkwds + nkwds ;
417417 Py_ssize_t tot_nargskw = tot_nargs + tot_nkwds ;
418418
419+ PyObject * pto_kw_merged = NULL ; // pto_kw with duplicates merged (if any)
420+ PyObject * tot_kwnames ;
421+
419422 /* Allocate Stack */
420423 PyObject * * tmp_stack , * * stack , * small_stack [_PY_FASTCALL_SMALL_STACK ];
421- if (tot_nargskw <= (Py_ssize_t )Py_ARRAY_LENGTH (small_stack )) {
424+ Py_ssize_t init_stack_size = tot_nargskw ;
425+ if (pto_nkwds ) {
426+ // If pto_nkwds, allocate additional space for temporary new keys
427+ init_stack_size += nkwds ;
428+ }
429+ if (init_stack_size <= (Py_ssize_t )Py_ARRAY_LENGTH (small_stack )) {
422430 stack = small_stack ;
423431 }
424432 else {
425- /* NOTE, size * elsize could overflow */
426- stack = PyMem_Malloc (tot_nargskw * sizeof (PyObject * ));
433+ /* NOTE, in theory size * elsize could overflow */
434+ stack = PyMem_Malloc (init_stack_size * sizeof (PyObject * ));
427435 if (stack == NULL ) {
428436 PyErr_NoMemory ();
429437 return NULL ;
430438 }
431439 }
432440
433- PyObject * pto_kw_merged = NULL ; // pto_kw with duplicates merged (if any)
434- PyObject * tot_kwnames ;
435-
436441 /* Copy keywords to stack */
437442 if (!pto_nkwds ) {
438443 tot_kwnames = kwnames ;
439-
440444 if (nkwds ) {
441445 /* if !pto_nkwds & nkwds, then simply append kw */
442446 memcpy (stack + tot_nargs , args + nargs , nkwds * sizeof (PyObject * ));
443447 }
444448 }
445449 else {
446- tot_kwnames = PyTuple_New (tot_nkwds );
450+ /* stack is now [<positionals>, <pto_kwds>, <kwds>, <kwds_keys>]
451+ * Will truncate to [<positionals>, <merged_kwds>] */
447452 PyObject * key , * val ;
448453
449454 /* Merge kw to pto_kw or add to tail (if not duplicate) */
@@ -464,27 +469,19 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
464469 }
465470 else {
466471 /* Copy keyword tail to stack */
467- PyTuple_SET_ITEM (tot_kwnames , pto_nkwds + n_tail , key );
468- Py_INCREF (key );
469472 stack [tot_nargs + pto_nkwds + n_tail ] = val ;
473+ stack [tot_nargskw + n_tail ] = key ;
470474 n_tail ++ ;
471475 }
472476 }
473-
474- /* Resize Stack and tot_kwnames */
475477 Py_ssize_t n_merges = nkwds - n_tail ;
476- if (n_merges ) {
477- if (stack != small_stack ) {
478- tmp_stack = PyMem_Realloc (stack , (tot_nargskw - n_merges ) * sizeof (PyObject * ));
479- if (tmp_stack == NULL ) {
480- PyErr_NoMemory ();
481- goto error_1 ;
482- }
483- stack = tmp_stack ;
484- }
485- if (_PyTuple_Resize (& tot_kwnames , (tot_nkwds - n_merges )) != 0 ) {
486- goto error_1 ;
487- }
478+
479+ /* Create tot_kwnames */
480+ tot_kwnames = PyTuple_New (pto_nkwds + n_tail );
481+ for (Py_ssize_t i = 0 ; i < n_tail ; ++ i ) {
482+ key = stack [tot_nargskw + i ];
483+ PyTuple_SET_ITEM (tot_kwnames , pto_nkwds + i , key );
484+ Py_INCREF (key );
488485 }
489486
490487 /* Copy pto_kw_merged to stack */
@@ -496,6 +493,16 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
496493 i ++ ;
497494 }
498495 Py_XDECREF (pto_kw_merged );
496+
497+ /* Resize Stack */
498+ if (n_merges && stack != small_stack ) {
499+ tmp_stack = PyMem_Realloc (stack , (tot_nargskw - n_merges ) * sizeof (PyObject * ));
500+ if (tmp_stack == NULL ) {
501+ PyErr_NoMemory ();
502+ goto error_0 ;
503+ }
504+ stack = tmp_stack ;
505+ }
499506 }
500507
501508 /* Copy Positionals to stack */
@@ -532,15 +539,14 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
532539 }
533540 return ret ;
534541
542+ error_0 :
543+ Py_DECREF (tot_kwnames );
535544error_1 :
536545 Py_XDECREF (pto_kw_merged );
537546error_2 :
538547 if (stack != small_stack ) {
539548 PyMem_Free (stack );
540549 }
541- if (pto_nkwds ) {
542- Py_DECREF (tot_kwnames );
543- }
544550 return NULL ;
545551}
546552
0 commit comments