@@ -416,34 +416,39 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
416
416
Py_ssize_t tot_nkwds = pto_nkwds + nkwds ;
417
417
Py_ssize_t tot_nargskw = tot_nargs + tot_nkwds ;
418
418
419
+ PyObject * pto_kw_merged = NULL ; // pto_kw with duplicates merged (if any)
420
+ PyObject * tot_kwnames ;
421
+
419
422
/* Allocate Stack */
420
423
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 )) {
422
430
stack = small_stack ;
423
431
}
424
432
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 * ));
427
435
if (stack == NULL ) {
428
436
PyErr_NoMemory ();
429
437
return NULL ;
430
438
}
431
439
}
432
440
433
- PyObject * pto_kw_merged = NULL ; // pto_kw with duplicates merged (if any)
434
- PyObject * tot_kwnames ;
435
-
436
441
/* Copy keywords to stack */
437
442
if (!pto_nkwds ) {
438
443
tot_kwnames = kwnames ;
439
-
440
444
if (nkwds ) {
441
445
/* if !pto_nkwds & nkwds, then simply append kw */
442
446
memcpy (stack + tot_nargs , args + nargs , nkwds * sizeof (PyObject * ));
443
447
}
444
448
}
445
449
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>] */
447
452
PyObject * key , * val ;
448
453
449
454
/* Merge kw to pto_kw or add to tail (if not duplicate) */
@@ -464,27 +469,19 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
464
469
}
465
470
else {
466
471
/* Copy keyword tail to stack */
467
- PyTuple_SET_ITEM (tot_kwnames , pto_nkwds + n_tail , key );
468
- Py_INCREF (key );
469
472
stack [tot_nargs + pto_nkwds + n_tail ] = val ;
473
+ stack [tot_nargskw + n_tail ] = key ;
470
474
n_tail ++ ;
471
475
}
472
476
}
473
-
474
- /* Resize Stack and tot_kwnames */
475
477
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 );
488
485
}
489
486
490
487
/* Copy pto_kw_merged to stack */
@@ -496,6 +493,16 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
496
493
i ++ ;
497
494
}
498
495
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
+ }
499
506
}
500
507
501
508
/* Copy Positionals to stack */
@@ -532,15 +539,14 @@ partial_vectorcall(PyObject *self, PyObject *const *args,
532
539
}
533
540
return ret ;
534
541
542
+ error_0 :
543
+ Py_DECREF (tot_kwnames );
535
544
error_1 :
536
545
Py_XDECREF (pto_kw_merged );
537
546
error_2 :
538
547
if (stack != small_stack ) {
539
548
PyMem_Free (stack );
540
549
}
541
- if (pto_nkwds ) {
542
- Py_DECREF (tot_kwnames );
543
- }
544
550
return NULL ;
545
551
}
546
552
0 commit comments