@@ -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