mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +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); | ||||
| 
 | ||||
| #ifndef Py_LIMITED_API | ||||
|     PyAPI_FUNC(PyObject*) _PyStack_AsTuple(PyObject **stack, | ||||
|     PyAPI_FUNC(PyObject*) _PyStack_AsTuple( | ||||
|         PyObject **stack, | ||||
|         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:
 | ||||
|         args is a C array for positional arguments (nargs is the number of | ||||
|         positional arguments), kwargs is a dictionary for keyword arguments. | ||||
|  |  | |||
|  | @ -42,6 +42,11 @@ PyAPI_FUNC(PyObject *) _PyCFunction_FastCallDict(PyObject *func, | |||
|     PyObject **args, | ||||
|     Py_ssize_t nargs, | ||||
|     PyObject *kwargs); | ||||
| 
 | ||||
| PyAPI_FUNC(PyObject *) _PyCFunction_FastCallKeywords(PyObject *func, | ||||
|     PyObject **stack, | ||||
|     Py_ssize_t nargs, | ||||
|     PyObject *kwnames); | ||||
| #endif | ||||
| 
 | ||||
| struct PyMethodDef { | ||||
|  |  | |||
|  | @ -2366,7 +2366,7 @@ _PyObject_Call_Prepend(PyObject *func, | |||
|     return result; | ||||
| } | ||||
| 
 | ||||
| static PyObject * | ||||
| PyObject * | ||||
| _PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, | ||||
|                 PyObject *func) | ||||
| { | ||||
|  | @ -2415,10 +2415,13 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, | |||
|     assert((nargs == 0 && nkwargs == 0) || stack != NULL); | ||||
| 
 | ||||
|     if (PyFunction_Check(func)) { | ||||
|         /* Fast-path: avoid temporary tuple or dict */ | ||||
|         return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames); | ||||
|     } | ||||
| 
 | ||||
|     if (PyCFunction_Check(func)) { | ||||
|         return _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames); | ||||
|     } | ||||
| 
 | ||||
|     if (nkwargs > 0) { | ||||
|         kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func); | ||||
|         if (kwdict == NULL) { | ||||
|  |  | |||
|  | @ -155,6 +155,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, | |||
|     PyObject *result; | ||||
|     int flags; | ||||
| 
 | ||||
|     assert(PyCFunction_Check(func)); | ||||
|     assert(func != NULL); | ||||
|     assert(nargs >= 0); | ||||
|     assert(nargs == 0 || args != NULL); | ||||
|  | @ -243,6 +244,31 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, | |||
|     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) */ | ||||
| 
 | ||||
| static void | ||||
|  |  | |||
							
								
								
									
										114
									
								
								Python/ceval.c
									
										
									
									
									
								
							
							
						
						
									
										114
									
								
								Python/ceval.c
									
										
									
									
									
								
							|  | @ -115,8 +115,6 @@ static PyObject * call_function(PyObject ***, Py_ssize_t, PyObject *); | |||
| #endif | ||||
| static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, 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 | ||||
| static int lltrace; | ||||
|  | @ -4892,21 +4890,6 @@ PyEval_GetFuncDesc(PyObject *func) | |||
|         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) \ | ||||
| if (tstate->use_tracing && tstate->c_profilefunc) { \ | ||||
|     if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \ | ||||
|  | @ -4950,61 +4933,20 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames | |||
|     PyObject *x, *w; | ||||
|     Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); | ||||
|     Py_ssize_t nargs = oparg - nkwargs; | ||||
|     PyObject **stack; | ||||
| 
 | ||||
|     /* Always dispatch PyCFunction first, because these are
 | ||||
|        presumed to be the most frequent callable object. | ||||
|     */ | ||||
|     if (PyCFunction_Check(func)) { | ||||
|         int flags = PyCFunction_GET_FLAGS(func); | ||||
|         PyThreadState *tstate = PyThreadState_GET(); | ||||
| 
 | ||||
|         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); | ||||
|             } | ||||
|             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); | ||||
|         stack = (*pp_stack) - nargs - nkwargs; | ||||
|         C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames)); | ||||
|     } | ||||
|     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 { | ||||
|       Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); | ||||
|       PyObject **stack; | ||||
| 
 | ||||
|         if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { | ||||
|             /* optimize access to bound methods */ | ||||
|             PyObject *self = PyMethod_GET_SELF(func); | ||||
|  | @ -5034,7 +4976,6 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames | |||
|         Py_DECREF(func); | ||||
|     } | ||||
| 
 | ||||
| cfuncerror: | ||||
|     assert((x != NULL) ^ (PyErr_Occurred() != NULL)); | ||||
| 
 | ||||
|     /* 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; | ||||
| } | ||||
| 
 | ||||
| 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 * | ||||
| do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict) | ||||
| { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Victor Stinner
						Victor Stinner