mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	Issue #27810: Add _PyCFunction_FastCallKeywords()
Use _PyCFunction_FastCallKeywords() in ceval.c: it allows to remove a lot of code from ceval.c which was only used to call C functions.
This commit is contained in:
		
							parent
							
								
									502893896a
								
							
						
					
					
						commit
						ae8b69c410
					
				
					 5 changed files with 71 additions and 138 deletions
				
			
		|  | @ -267,9 +267,16 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ | ||||||
|                                           PyObject *args, PyObject *kwargs); |                                           PyObject *args, PyObject *kwargs); | ||||||
| 
 | 
 | ||||||
| #ifndef Py_LIMITED_API | #ifndef Py_LIMITED_API | ||||||
|     PyAPI_FUNC(PyObject*) _PyStack_AsTuple(PyObject **stack, |     PyAPI_FUNC(PyObject*) _PyStack_AsTuple( | ||||||
|  |         PyObject **stack, | ||||||
|         Py_ssize_t nargs); |         Py_ssize_t nargs); | ||||||
| 
 | 
 | ||||||
|  |     PyAPI_FUNC(PyObject *) _PyStack_AsDict( | ||||||
|  |         PyObject **values, | ||||||
|  |         Py_ssize_t nkwargs, | ||||||
|  |         PyObject *kwnames, | ||||||
|  |         PyObject *func); | ||||||
|  | 
 | ||||||
|      /* Call the callable object func with the "fast call" calling convention:
 |      /* Call the callable object func with the "fast call" calling convention:
 | ||||||
|         args is a C array for positional arguments (nargs is the number of |         args is a C array for positional arguments (nargs is the number of | ||||||
|         positional arguments), kwargs is a dictionary for keyword arguments. |         positional arguments), kwargs is a dictionary for keyword arguments. | ||||||
|  |  | ||||||
|  | @ -42,6 +42,11 @@ PyAPI_FUNC(PyObject *) _PyCFunction_FastCallDict(PyObject *func, | ||||||
|     PyObject **args, |     PyObject **args, | ||||||
|     Py_ssize_t nargs, |     Py_ssize_t nargs, | ||||||
|     PyObject *kwargs); |     PyObject *kwargs); | ||||||
|  | 
 | ||||||
|  | PyAPI_FUNC(PyObject *) _PyCFunction_FastCallKeywords(PyObject *func, | ||||||
|  |     PyObject **stack, | ||||||
|  |     Py_ssize_t nargs, | ||||||
|  |     PyObject *kwnames); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| struct PyMethodDef { | struct PyMethodDef { | ||||||
|  |  | ||||||
|  | @ -2366,7 +2366,7 @@ _PyObject_Call_Prepend(PyObject *func, | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * | PyObject * | ||||||
| _PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, | _PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, | ||||||
|                 PyObject *func) |                 PyObject *func) | ||||||
| { | { | ||||||
|  | @ -2415,10 +2415,13 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, | ||||||
|     assert((nargs == 0 && nkwargs == 0) || stack != NULL); |     assert((nargs == 0 && nkwargs == 0) || stack != NULL); | ||||||
| 
 | 
 | ||||||
|     if (PyFunction_Check(func)) { |     if (PyFunction_Check(func)) { | ||||||
|         /* Fast-path: avoid temporary tuple or dict */ |  | ||||||
|         return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames); |         return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (PyCFunction_Check(func)) { | ||||||
|  |         return _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if (nkwargs > 0) { |     if (nkwargs > 0) { | ||||||
|         kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func); |         kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func); | ||||||
|         if (kwdict == NULL) { |         if (kwdict == NULL) { | ||||||
|  |  | ||||||
|  | @ -155,6 +155,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, | ||||||
|     PyObject *result; |     PyObject *result; | ||||||
|     int flags; |     int flags; | ||||||
| 
 | 
 | ||||||
|  |     assert(PyCFunction_Check(func)); | ||||||
|     assert(func != NULL); |     assert(func != NULL); | ||||||
|     assert(nargs >= 0); |     assert(nargs >= 0); | ||||||
|     assert(nargs == 0 || args != NULL); |     assert(nargs == 0 || args != NULL); | ||||||
|  | @ -243,6 +244,31 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | PyObject * | ||||||
|  | _PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack, | ||||||
|  |                               Py_ssize_t nargs, PyObject *kwnames) | ||||||
|  | { | ||||||
|  |     PyObject *kwdict, *result; | ||||||
|  |     Py_ssize_t nkwargs; | ||||||
|  | 
 | ||||||
|  |     assert(PyCFunction_Check(func)); | ||||||
|  | 
 | ||||||
|  |     nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); | ||||||
|  |     if (nkwargs > 0) { | ||||||
|  |         kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func); | ||||||
|  |         if (kwdict == NULL) { | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         kwdict = NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     result = _PyCFunction_FastCallDict(func, stack, nargs, kwdict); | ||||||
|  |     Py_XDECREF(kwdict); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* Methods (the standard built-in methods, that is) */ | /* Methods (the standard built-in methods, that is) */ | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
|  |  | ||||||
							
								
								
									
										162
									
								
								Python/ceval.c
									
										
									
									
									
								
							
							
						
						
									
										162
									
								
								Python/ceval.c
									
										
									
									
									
								
							|  | @ -115,8 +115,6 @@ static PyObject * call_function(PyObject ***, Py_ssize_t, PyObject *); | ||||||
| #endif | #endif | ||||||
| static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, PyObject *); | static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, PyObject *); | ||||||
| static PyObject * do_call_core(PyObject *, PyObject *, PyObject *); | static PyObject * do_call_core(PyObject *, PyObject *, PyObject *); | ||||||
| static PyObject * create_keyword_args(PyObject *, PyObject ***, PyObject *); |  | ||||||
| static PyObject * load_args(PyObject ***, Py_ssize_t); |  | ||||||
| 
 | 
 | ||||||
| #ifdef LLTRACE | #ifdef LLTRACE | ||||||
| static int lltrace; | static int lltrace; | ||||||
|  | @ -4892,21 +4890,6 @@ PyEval_GetFuncDesc(PyObject *func) | ||||||
|         return " object"; |         return " object"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void |  | ||||||
| err_args(PyObject *func, int flags, Py_ssize_t nargs) |  | ||||||
| { |  | ||||||
|     if (flags & METH_NOARGS) |  | ||||||
|         PyErr_Format(PyExc_TypeError, |  | ||||||
|                      "%.200s() takes no arguments (%zd given)", |  | ||||||
|                      ((PyCFunctionObject *)func)->m_ml->ml_name, |  | ||||||
|                      nargs); |  | ||||||
|     else |  | ||||||
|         PyErr_Format(PyExc_TypeError, |  | ||||||
|                      "%.200s() takes exactly one argument (%zd given)", |  | ||||||
|                      ((PyCFunctionObject *)func)->m_ml->ml_name, |  | ||||||
|                      nargs); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #define C_TRACE(x, call) \ | #define C_TRACE(x, call) \ | ||||||
| if (tstate->use_tracing && tstate->c_profilefunc) { \ | if (tstate->use_tracing && tstate->c_profilefunc) { \ | ||||||
|     if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \ |     if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \ | ||||||
|  | @ -4950,91 +4933,49 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames | ||||||
|     PyObject *x, *w; |     PyObject *x, *w; | ||||||
|     Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); |     Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); | ||||||
|     Py_ssize_t nargs = oparg - nkwargs; |     Py_ssize_t nargs = oparg - nkwargs; | ||||||
|  |     PyObject **stack; | ||||||
| 
 | 
 | ||||||
|     /* Always dispatch PyCFunction first, because these are
 |     /* Always dispatch PyCFunction first, because these are
 | ||||||
|        presumed to be the most frequent callable object. |        presumed to be the most frequent callable object. | ||||||
|     */ |     */ | ||||||
|     if (PyCFunction_Check(func)) { |     if (PyCFunction_Check(func)) { | ||||||
|         int flags = PyCFunction_GET_FLAGS(func); |  | ||||||
|         PyThreadState *tstate = PyThreadState_GET(); |         PyThreadState *tstate = PyThreadState_GET(); | ||||||
| 
 | 
 | ||||||
|         PCALL(PCALL_CFUNCTION); |         PCALL(PCALL_CFUNCTION); | ||||||
|         if (kwnames == NULL && flags & (METH_NOARGS | METH_O)) { |  | ||||||
|             PyCFunction meth = PyCFunction_GET_FUNCTION(func); |  | ||||||
|             PyObject *self = PyCFunction_GET_SELF(func); |  | ||||||
|             if (flags & METH_NOARGS && nargs == 0) { |  | ||||||
|                 C_TRACE(x, (*meth)(self,NULL)); |  | ||||||
| 
 | 
 | ||||||
|                 x = _Py_CheckFunctionResult(func, x, NULL); |         stack = (*pp_stack) - nargs - nkwargs; | ||||||
|             } |         C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames)); | ||||||
|             else if (flags & METH_O && nargs == 1) { |  | ||||||
|                 PyObject *arg = EXT_POP(*pp_stack); |  | ||||||
|                 C_TRACE(x, (*meth)(self,arg)); |  | ||||||
|                 Py_DECREF(arg); |  | ||||||
| 
 |  | ||||||
|                 x = _Py_CheckFunctionResult(func, x, NULL); |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 err_args(func, flags, nargs); |  | ||||||
|                 x = NULL; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|             PyObject *callargs, *kwdict = NULL; |  | ||||||
|             if (kwnames != NULL) { |  | ||||||
|                 kwdict = create_keyword_args(kwnames, pp_stack, func); |  | ||||||
|                 if (kwdict == NULL) { |  | ||||||
|                     x = NULL; |  | ||||||
|                     goto cfuncerror; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             callargs = load_args(pp_stack, nargs); |  | ||||||
|             if (callargs != NULL) { |  | ||||||
|                 READ_TIMESTAMP(*pintr0); |  | ||||||
|                 C_TRACE(x, PyCFunction_Call(func, callargs, kwdict)); |  | ||||||
|                 READ_TIMESTAMP(*pintr1); |  | ||||||
|                 Py_DECREF(callargs); |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 x = NULL; |  | ||||||
|             } |  | ||||||
|             Py_XDECREF(kwdict); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|       Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); |         if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { | ||||||
|       PyObject **stack; |             /* optimize access to bound methods */ | ||||||
|  |             PyObject *self = PyMethod_GET_SELF(func); | ||||||
|  |             PCALL(PCALL_METHOD); | ||||||
|  |             PCALL(PCALL_BOUND_METHOD); | ||||||
|  |             Py_INCREF(self); | ||||||
|  |             func = PyMethod_GET_FUNCTION(func); | ||||||
|  |             Py_INCREF(func); | ||||||
|  |             Py_SETREF(*pfunc, self); | ||||||
|  |             nargs++; | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             Py_INCREF(func); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|       if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { |         stack = (*pp_stack) - nargs - nkwargs; | ||||||
|           /* optimize access to bound methods */ |  | ||||||
|           PyObject *self = PyMethod_GET_SELF(func); |  | ||||||
|           PCALL(PCALL_METHOD); |  | ||||||
|           PCALL(PCALL_BOUND_METHOD); |  | ||||||
|           Py_INCREF(self); |  | ||||||
|           func = PyMethod_GET_FUNCTION(func); |  | ||||||
|           Py_INCREF(func); |  | ||||||
|           Py_SETREF(*pfunc, self); |  | ||||||
|           nargs++; |  | ||||||
|       } |  | ||||||
|       else { |  | ||||||
|           Py_INCREF(func); |  | ||||||
|       } |  | ||||||
| 
 | 
 | ||||||
|       stack = (*pp_stack) - nargs - nkwargs; |         READ_TIMESTAMP(*pintr0); | ||||||
|  |         if (PyFunction_Check(func)) { | ||||||
|  |             x = fast_function(func, stack, nargs, kwnames); | ||||||
|  |         } | ||||||
|  |         else { | ||||||
|  |             x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames); | ||||||
|  |         } | ||||||
|  |         READ_TIMESTAMP(*pintr1); | ||||||
| 
 | 
 | ||||||
|       READ_TIMESTAMP(*pintr0); |         Py_DECREF(func); | ||||||
|       if (PyFunction_Check(func)) { |  | ||||||
|           x = fast_function(func, stack, nargs, kwnames); |  | ||||||
|       } |  | ||||||
|       else { |  | ||||||
|           x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames); |  | ||||||
|       } |  | ||||||
|       READ_TIMESTAMP(*pintr1); |  | ||||||
| 
 |  | ||||||
|       Py_DECREF(func); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| cfuncerror: |  | ||||||
|     assert((x != NULL) ^ (PyErr_Occurred() != NULL)); |     assert((x != NULL) ^ (PyErr_Occurred() != NULL)); | ||||||
| 
 | 
 | ||||||
|     /* Clear the stack of the function object.  Also removes
 |     /* Clear the stack of the function object.  Also removes
 | ||||||
|  | @ -5242,55 +5183,6 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * |  | ||||||
| create_keyword_args(PyObject *names, PyObject ***pp_stack, |  | ||||||
|                     PyObject *func) |  | ||||||
| { |  | ||||||
|     Py_ssize_t nk = PyTuple_GET_SIZE(names); |  | ||||||
|     PyObject *kwdict = _PyDict_NewPresized(nk); |  | ||||||
|     if (kwdict == NULL) |  | ||||||
|         return NULL; |  | ||||||
|     while (--nk >= 0) { |  | ||||||
|         int err; |  | ||||||
|         PyObject *key = PyTuple_GET_ITEM(names, nk); |  | ||||||
|         PyObject *value = EXT_POP(*pp_stack); |  | ||||||
|         if (PyDict_GetItem(kwdict, key) != NULL) { |  | ||||||
|             PyErr_Format(PyExc_TypeError, |  | ||||||
|                          "%.200s%s got multiple values " |  | ||||||
|                          "for keyword argument '%U'", |  | ||||||
|                          PyEval_GetFuncName(func), |  | ||||||
|                          PyEval_GetFuncDesc(func), |  | ||||||
|                          key); |  | ||||||
|             Py_DECREF(value); |  | ||||||
|             Py_DECREF(kwdict); |  | ||||||
|             return NULL; |  | ||||||
|         } |  | ||||||
|         err = PyDict_SetItem(kwdict, key, value); |  | ||||||
|         Py_DECREF(value); |  | ||||||
|         if (err) { |  | ||||||
|             Py_DECREF(kwdict); |  | ||||||
|             return NULL; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return kwdict; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static PyObject * |  | ||||||
| load_args(PyObject ***pp_stack, Py_ssize_t nargs) |  | ||||||
| { |  | ||||||
|     PyObject *args = PyTuple_New(nargs); |  | ||||||
| 
 |  | ||||||
|     if (args == NULL) { |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     while (--nargs >= 0) { |  | ||||||
|         PyObject *arg= EXT_POP(*pp_stack); |  | ||||||
|         PyTuple_SET_ITEM(args, nargs, arg); |  | ||||||
|     } |  | ||||||
|     return args; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static PyObject * | static PyObject * | ||||||
| do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict) | do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict) | ||||||
| { | { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Victor Stinner
						Victor Stinner