Skip to content

Commit e8fbaf8

Browse files
committed
regain previous performance
1 parent cc557e9 commit e8fbaf8

File tree

1 file changed

+33
-27
lines changed

1 file changed

+33
-27
lines changed

Modules/_functoolsmodule.c

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -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);
535544
error_1:
536545
Py_XDECREF(pto_kw_merged);
537546
error_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

Comments
 (0)