https://github.com/python/cpython/commit/1c327a4464fa47f5d3aaf4c6c0184cb14ef2e21e
commit: 1c327a4464fa47f5d3aaf4c6c0184cb14ef2e21e
branch: main
author: Sergey B Kirpichev <[email protected]>
committer: vstinner <[email protected]>
date: 2026-10-26T00:29:42Z
summary:

gh-144650: Support vectorcall for _decimal.Decimal (#158207)

Co-authored-by: Cody Maloney <[email protected]>
Co-authored-by: Victor Stinner <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-09-26-05-18-21.gh-issue-144650.zqHLOW.rst
M Modules/_decimal/_decimal.c
M Modules/_decimal/clinic/_decimal.c.h

diff --git 
a/Misc/NEWS.d/next/Library/2026-09-26-05-18-21.gh-issue-144650.zqHLOW.rst 
b/Misc/NEWS.d/next/Library/2026-09-26-05-18-21.gh-issue-144650.zqHLOW.rst
new file mode 100644
index 000000000000000..ef4323571e59984
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-09-26-05-18-21.gh-issue-144650.zqHLOW.rst
@@ -0,0 +1,2 @@
+Use Argument Clinic vectorcall support for the :class:`decimal.Decimal` type.  
This offers
+1.10x speedup on creation of small instances.
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c
index 6a202e010ce2796..4849b447e277bfc 100644
--- a/Modules/_decimal/_decimal.c
+++ b/Modules/_decimal/_decimal.c
@@ -3313,6 +3313,7 @@ PyDec_FromObject(PyObject *v, PyObject *context)
 }
 
 /*[clinic input]
+@vectorcall
 @classmethod
 _decimal.Decimal.__new__ as dec_new
 
@@ -3329,7 +3330,7 @@ trap is active.
 
 static PyObject *
 dec_new_impl(PyTypeObject *type, PyObject *value, PyObject *context)
-/*[clinic end generated code: output=35f48a40c65625ba input=5f8a0892d3fcef80]*/
+/*[clinic end generated code: output=35f48a40c65625ba input=0e5ca99183562cd9]*/
 {
     decimal_state *state = get_module_state_by_def(type);
     CONTEXT_CHECK_VA(state, context);
@@ -6190,6 +6191,7 @@ static PyType_Slot dec_slots[] = {
     {Py_tp_methods, dec_methods},
     {Py_tp_getset, dec_getsets},
     {Py_tp_new, dec_new},
+    {Py_tp_vectorcall, dec_vectorcall},
 
     // Number protocol
     {Py_nb_add, nm_mpd_qadd},
diff --git a/Modules/_decimal/clinic/_decimal.c.h 
b/Modules/_decimal/clinic/_decimal.c.h
index 6c8e0b84402b12e..8aa362b5258d7df 100644
--- a/Modules/_decimal/clinic/_decimal.c.h
+++ b/Modules/_decimal/clinic/_decimal.c.h
@@ -867,7 +867,8 @@ static PyObject *
 dec_new_impl(PyTypeObject *type, PyObject *value, PyObject *context);
 
 static PyObject *
-dec_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+dec_new_helper(PyTypeObject *type, PyObject *const *args,
+    Py_ssize_t nargs, Py_ssize_t nkw, PyObject *kwargs, PyObject *kwnames)
 {
     PyObject *return_value = NULL;
     #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
@@ -899,12 +900,11 @@ dec_new(PyTypeObject *type, PyObject *args, PyObject 
*kwargs)
     #undef KWTUPLE
     PyObject *argsbuf[2];
     PyObject * const *fastargs;
-    Py_ssize_t nargs = PyTuple_GET_SIZE(args);
-    Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0;
+    Py_ssize_t noptargs = nargs + nkw - 0;
     PyObject *value = NULL;
     PyObject *context = Py_None;
 
-    fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, 
kwargs, NULL, &_parser,
+    fastargs = _PyArg_UnpackKeywords(args, nargs, kwargs, kwnames, &_parser,
             /*minpos*/ 0, /*maxpos*/ 2, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
     if (!fastargs) {
         goto exit;
@@ -926,6 +926,47 @@ dec_new(PyTypeObject *type, PyObject *args, PyObject 
*kwargs)
     return return_value;
 }
 
+static PyObject *
+dec_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
+{
+    return dec_new_helper(type, _PyTuple_CAST(args)->ob_item,
+        PyTuple_GET_SIZE(args),
+        kwargs ? PyDict_GET_SIZE(kwargs) : 0,
+        kwargs, NULL);
+}
+
+static PyObject *
+dec_vectorcall(PyObject *type, PyObject *const *args,
+    size_t nargsf, PyObject *kwnames)
+{
+    PyObject *return_value = NULL;
+    Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
+    PyObject *value = NULL;
+    PyObject *context = Py_None;
+
+    assert(_PyType_CAST(type)->tp_new == dec_new);
+    /* Make sure the type object is immutable: the generated
+     * vectorcall doesn't deal e.g. with users reassigning __init__. */
+    assert(PyType_HasFeature(_PyType_CAST(type), Py_TPFLAGS_IMMUTABLETYPE));
+    if (kwnames != NULL || nargs > 2) {
+        return dec_new_helper(_PyType_CAST(type), args, nargs,
+            kwnames ? PyTuple_GET_SIZE(kwnames) : 0,
+            NULL, kwnames);
+    }
+    if (nargs < 1) {
+        goto skip_optional;
+    }
+    value = args[0];
+    if (nargs < 2) {
+        goto skip_optional;
+    }
+    context = args[1];
+skip_optional:
+    return_value = dec_new_impl(_PyType_CAST(type), value, context);
+
+    return return_value;
+}
+
 PyDoc_STRVAR(_decimal_Context_create_decimal__doc__,
 "create_decimal($self, num=\'0\', /)\n"
 "--\n"
@@ -6289,4 +6330,4 @@ _decimal_Context_same_quantum(PyObject *context, 
PyTypeObject *cls, PyObject *co
 #ifndef _DECIMAL_CONTEXT_APPLY_METHODDEF
     #define _DECIMAL_CONTEXT_APPLY_METHODDEF
 #endif /* !defined(_DECIMAL_CONTEXT_APPLY_METHODDEF) */
-/*[clinic end generated code: output=02f6a8f0e93bc9f8 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=f9ddc00f5a7335c4 input=a9049054013a1b77]*/

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to