@@ -355,24 +355,6 @@ partial_descr_get(PyObject *self, PyObject *obj, PyObject *type)
355355    return  PyMethod_New (self , obj );
356356}
357357
358- #define  ALLOCATE_STACK (elsize , size , small_stack , stack )        \
359-     do {                                                        \
360-         if (size <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { \
361-             stack = small_stack;                                \
362-         }                                                       \
363-         else {                                                  \
364-             /* NOTE, size * elsize in theory could overflow */   \
365-             stack  =  PyMem_Malloc (size  *  elsize );                \
366-         }                                                       \
367-     } while  (0 )
368- 
369- #define  DEALLOCATE_STACK (small_stack , stack )    \
370-     do {                                        \
371-         if (stack != small_stack) {             \
372-             PyMem_Free(stack);                  \
373-         }                                       \
374-     } while (0)
375- 
376358static  PyObject  * 
377359partial_vectorcall (PyObject  * self , PyObject  * const  * args ,
378360                   size_t  nargsf , PyObject  * kwnames )
@@ -434,17 +416,25 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
434416    Py_ssize_t  tot_nkwds  =  pto_nkwds  +  nkwds ;
435417    Py_ssize_t  tot_nargskw  =  tot_nargs  +  tot_nkwds ;
436418
437-     PyObject  * * stack , * small_stack [_PY_FASTCALL_SMALL_STACK ];
438-     PyObject  * tot_kwnames ;
439- 
440-     /* Initialize stack & copy keywords to stack */ 
441-     if  (!pto_nkwds ) {
442-         /* Allocate Stack */ 
443-         ALLOCATE_STACK (sizeof (PyObject  * ), tot_nargskw , small_stack , stack );
419+     /* Allocate Stack */ 
420+     PyObject  * * tmp_stack , * * stack , * small_stack [_PY_FASTCALL_SMALL_STACK ];
421+     if  (tot_nargskw  <= (Py_ssize_t )Py_ARRAY_LENGTH (small_stack )) {
422+         stack  =  small_stack ;
423+     }
424+     else  {
425+         /* NOTE, size * elsize could overflow */ 
426+         stack  =  PyMem_Malloc (tot_nargskw  *  sizeof (PyObject  * ));
444427        if  (stack  ==  NULL ) {
445428            PyErr_NoMemory ();
446429            return  NULL ;
447430        }
431+     }
432+ 
433+     PyObject  * pto_kw_merged  =  NULL ;  // pto_kw with duplicates merged (if any) 
434+     PyObject  * tot_kwnames ;
435+ 
436+     /* Copy keywords to stack */ 
437+     if  (!pto_nkwds ) {
448438        tot_kwnames  =  kwnames ;
449439
450440        if  (nkwds ) {
@@ -453,74 +443,59 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
453443        }
454444    }
455445    else  {
446+         tot_kwnames  =  PyTuple_New (tot_nkwds );
456447        PyObject  * key , * val ;
457-         PyObject  * pto_kw  =  NULL ;  // pto_kw with duplicates merged (if any) 
458- 
459-         /* Temporary stack for keywords that are not in pto->kw */ 
460-         PyObject  * * kwtail , * small_kwtail [_PY_FASTCALL_SMALL_STACK  *  2 ];
461-         ALLOCATE_STACK (sizeof (PyObject  * ), nkwds  *  2 , small_kwtail , kwtail );
462-         if  (kwtail  ==  NULL ) {
463-             PyErr_NoMemory ();
464-             return  NULL ;
465-         }
466448
467449        /* Merge kw to pto_kw or add to tail (if not duplicate) */ 
468450        Py_ssize_t  n_tail  =  0 ;
469451        for  (Py_ssize_t  i  =  0 ; i  <  nkwds ; ++ i ) {
470452            key  =  PyTuple_GET_ITEM (kwnames , i );
471453            val  =  args [nargs  +  i ];
472454            if  (PyDict_Contains (pto -> kw , key )) {
473-                 if  (pto_kw  ==  NULL ) {
474-                     pto_kw  =  PyDict_Copy (pto -> kw );
475-                     if  (pto_kw  ==  NULL ) {
476-                         DEALLOCATE_STACK (small_kwtail , kwtail );
477-                         return  NULL ;
455+                 if  (pto_kw_merged  ==  NULL ) {
456+                     pto_kw_merged  =  PyDict_Copy (pto -> kw );
457+                     if  (pto_kw_merged  ==  NULL ) {
458+                         goto error_2 ;
478459                    }
479460                }
480-                 if  (PyDict_SetItem (pto_kw , key , val ) <  0 ) {
481-                     DEALLOCATE_STACK (small_kwtail , kwtail );
482-                     Py_DECREF (pto_kw );
483-                     return  NULL ;
461+                 if  (PyDict_SetItem (pto_kw_merged , key , val ) <  0 ) {
462+                     goto error_1 ;
484463                }
485464            }
486465            else  {
487-                 kwtail [n_tail ] =  key ;
488-                 kwtail [n_tail  +  nkwds ] =  val ;
466+                 /* Copy keyword tail to stack */ 
467+                 PyTuple_SET_ITEM (tot_kwnames , pto_nkwds  +  n_tail , key );
468+                 Py_INCREF (key );
469+                 stack [tot_nargs  +  pto_nkwds  +  n_tail ] =  val ;
489470                n_tail ++ ;
490471            }
491472        }
492473
493-         /* Allocate  Stack */ 
474+         /* Resize  Stack and tot_kwnames  */ 
494475        Py_ssize_t  n_merges  =  nkwds  -  n_tail ;
495-         tot_nkwds  =  pto_nkwds  +  nkwds  -  n_merges ;
496-         tot_nargskw  =  tot_nargs  +  tot_nkwds ;
497-         ALLOCATE_STACK (sizeof (PyObject  * ), tot_nargskw , small_stack , stack );
498-         if  (stack  ==  NULL ) {
499-             Py_XDECREF (pto_kw );
500-             PyErr_NoMemory ();
501-             return  NULL ;
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+             }
502488        }
503-         tot_kwnames  =  PyTuple_New (tot_nkwds );
504489
505-         /* Copy pto_kw  to stack */ 
490+         /* Copy pto_kw_merged  to stack */ 
506491        Py_ssize_t  pos  =  0 , i  =  0 ;
507-         while  (PyDict_Next (n_merges  ? pto_kw  : pto -> kw , & pos , & key , & val )) {
492+         while  (PyDict_Next (n_merges  ? pto_kw_merged  : pto -> kw , & pos , & key , & val )) {
508493            PyTuple_SET_ITEM (tot_kwnames , i , key );
509494            Py_INCREF (key );
510495            stack [tot_nargs  +  i ] =  val ;
511496            i ++ ;
512497        }
513-         Py_XDECREF (pto_kw );
514- 
515-         /* Copy kw tail to stack */ 
516-         for  (Py_ssize_t  i  =  0 ; i  <  n_tail ; ++ i ) {
517-             key  =  kwtail [i ];
518-             val  =  kwtail [i  +  nkwds ];
519-             PyTuple_SET_ITEM (tot_kwnames , pto_nkwds  +  i , key );
520-             Py_INCREF (key );
521-             stack [tot_nargs  +  pto_nkwds  +  i ] =  val ;
522-         }
523-         DEALLOCATE_STACK (small_kwtail , kwtail );
498+         Py_XDECREF (pto_kw_merged );
524499    }
525500
526501    /* Copy Positionals to stack */ 
@@ -549,15 +524,25 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
549524    /* Call / Maintenance / Return */ 
550525    PyObject  * ret  =  _PyObject_VectorcallTstate (tstate , pto -> fn , stack ,
551526                                               tot_nargs , tot_kwnames );
552-     DEALLOCATE_STACK (small_stack , stack );
527+     if  (stack  !=  small_stack ) {
528+         PyMem_Free (stack );
529+     }
553530    if  (pto_nkwds ) {
554531        Py_DECREF (tot_kwnames );
555532    }
556533    return  ret ;
557- }
558534
559- #undef  ALLOCATE_STACK
560- #undef  DEALLOCATE_STACK
535+ error_1 :
536+     Py_XDECREF (pto_kw_merged );
537+ error_2 :
538+     if  (stack  !=  small_stack ) {
539+         PyMem_Free (stack );
540+     }
541+     if  (pto_nkwds ) {
542+         Py_DECREF (tot_kwnames );
543+     }
544+     return  NULL ;
545+ }
561546
562547/* Set pto->vectorcall depending on the parameters of the partial object */ 
563548static  void 
0 commit comments