8000 bpo-46323: Use PyObject_Vectorcall while calling ctypes callback func… · python/cpython@b552768 · GitHub
[go: up one dir, main page]

Skip to content

Commit b552768

Browse files
authored
bpo-46323: Use PyObject_Vectorcall while calling ctypes callback function (GH-31138)
1 parent 69e1097 commit b552768

File tree

2 files changed

+42
-38
lines changed

2 files changed

+42
-38
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Use :c:func:`PyObject_Vectorcall` while calling ctypes callback function.
2+
Patch by Dong-hee Na.

Modules/_ctypes/callbacks.c

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -146,47 +146,48 @@ static void _CallPythonObject(void *mem,
146146
int flags,
147147
void **pArgs)
148148
{
149-
Py_ssize_t i;
150-
PyObject *result;
151-
PyObject *arglist = NULL;
152-
Py_ssize_t nArgs;
149+
PyObject *result = NULL;
150+
PyObject **args = NULL;
151+
Py_ssize_t i = 0, j = 0, nargs = 0;
153152
PyObject *error_object = NULL;
154153
int *space;
155154
PyGILState_STATE state = PyGILState_Ensure();
156155

157-
nArgs = PySequence_Length(converters);
156+
assert(PyTuple_Check(converters));
157+
nargs = PyTuple_GET_SIZE(converters);
158158
/* Hm. What to return in case of error?
159159
For COM, 0xFFFFFFFF seems better than 0.
160160
*/
161-
if (nArgs < 0) {
161+
if (nargs < 0) {
162162
PrintError("BUG: PySequence_Length");
163163
goto Done;
164164
}
165165

166-
arglist = PyTuple_New(nArgs);
167-
if (!arglist) {
168-
PrintError("PyTuple_New()");
169-
goto Done;
166+
PyObject *args_stack[CTYPES_MAX_ARGCOUNT];
167+
if (nargs <= CTYPES_MAX_ARGCOUNT) {
168+
args = args_stack;
170169
}
171-
for (i = 0; i < nArgs; ++i) {
172-
/* Note: new reference! */
173-
PyObject *cnv = PySequence_GetItem(converters, i);
174-
StgDictObject *dict;
175-
if (cnv)
176-
dict = PyType_stgdict(cnv);
177-
else {
178-
PrintError("Getting argument converter %zd\n", i);
170+
else {
171+
args = PyMem_Malloc(nargs * sizeof(PyObject *));
172+
if (args == NULL) {
173+
PyErr_NoMemory();
179174
goto Done;
180175
}
176+
}
177+
178+
PyObject **cnvs = PySequence_Fast_ITEMS(converters);
179+
for (i = 0; i < nargs; i++) {
180+
PyObject *cnv = cnvs[i]; // borrowed ref
181+
StgDictObject *dict;
182+
dict = PyType_stgdict(cnv);
181183

182184
if (dict && dict->getfunc && !_ctypes_simple_instance(cnv)) {
183185
PyObject *v = dict->getfunc(*pArgs, dict->size);
184186
if (!v) {
185187
PrintError("create argument %zd:\n", i);
186-
Py_DECREF(cnv);
187188
goto Done;
188189
}
189-
PyTuple_SET_ITEM(arglist, i, v);
190+
args[i] = v;
190191
/* XXX XXX XX
191192
We have the problem that c_byte or c_short have dict->size of
192193
1 resp. 4, but these parameters are pushed as sizeof(int) bytes.
@@ -202,23 +203,20 @@ static void _CallPythonObject(void *mem,
202203
}
203204
if (!CDataObject_Check(obj)) {
204205
Py_DECREF(obj);
205-
Py_DECREF(cnv);
206206
PrintError("unexpected result of create argument %zd:\n", i);
207207
goto Done;
208208
}
209209
memcpy(obj->b_ptr, *pArgs, dict->size);
210-
PyTuple_SET_ITEM(arglist, i, (PyObject *)obj);
210+
args[i] = (PyObject *)obj;
211211
#ifdef MS_WIN32
212212
TryAddRef(dict, obj);
213213
#endif
214214
} else {
215215
PyErr_SetString(PyExc_TypeError,
216216
"cannot build parameter");
217217
PrintError("Parsing argument %zd\n", i);
218-
Py_DECREF(cnv);
219218
goto Done;
220219
}
221-
Py_DECREF(cnv);
222220
/* XXX error handling! */
223221
pArgs++;
224222
}
@@ -241,7 +239,7 @@ static void _CallPythonObject(void *mem,
241239
#endif
242240
}
243241

244-
result = PyObject_CallObject(callable, arglist);
242+
result = PyObject_Vectorcall(callable, args, nargs, NULL);
245243
if (result == NULL) {
246244
_PyErr_WriteUnraisableMsg("on calling ctypes callback function",
247245
callable);
@@ -308,7 +306,12 @@ static void _CallPythonObject(void *mem,
308306
Py_XDECREF(result);
309307

310308
Done:
311-
Py_XDECREF(arglist);
309+
for (j = 0; j < i; j++) {
310+
Py_DECREF(args[j]);
311+
}
312+
if (args != args_stack) {
313+
PyMem_Free(args);
314+
}
312315
PyGILState_Release(state);
313316
}
314317

@@ -328,12 +331,12 @@ static void closure_fcn(ffi_cif *cif,
328331
args);
329332
}
330333

331-
static CThunkObject* CThunkObject_new(Py_ssize_t nArgs)
334+
static CThunkObject* CThunkObject_new(Py_ssize_t nargs)
332335
{
333336
CThunkObject *p;
334337
Py_ssize_t i;
335338

336-
p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nArgs);
339+
p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nargs);
337340
if (p == NULL) {
338341
return NULL;
339342
}
@@ -348,7 +351,7 @@ static CThunkObject* CThunkObject_new(Py_ssize_t nArgs)
348351
p->setfunc = NULL;
349352
p->ffi_restype = NULL;
350353

351-
for (i = 0; i < nArgs + 1; ++i)
354+
for (i = 0; i < nargs + 1; ++i)
352355
p->atypes[i] = NULL;
353356
PyObject_GC_Track((PyObject *)p);
354357
return p;
@@ -361,11 +364,12 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
361364
{
362365
int result;
363366
CThunkObject *p;
364-
Py_ssize_t nArgs, i;
367+
Py_ssize_t nargs, i;
365368
ffi_abi cc;
366369

367-
nArgs = PySequence_Size(converters);
368-
p = CThunkObject_new(nArgs);
370+
assert(PyTuple_Check(converters));
371+
nargs = PyTuple_GET_SIZE(converters);
372+
p = CThunkObject_new(nargs);
369373
if (p == NULL)
370374
return NULL;
371375

@@ -378,12 +382,10 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
378382
}
379383

380384
p->flags = flags;
381-
for (i = 0; i < nArgs; ++i) {
382-
PyObject *cnv = PySequence_GetItem(converters, i);
383-
if (cnv == NULL)
384-
goto error;
385+
PyObject **cnvs = PySequence_Fast_ITEMS(converters);
386+
for (i = 0; i < nargs; ++i) {
387+
PyObject *cnv = cnvs[i]; // borrowed ref
385388
p->atypes[i] = _ctypes_get_ffi_type(cnv);
386-
Py_DECREF(cnv);
387389
}
388390
p->atypes[i] = NULL;
389391

@@ -409,7 +411,7 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
409411
cc = FFI_STDCALL;
410412
#endif
411413
result = ffi_prep_cif(&p->cif, cc,
412-
Py_SAFE_DOWNCAST(nArgs, Py_ssize_t, int),
414+
Py_SAFE_DOWNCAST(nargs, Py_ssize_t, int),
413415
_ctypes_get_ffi_type(restype),
414416
&p->atypes[0]);
415417
if (result != FFI_OK) {

0 commit comments

Comments
 (0)
0