diff options
author | Dong-hee Na <donghee.na@python.org> | 2022-02-08 13:09:17 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-08 13:09:17 (GMT) |
commit | b5527688aae11d0b5af58176267a9943576e71e5 (patch) | |
tree | ad529925b8e9bf71e8f75a9dcf02205b1a2ab57b /Modules | |
parent | 69e10976b2e7682c6d57f4272932ebc19f8e8859 (diff) | |
download | cpython-b5527688aae11d0b5af58176267a9943576e71e5.zip cpython-b5527688aae11d0b5af58176267a9943576e71e5.tar.gz cpython-b5527688aae11d0b5af58176267a9943576e71e5.tar.bz2 |
bpo-46323: Use PyObject_Vectorcall while calling ctypes callback function (GH-31138)
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_ctypes/callbacks.c | 78 |
1 files changed, 40 insertions, 38 deletions
diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index b4079ee..a8fee0d 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -146,47 +146,48 @@ static void _CallPythonObject(void *mem, int flags, void **pArgs) { - Py_ssize_t i; - PyObject *result; - PyObject *arglist = NULL; - Py_ssize_t nArgs; + PyObject *result = NULL; + PyObject **args = NULL; + Py_ssize_t i = 0, j = 0, nargs = 0; PyObject *error_object = NULL; int *space; PyGILState_STATE state = PyGILState_Ensure(); - nArgs = PySequence_Length(converters); + assert(PyTuple_Check(converters)); + nargs = PyTuple_GET_SIZE(converters); /* Hm. What to return in case of error? For COM, 0xFFFFFFFF seems better than 0. */ - if (nArgs < 0) { + if (nargs < 0) { PrintError("BUG: PySequence_Length"); goto Done; } - arglist = PyTuple_New(nArgs); - if (!arglist) { - PrintError("PyTuple_New()"); - goto Done; + PyObject *args_stack[CTYPES_MAX_ARGCOUNT]; + if (nargs <= CTYPES_MAX_ARGCOUNT) { + args = args_stack; } - for (i = 0; i < nArgs; ++i) { - /* Note: new reference! */ - PyObject *cnv = PySequence_GetItem(converters, i); - StgDictObject *dict; - if (cnv) - dict = PyType_stgdict(cnv); - else { - PrintError("Getting argument converter %zd\n", i); + else { + args = PyMem_Malloc(nargs * sizeof(PyObject *)); + if (args == NULL) { + PyErr_NoMemory(); goto Done; } + } + + PyObject **cnvs = PySequence_Fast_ITEMS(converters); + for (i = 0; i < nargs; i++) { + PyObject *cnv = cnvs[i]; // borrowed ref + StgDictObject *dict; + dict = PyType_stgdict(cnv); if (dict && dict->getfunc && !_ctypes_simple_instance(cnv)) { PyObject *v = dict->getfunc(*pArgs, dict->size); if (!v) { PrintError("create argument %zd:\n", i); - Py_DECREF(cnv); goto Done; } - PyTuple_SET_ITEM(arglist, i, v); + args[i] = v; /* XXX XXX XX We have the problem that c_byte or c_short have dict->size of 1 resp. 4, but these parameters are pushed as sizeof(int) bytes. @@ -202,12 +203,11 @@ static void _CallPythonObject(void *mem, } if (!CDataObject_Check(obj)) { Py_DECREF(obj); - Py_DECREF(cnv); PrintError("unexpected result of create argument %zd:\n", i); goto Done; } memcpy(obj->b_ptr, *pArgs, dict->size); - PyTuple_SET_ITEM(arglist, i, (PyObject *)obj); + args[i] = (PyObject *)obj; #ifdef MS_WIN32 TryAddRef(dict, obj); #endif @@ -215,10 +215,8 @@ static void _CallPythonObject(void *mem, PyErr_SetString(PyExc_TypeError, "cannot build parameter"); PrintError("Parsing argument %zd\n", i); - Py_DECREF(cnv); goto Done; } - Py_DECREF(cnv); /* XXX error handling! */ pArgs++; } @@ -241,7 +239,7 @@ static void _CallPythonObject(void *mem, #endif } - result = PyObject_CallObject(callable, arglist); + result = PyObject_Vectorcall(callable, args, nargs, NULL); if (result == NULL) { _PyErr_WriteUnraisableMsg("on calling ctypes callback function", callable); @@ -308,7 +306,12 @@ static void _CallPythonObject(void *mem, Py_XDECREF(result); Done: - Py_XDECREF(arglist); + for (j = 0; j < i; j++) { + Py_DECREF(args[j]); + } + if (args != args_stack) { + PyMem_Free(args); + } PyGILState_Release(state); } @@ -328,12 +331,12 @@ static void closure_fcn(ffi_cif *cif, args); } -static CThunkObject* CThunkObject_new(Py_ssize_t nArgs) +static CThunkObject* CThunkObject_new(Py_ssize_t nargs) { CThunkObject *p; Py_ssize_t i; - p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nArgs); + p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nargs); if (p == NULL) { return NULL; } @@ -348,7 +351,7 @@ static CThunkObject* CThunkObject_new(Py_ssize_t nArgs) p->setfunc = NULL; p->ffi_restype = NULL; - for (i = 0; i < nArgs + 1; ++i) + for (i = 0; i < nargs + 1; ++i) p->atypes[i] = NULL; PyObject_GC_Track((PyObject *)p); return p; @@ -361,11 +364,12 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable, { int result; CThunkObject *p; - Py_ssize_t nArgs, i; + Py_ssize_t nargs, i; ffi_abi cc; - nArgs = PySequence_Size(converters); - p = CThunkObject_new(nArgs); + assert(PyTuple_Check(converters)); + nargs = PyTuple_GET_SIZE(converters); + p = CThunkObject_new(nargs); if (p == NULL) return NULL; @@ -378,12 +382,10 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable, } p->flags = flags; - for (i = 0; i < nArgs; ++i) { - PyObject *cnv = PySequence_GetItem(converters, i); - if (cnv == NULL) - goto error; + PyObject **cnvs = PySequence_Fast_ITEMS(converters); + for (i = 0; i < nargs; ++i) { + PyObject *cnv = cnvs[i]; // borrowed ref p->atypes[i] = _ctypes_get_ffi_type(cnv); - Py_DECREF(cnv); } p->atypes[i] = NULL; @@ -409,7 +411,7 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable, cc = FFI_STDCALL; #endif result = ffi_prep_cif(&p->cif, cc, - Py_SAFE_DOWNCAST(nArgs, Py_ssize_t, int), + Py_SAFE_DOWNCAST(nargs, Py_ssize_t, int), _ctypes_get_ffi_type(restype), &p->atypes[0]); if (result != FFI_OK) { |