8
8
static PyObject *
9
9
cfunction_call_varargs (PyObject * func , PyObject * args , PyObject * kwargs );
10
10
11
+ static PyObject * const *
12
+ _PyStack_UnpackDict (PyObject * const * args , Py_ssize_t nargs , PyObject * kwargs ,
13
+ PyObject * * p_kwnames );
14
+
15
+ static void
16
+ _PyStack_UnpackDict_Free (PyObject * const * stack , Py_ssize_t nargs ,
17
+ PyObject * kwnames );
18
+
11
19
12
20
static PyObject *
13
21
null_error (void )
@@ -100,24 +108,19 @@ _PyObject_FastCallDict(PyObject *callable, PyObject *const *args,
100
108
}
101
109
102
110
PyObject * res ;
103
- if (kwargs == NULL ) {
111
+ if (kwargs == NULL || PyDict_GET_SIZE ( kwargs ) == 0 ) {
104
112
res = func (callable , args , nargsf , NULL );
105
113
}
106
114
else {
107
115
PyObject * kwnames ;
108
116
PyObject * const * newargs ;
109
- if (_PyStack_UnpackDict (args , nargs , kwargs , & newargs , & kwnames ) < 0 ) {
117
+ newargs = _PyStack_UnpackDict (args , nargs , kwargs , & kwnames );
118
+ if (newargs == NULL ) {
110
119
return NULL ;
111
120
}
112
- res = func (callable , newargs , nargs , kwnames );
113
- if (kwnames != NULL ) {
114
- Py_ssize_t i , n = PyTuple_GET_SIZE (kwnames ) + nargs ;
115
- for (i = 0 ; i < n ; i ++ ) {
116
- Py_DECREF (newargs [i ]);
117
- }
118
- PyMem_Free ((PyObject * * )newargs );
119
- Py_DECREF (kwnames );
120
- }
121
+ res = func (callable , newargs ,
122
+ nargs | PY_VECTORCALL_ARGUMENTS_OFFSET , kwnames );
123
+ _PyStack_UnpackDict_Free (newargs , nargs , kwnames );
121
124
}
122
125
return _Py_CheckFunctionResult (callable , res , NULL );
123
126
}
@@ -196,24 +199,23 @@ PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *kwargs)
196
199
return NULL ;
197
200
}
198
201
202
+ Py_ssize_t nargs = PyTuple_GET_SIZE (tuple );
203
+
204
+ /* Fast path for no keywords */
205
+ if (kwargs == NULL || PyDict_GET_SIZE (kwargs ) == 0 ) {
206
+ return func (callable , _PyTuple_ITEMS (tuple ), nargs , NULL );
207
+ }
208
+
199
209
/* Convert arguments & call */
200
210
PyObject * const * args ;
201
- Py_ssize_t nargs = PyTuple_GET_SIZE (tuple );
202
211
PyObject * kwnames ;
203
- if ( _PyStack_UnpackDict (_PyTuple_ITEMS (tuple ), nargs ,
204
- kwargs , & args , & kwnames ) < 0 ) {
212
+ args = _PyStack_UnpackDict (_PyTuple_ITEMS (tuple ), nargs , kwargs , & kwnames );
213
+ if ( args == NULL ) {
205
214
return NULL ;
206
215
}
207
- PyObject * result = func (callable , args , nargs , kwnames );
208
- if (kwnames != NULL ) {
209
- Py_ssize_t i , n = PyTuple_GET_SIZE (kwnames ) + nargs ;
210
- for (i = 0 ; i < n ; i ++ ) {
211
- Py_DECREF (args [i ]);
212
- }
213
- PyMem_Free ((PyObject * * )args );
214
- Py_DECREF (kwnames );
215
- }
216
-
216
+ PyObject * result = func (callable , args ,
217
+ nargs | PY_VECTORCALL_ARGUMENTS_OFFSET , kwnames );
218
+ _PyStack_UnpackDict_Free (args , nargs , kwnames );
217
219
return result ;
218
220
}
219
221
@@ -455,23 +457,22 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self,
455
457
456
458
case METH_FASTCALL | METH_KEYWORDS :
457
459
{
458
- PyObject * const * stack ;
459
- PyObject * kwnames ;
460
460
_PyCFunctionFastWithKeywords fastmeth = (_PyCFunctionFastWithKeywords )(void (* )(void ))meth ;
461
461
462
- if (_PyStack_UnpackDict (args , nargs , kwargs , & stack , & kwnames ) < 0 ) {
463
- goto exit ;
462
+ /* Fast path for no keywords */
463
+ if (kwargs == NULL || PyDict_GET_SIZE (kwargs ) == 0 ) {
464
+ result = (* fastmeth ) (self , args , nargs , NULL );
465
+ break ;
464
466
}
465
467
466
- result = (* fastmeth ) (self , stack , nargs , kwnames );
467
- if (kwnames != NULL ) {
468
- Py_ssize_t i , n = nargs + PyTuple_GET_SIZE (kwnames );
469
- for (i = 0 ; i < n ; i ++ ) {
470
- Py_DECREF (stack [i ]);
471
- }
472
- PyMem_Free ((PyObject * * )stack );
473
- Py_DECREF (kwnames );
468
+ PyObject * const * stack ;
469
+ PyObject * kwnames ;
470
+ stack = _PyStack_UnpackDict (args , nargs , kwargs , & kwnames );
471
+ if (stack == NULL ) {
472
+ goto exit ;
474
473
}
474
+ result = (* fastmeth ) (self , stack , nargs , kwnames );
475
+ _PyStack_UnpackDict_Free (stack , nargs , kwnames );
475
476
break ;
476
477
}
477
478
@@ -1206,53 +1207,63 @@ _PyStack_AsDict(PyObject *const *values, PyObject *kwnames)
1206
1207
}
1207
1208
1208
1209
1209
- int
1210
- _PyStack_UnpackDict (PyObject * const * args , Py_ssize_t nargs , PyObject * kwargs ,
1211
- PyObject * const * * p_stack , PyObject * * p_kwnames )
1212
- {
1213
- PyObject * * stack , * * kwstack ;
1214
- Py_ssize_t nkwargs ;
1215
- Py_ssize_t pos , i ;
1216
- PyObject * key , * value ;
1217
- PyObject * kwnames ;
1210
+ /* Convert (args, nargs, kwargs: dict) into a (stack, nargs, kwnames: tuple).
1218
1211
1219
- assert (nargs >= 0 );
1220
- assert (kwargs == NULL || PyDict_CheckExact (kwargs ));
1212
+ Allocate a new argument vector and keyword names tuple. Return the argument
1213
+ vector; return NULL with exception set on error. Return the keyword names
1214
+ tuple in *p_kwnames.
1221
1215
1222
- if (kwargs == NULL || (nkwargs = PyDict_GET_SIZE (kwargs )) == 0 ) {
1223
- * p_stack = args ;
1224
- * p_kwnames = NULL ;
1225
- return 0 ;
1226
- }
1216
+ The newly allocated argument vector supports PY_VECTORCALL_ARGUMENTS_OFFSET.
1217
+
1218
+ When done, you must call _PyStack_UnpackDict_Free(stack, nargs, kwnames)
1227
1219
1228
- if ((size_t )nargs > PY_SSIZE_T_MAX / sizeof (stack [0 ]) - (size_t )nkwargs ) {
1220
+ The type of keyword keys is not checked, these checks should be done
1221
+ later (ex: _PyArg_ParseStackAndKeywords). */
1222
+ static PyObject * const *
1223
+ _PyStack_UnpackDict (PyObject * const * args , Py_ssize_t nargs , PyObject * kwargs ,
1224
+ PyObject * * p_kwnames )
1225
+ {
1226
+ assert (nargs >= 0 );
1227
+ assert (kwargs != NULL );
1228
+ assert (PyDict_Check (kwargs ));
1229
+
1230
+ Py_ssize_t nkwargs = PyDict_GET_SIZE (kwargs );
1231
+ /* Check for overflow in the PyMem_Malloc() call below. The subtraction
1232
+ * in this check cannot overflow: both maxnargs and nkwargs are
1233
+ * non-negative signed integers, so their difference fits in the type. */
1234
+ Py_ssize_t maxnargs = PY_SSIZE_T_MAX / sizeof (args [0 ]) - 1 ;
1235
+ if (nargs > maxnargs - nkwargs ) {
1229
1236
PyErr_NoMemory ();
1230
- return -1 ;
1237
+ return NULL ;
1231
1238
}
1232
1239
1233
- stack = PyMem_Malloc ((nargs + nkwargs ) * sizeof (stack [0 ]));
1240
+ /* Add 1 to support PY_VECTORCALL_ARGUMENTS_OFFSET */
1241
+ PyObject * * stack = PyMem_Malloc ((1 + nargs + nkwargs ) * sizeof (args [0 ]));
1234
1242
if (stack == NULL ) {
1235
1243
PyErr_NoMemory ();
1236
- return -1 ;
1244
+ return NULL ;
1237
1245
}
1238
1246
1239
- kwnames = PyTuple_New (nkwargs );
1247
+ PyObject * kwnames = PyTuple_New (nkwargs );
1240
1248
if (kwnames == NULL ) {
1241
1249
PyMem_Free (stack );
1242
- return -1 ;
1250
+ return NULL ;
1243
1251
}
1244
1252
1253
+ stack ++ ; /* For PY_VECTORCALL_ARGUMENTS_OFFSET */
1254
+
1245
1255
/* Copy positional arguments */
1246
- for (i = 0 ; i < nargs ; i ++ ) {
1256
+ for (Py_ssize_t i = 0 ; i < nargs ; i ++ ) {
1247
1257
Py_INCREF (args [i ]);
1248
1258
stack [i ] = args [i ];
1249
1259
}
1250
1260
1251
- kwstack = stack + nargs ;
1252
- pos = i = 0 ;
1261
+ PyObject * * kwstack = stack + nargs ;
1253
1262
/* This loop doesn't support lookup function mutating the dictionary
1254
1263
to change its size. It's a deliberate choice for speed, this function is
1255
1264
called in the performance critical hot code. */
1265
+ Py_ssize_t pos = 0 , i = 0 ;
1266
+ PyObject * key , * value ;
1256
1267
while (PyDict_Next (kwargs , & pos , & key , & value )) {
1257
1268
Py_INCREF (key );
1258
1269
Py_INCREF (value );
@@ -1261,7 +1272,18 @@ _PyStack_UnpackDict(PyObject *const *args, Py_ssize_t nargs, PyObject *kwargs,
1261
1272
i ++ ;
1262
1273
}
1263
1274
1264
- * p_stack = stack ;
1265
1275
* p_kwnames = kwnames ;
1266
- return 0 ;
1276
+ return stack ;
1277
+ }
1278
+
1279
+ static void
1280
+ _PyStack_UnpackDict_Free (PyObject * const * stack , Py_ssize_t nargs ,
1281
+ PyObject * kwnames )
1282
+ {
1283
+ Py_ssize_t n = PyTuple_GET_SIZE (kwnames ) + nargs ;
1284
+ for (Py_ssize_t i = 0 ; i < n ; i ++ ) {
1285
+ Py_DECREF (stack [i ]);
1286
+ }
1287
+ PyMem_Free ((PyObject * * )stack - 1 );
1288
+ Py_DECREF (kwnames );
1267
1289
}
0 commit comments