in Jit/jit_rt.cpp [34:187]
static int JITRT_BindKeywordArgs(
PyFunctionObject* func,
PyObject** args,
size_t nargsf,
PyObject* kwnames,
PyObject** arg_space,
Py_ssize_t total_args,
Ref<PyObject>& kwdict,
Ref<PyObject>& varargs) {
PyCodeObject* co = (PyCodeObject*)func->func_code;
Py_ssize_t argcount = PyVectorcall_NARGS(nargsf);
for (int i = 0; i < total_args; i++) {
arg_space[i] = NULL;
}
// Create a dictionary for keyword parameters (**kwags)
if (co->co_flags & CO_VARKEYWORDS) {
kwdict = Ref<>::steal(PyDict_New());
if (kwdict == NULL) {
return 0;
}
arg_space[total_args - 1] = kwdict;
}
// Copy all positional arguments into local variables
Py_ssize_t n = std::min<Py_ssize_t>(argcount, co->co_argcount);
for (Py_ssize_t j = 0; j < n; j++) {
arg_space[j] = args[j];
}
// Pack other positional arguments into the *args argument
if (co->co_flags & CO_VARARGS) {
varargs = Ref<>::steal(_PyTuple_FromArray(args + n, argcount - n));
if (varargs == NULL) {
return 0;
}
Py_ssize_t i = total_args - 1;
if (co->co_flags & CO_VARKEYWORDS) {
i--;
}
arg_space[i] = varargs;
}
// Handle keyword arguments passed as two strided arrays
if (kwnames != NULL) {
for (Py_ssize_t i = 0; i < PyTuple_Size(kwnames); i++) {
PyObject** co_varnames;
PyObject* keyword = PyTuple_GET_ITEM(kwnames, i);
PyObject* value = args[argcount + i];
Py_ssize_t j;
if (keyword == NULL || !PyUnicode_Check(keyword)) {
return 0;
}
// Speed hack: do raw pointer compares. As names are
// normally interned this should almost always hit.
co_varnames = ((PyTupleObject*)(co->co_varnames))->ob_item;
for (j = co->co_posonlyargcount; j < total_args; j++) {
PyObject* name = co_varnames[j];
if (name == keyword) {
goto kw_found;
}
}
// Slow fallback, just in case
for (j = co->co_posonlyargcount; j < total_args; j++) {
PyObject* name = co_varnames[j];
int cmp = PyObject_RichCompareBool(keyword, name, Py_EQ);
if (cmp > 0) {
goto kw_found;
} else if (cmp < 0) {
return 0;
}
}
if (kwdict == NULL || PyDict_SetItem(kwdict, keyword, value) == -1) {
return 0;
}
continue;
kw_found:
if (arg_space[j] != NULL) {
return 0;
}
arg_space[j] = value;
}
}
// Check the number of positional arguments
if ((argcount > co->co_argcount) && !(co->co_flags & CO_VARARGS)) {
return 0;
}
// Add missing positional arguments (copy default values from defs)
if (argcount < co->co_argcount) {
Py_ssize_t defcount;
if (func->func_defaults != NULL) {
defcount = PyTuple_Size(func->func_defaults);
} else {
defcount = 0;
}
Py_ssize_t m = co->co_argcount - defcount;
Py_ssize_t missing = 0;
for (Py_ssize_t i = argcount; i < m; i++) {
if (arg_space[i] == NULL) {
missing++;
}
}
if (missing) {
return 0;
}
if (defcount) {
PyObject* const* defs =
&((PyTupleObject*)func->func_defaults)->ob_item[0];
for (Py_ssize_t i = std::max<Py_ssize_t>(n - m, 0); i < defcount; i++) {
if (arg_space[m + i] == NULL) {
PyObject* def = defs[i];
arg_space[m + i] = def;
}
}
}
}
// Add missing keyword arguments (copy default values from kwdefs)
if (co->co_kwonlyargcount > 0) {
Py_ssize_t missing = 0;
PyObject* kwdefs = func->func_kwdefaults;
for (Py_ssize_t i = co->co_argcount; i < total_args; i++) {
PyObject* name;
if (arg_space[i] != NULL)
continue;
name = PyTuple_GET_ITEM(co->co_varnames, i);
if (kwdefs != NULL) {
PyObject* def = PyDict_GetItemWithError(kwdefs, name);
if (def) {
arg_space[i] = def;
continue;
} else if (_PyErr_Occurred(_PyThreadState_GET())) {
return 0;
}
}
missing++;
}
if (missing) {
return 0;
}
}
return 1;
}