mirror of
				https://github.com/python/cpython.git
				synced 2025-10-26 11:14:33 +00:00 
			
		
		
		
	Add _PyObject_FastCallKeywords()
Issue #27830: Add _PyObject_FastCallKeywords(): avoid the creation of a temporary dictionary for keyword arguments. Other changes: * Cleanup call_function() and fast_function() (ex: rename nk to nkwargs) * Remove now useless do_call(), replaced with _PyObject_FastCallKeywords()
This commit is contained in:
		
							parent
							
								
									84f6a8f725
								
							
						
					
					
						commit
						d873572095
					
				
					 4 changed files with 130 additions and 55 deletions
				
			
		|  | @ -271,8 +271,8 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ | ||||||
|         Py_ssize_t nargs); |         Py_ssize_t nargs); | ||||||
| 
 | 
 | ||||||
|      /* 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 parameters (nargs is the number of |         args is a C array for positional arguments (nargs is the number of | ||||||
|         positional paramater), kwargs is a dictionary for keyword parameters. |         positional arguments), kwargs is a dictionary for keyword arguments. | ||||||
| 
 | 
 | ||||||
|         If nargs is equal to zero, args can be NULL. kwargs can be NULL. |         If nargs is equal to zero, args can be NULL. kwargs can be NULL. | ||||||
|         nargs must be greater or equal to zero. |         nargs must be greater or equal to zero. | ||||||
|  | @ -283,6 +283,24 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ | ||||||
|                                                    PyObject **args, Py_ssize_t nargs, |                                                    PyObject **args, Py_ssize_t nargs, | ||||||
|                                                    PyObject *kwargs); |                                                    PyObject *kwargs); | ||||||
| 
 | 
 | ||||||
|  |      /* Call the callable object func with the "fast call" calling convention:
 | ||||||
|  |         args is a C array for positional arguments followed by values of | ||||||
|  |         keyword arguments. Keys of keyword arguments are stored as a tuple | ||||||
|  |         of strings in kwnames. nargs is the number of positional parameters at | ||||||
|  |         the beginning of stack. The size of kwnames gives the number of keyword | ||||||
|  |         values in the stack after positional arguments. | ||||||
|  | 
 | ||||||
|  |         If nargs is equal to zero and there is no keyword argument (kwnames is | ||||||
|  |         NULL or its size is zero), args can be NULL. | ||||||
|  | 
 | ||||||
|  |         Return the result on success. Raise an exception and return NULL on | ||||||
|  |         error. */ | ||||||
|  |      PyAPI_FUNC(PyObject *) _PyObject_FastCallKeywords | ||||||
|  |         (PyObject *func, | ||||||
|  |          PyObject **args, | ||||||
|  |          Py_ssize_t nargs, | ||||||
|  |          PyObject *kwnames); | ||||||
|  | 
 | ||||||
| #define _PyObject_FastCall(func, args, nargs) \ | #define _PyObject_FastCall(func, args, nargs) \ | ||||||
|     _PyObject_FastCallDict((func), (args), (nargs), NULL) |     _PyObject_FastCallDict((func), (args), (nargs), NULL) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -64,6 +64,12 @@ PyAPI_FUNC(PyObject *) _PyFunction_FastCallDict( | ||||||
|     PyObject **args, |     PyObject **args, | ||||||
|     Py_ssize_t nargs, |     Py_ssize_t nargs, | ||||||
|     PyObject *kwargs); |     PyObject *kwargs); | ||||||
|  | 
 | ||||||
|  | PyAPI_FUNC(PyObject *) _PyFunction_FastCallKeywords( | ||||||
|  |     PyObject *func, | ||||||
|  |     PyObject **stack, | ||||||
|  |     Py_ssize_t nargs, | ||||||
|  |     PyObject *kwnames); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| /* Macros for direct access to these values. Type checks are *not*
 | /* Macros for direct access to these values. Type checks are *not*
 | ||||||
|  |  | ||||||
|  | @ -2366,6 +2366,74 @@ _PyObject_Call_Prepend(PyObject *func, | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static PyObject * | ||||||
|  | _PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, | ||||||
|  |                 PyObject *func) | ||||||
|  | { | ||||||
|  |     PyObject *kwdict; | ||||||
|  |     Py_ssize_t i; | ||||||
|  | 
 | ||||||
|  |     kwdict = PyDict_New(); | ||||||
|  |     if (kwdict == NULL) { | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for (i=0; i < nkwargs; i++) { | ||||||
|  |         int err; | ||||||
|  |         PyObject *key = PyTuple_GET_ITEM(kwnames, i); | ||||||
|  |         PyObject *value = *values++; | ||||||
|  | 
 | ||||||
|  |         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(kwdict); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         err = PyDict_SetItem(kwdict, key, value); | ||||||
|  |         if (err) { | ||||||
|  |             Py_DECREF(kwdict); | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return kwdict; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PyObject * | ||||||
|  | _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, | ||||||
|  |                            PyObject *kwnames) | ||||||
|  | { | ||||||
|  |     PyObject *kwdict, *result; | ||||||
|  |     Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); | ||||||
|  | 
 | ||||||
|  |     assert(nargs >= 0); | ||||||
|  |     assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); | ||||||
|  |     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 (nkwargs > 0) { | ||||||
|  |         kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func); | ||||||
|  |         if (kwdict == NULL) { | ||||||
|  |             return NULL; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |         kwdict = NULL; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     result = _PyObject_FastCallDict(func, stack, nargs, kwdict); | ||||||
|  |     Py_XDECREF(kwdict); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static PyObject* | static PyObject* | ||||||
| call_function_tail(PyObject *callable, PyObject *args) | call_function_tail(PyObject *callable, PyObject *args) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -113,8 +113,7 @@ static PyObject * call_function(PyObject ***, Py_ssize_t, PyObject *, uint64*, u | ||||||
| #else | #else | ||||||
| static PyObject * call_function(PyObject ***, Py_ssize_t, PyObject *); | 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(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 * create_keyword_args(PyObject *, PyObject ***, PyObject *); | ||||||
| static PyObject * load_args(PyObject ***, Py_ssize_t); | static PyObject * load_args(PyObject ***, Py_ssize_t); | ||||||
|  | @ -4940,7 +4939,7 @@ if (tstate->use_tracing && tstate->c_profilefunc) { \ | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| static PyObject * | static PyObject * | ||||||
| call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names | call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames | ||||||
| #ifdef WITH_TSC | #ifdef WITH_TSC | ||||||
|                 , uint64* pintr0, uint64* pintr1 |                 , uint64* pintr0, uint64* pintr1 | ||||||
| #endif | #endif | ||||||
|  | @ -4949,8 +4948,8 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names | ||||||
|     PyObject **pfunc = (*pp_stack) - oparg - 1; |     PyObject **pfunc = (*pp_stack) - oparg - 1; | ||||||
|     PyObject *func = *pfunc; |     PyObject *func = *pfunc; | ||||||
|     PyObject *x, *w; |     PyObject *x, *w; | ||||||
|     Py_ssize_t nk = names == NULL ? 0 : PyTuple_GET_SIZE(names); |     Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); | ||||||
|     Py_ssize_t nargs = oparg - nk; |     Py_ssize_t nargs = oparg - nkwargs; | ||||||
| 
 | 
 | ||||||
|     /* 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. | ||||||
|  | @ -4960,7 +4959,7 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names | ||||||
|         PyThreadState *tstate = PyThreadState_GET(); |         PyThreadState *tstate = PyThreadState_GET(); | ||||||
| 
 | 
 | ||||||
|         PCALL(PCALL_CFUNCTION); |         PCALL(PCALL_CFUNCTION); | ||||||
|         if (names == NULL && flags & (METH_NOARGS | METH_O)) { |         if (kwnames == NULL && flags & (METH_NOARGS | METH_O)) { | ||||||
|             PyCFunction meth = PyCFunction_GET_FUNCTION(func); |             PyCFunction meth = PyCFunction_GET_FUNCTION(func); | ||||||
|             PyObject *self = PyCFunction_GET_SELF(func); |             PyObject *self = PyCFunction_GET_SELF(func); | ||||||
|             if (flags & METH_NOARGS && nargs == 0) { |             if (flags & METH_NOARGS && nargs == 0) { | ||||||
|  | @ -4982,8 +4981,8 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|             PyObject *callargs, *kwdict = NULL; |             PyObject *callargs, *kwdict = NULL; | ||||||
|             if (names != NULL) { |             if (kwnames != NULL) { | ||||||
|                 kwdict = create_keyword_args(names, pp_stack, func); |                 kwdict = create_keyword_args(kwnames, pp_stack, func); | ||||||
|                 if (kwdict == NULL) { |                 if (kwdict == NULL) { | ||||||
|                     x = NULL; |                     x = NULL; | ||||||
|                     goto cfuncerror; |                     goto cfuncerror; | ||||||
|  | @ -5003,6 +5002,9 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|  |       Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); | ||||||
|  |       PyObject **stack; | ||||||
|  | 
 | ||||||
|       if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { |       if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { | ||||||
|           /* optimize access to bound methods */ |           /* optimize access to bound methods */ | ||||||
|           PyObject *self = PyMethod_GET_SELF(func); |           PyObject *self = PyMethod_GET_SELF(func); | ||||||
|  | @ -5018,11 +5020,14 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names | ||||||
|           Py_INCREF(func); |           Py_INCREF(func); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|  |       stack = (*pp_stack) - nargs - nkwargs; | ||||||
|  | 
 | ||||||
|       READ_TIMESTAMP(*pintr0); |       READ_TIMESTAMP(*pintr0); | ||||||
|       if (PyFunction_Check(func)) { |       if (PyFunction_Check(func)) { | ||||||
|           x = fast_function(func, pp_stack, nargs, names); |           x = fast_function(func, stack, nargs, kwnames); | ||||||
|       } else { |       } | ||||||
|           x = do_call(func, pp_stack, nargs, names); |       else { | ||||||
|  |           x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames); | ||||||
|       } |       } | ||||||
|       READ_TIMESTAMP(*pintr1); |       READ_TIMESTAMP(*pintr1); | ||||||
| 
 | 
 | ||||||
|  | @ -5055,7 +5060,7 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *names | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| static PyObject* | static PyObject* | ||||||
| _PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t nargs, | _PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs, | ||||||
|                      PyObject *globals) |                      PyObject *globals) | ||||||
| { | { | ||||||
|     PyFrameObject *f; |     PyFrameObject *f; | ||||||
|  | @ -5091,19 +5096,19 @@ _PyFunction_FastCallNoKw(PyCodeObject *co, PyObject **args, Py_ssize_t nargs, | ||||||
|     return result; |     return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Similar to _PyFunction_FastCall() but keywords are passed a (key, value)
 |  | ||||||
|    pairs in stack */ |  | ||||||
| static PyObject * | static PyObject * | ||||||
| fast_function(PyObject *func, PyObject ***pp_stack, Py_ssize_t nargs, PyObject *names) | fast_function(PyObject *func, PyObject **stack, | ||||||
|  |               Py_ssize_t nargs, PyObject *kwnames) | ||||||
| { | { | ||||||
|     PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); |     PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); | ||||||
|     PyObject *globals = PyFunction_GET_GLOBALS(func); |     PyObject *globals = PyFunction_GET_GLOBALS(func); | ||||||
|     PyObject *argdefs = PyFunction_GET_DEFAULTS(func); |     PyObject *argdefs = PyFunction_GET_DEFAULTS(func); | ||||||
|     PyObject *kwdefs, *closure, *name, *qualname; |     PyObject *kwdefs, *closure, *name, *qualname; | ||||||
|     PyObject **d; |     PyObject **d; | ||||||
|     Py_ssize_t nkwargs = names == NULL ? 0 : PyTuple_GET_SIZE(names); |     Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); | ||||||
|     Py_ssize_t nd; |     Py_ssize_t nd; | ||||||
|     PyObject **stack = (*pp_stack)-nargs-nkwargs; | 
 | ||||||
|  |     assert((nargs == 0 && nkwargs == 0) || stack != NULL); | ||||||
| 
 | 
 | ||||||
|     PCALL(PCALL_FUNCTION); |     PCALL(PCALL_FUNCTION); | ||||||
|     PCALL(PCALL_FAST_FUNCTION); |     PCALL(PCALL_FAST_FUNCTION); | ||||||
|  | @ -5112,15 +5117,14 @@ fast_function(PyObject *func, PyObject ***pp_stack, Py_ssize_t nargs, PyObject * | ||||||
|         co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) |         co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) | ||||||
|     { |     { | ||||||
|         if (argdefs == NULL && co->co_argcount == nargs) { |         if (argdefs == NULL && co->co_argcount == nargs) { | ||||||
|             return _PyFunction_FastCallNoKw(co, stack, nargs, globals); |             return _PyFunction_FastCall(co, stack, nargs, globals); | ||||||
|         } |         } | ||||||
|         else if (nargs == 0 && argdefs != NULL |         else if (nargs == 0 && argdefs != NULL | ||||||
|                  && co->co_argcount == Py_SIZE(argdefs)) { |                  && co->co_argcount == Py_SIZE(argdefs)) { | ||||||
|             /* function called with no arguments, but all parameters have
 |             /* function called with no arguments, but all parameters have
 | ||||||
|                a default value: use default values as arguments .*/ |                a default value: use default values as arguments .*/ | ||||||
|             stack = &PyTuple_GET_ITEM(argdefs, 0); |             stack = &PyTuple_GET_ITEM(argdefs, 0); | ||||||
|             return _PyFunction_FastCallNoKw(co, stack, Py_SIZE(argdefs), |             return _PyFunction_FastCall(co, stack, Py_SIZE(argdefs), globals); | ||||||
|                                             globals); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -5140,11 +5144,18 @@ fast_function(PyObject *func, PyObject ***pp_stack, Py_ssize_t nargs, PyObject * | ||||||
|     return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL, |     return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL, | ||||||
|                                     stack, nargs, |                                     stack, nargs, | ||||||
|                                     NULL, 0, |                                     NULL, 0, | ||||||
|                                     names, stack + nargs, |                                     kwnames, stack + nargs, | ||||||
|                                     d, (int)nd, kwdefs, |                                     d, (int)nd, kwdefs, | ||||||
|                                     closure, name, qualname); |                                     closure, name, qualname); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | PyObject * | ||||||
|  | _PyFunction_FastCallKeywords(PyObject *func, PyObject **stack, | ||||||
|  |                              Py_ssize_t nargs, PyObject *kwnames) | ||||||
|  | { | ||||||
|  |     return fast_function(func, stack, nargs, kwnames); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| PyObject * | PyObject * | ||||||
| _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, | _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, | ||||||
|                          PyObject *kwargs) |                          PyObject *kwargs) | ||||||
|  | @ -5172,15 +5183,14 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, | ||||||
|     { |     { | ||||||
|         /* Fast paths */ |         /* Fast paths */ | ||||||
|         if (argdefs == NULL && co->co_argcount == nargs) { |         if (argdefs == NULL && co->co_argcount == nargs) { | ||||||
|             return _PyFunction_FastCallNoKw(co, args, nargs, globals); |             return _PyFunction_FastCall(co, args, nargs, globals); | ||||||
|         } |         } | ||||||
|         else if (nargs == 0 && argdefs != NULL |         else if (nargs == 0 && argdefs != NULL | ||||||
|                  && co->co_argcount == Py_SIZE(argdefs)) { |                  && co->co_argcount == Py_SIZE(argdefs)) { | ||||||
|             /* function called with no arguments, but all parameters have
 |             /* function called with no arguments, but all parameters have
 | ||||||
|                a default value: use default values as arguments .*/ |                a default value: use default values as arguments .*/ | ||||||
|             args = &PyTuple_GET_ITEM(argdefs, 0); |             args = &PyTuple_GET_ITEM(argdefs, 0); | ||||||
|             return _PyFunction_FastCallNoKw(co, args, Py_SIZE(argdefs), |             return _PyFunction_FastCall(co, args, Py_SIZE(argdefs), globals); | ||||||
|                                             globals); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -5242,8 +5252,8 @@ create_keyword_args(PyObject *names, PyObject ***pp_stack, | ||||||
|         return NULL; |         return NULL; | ||||||
|     while (--nk >= 0) { |     while (--nk >= 0) { | ||||||
|         int err; |         int err; | ||||||
|         PyObject *value = EXT_POP(*pp_stack); |  | ||||||
|         PyObject *key = PyTuple_GET_ITEM(names, nk); |         PyObject *key = PyTuple_GET_ITEM(names, nk); | ||||||
|  |         PyObject *value = EXT_POP(*pp_stack); | ||||||
|         if (PyDict_GetItem(kwdict, key) != NULL) { |         if (PyDict_GetItem(kwdict, key) != NULL) { | ||||||
|             PyErr_Format(PyExc_TypeError, |             PyErr_Format(PyExc_TypeError, | ||||||
|                          "%.200s%s got multiple values " |                          "%.200s%s got multiple values " | ||||||
|  | @ -5281,33 +5291,6 @@ load_args(PyObject ***pp_stack, Py_ssize_t nargs) | ||||||
|     return args; |     return args; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static PyObject * |  | ||||||
| do_call(PyObject *func, PyObject ***pp_stack, Py_ssize_t nargs, PyObject *kwnames) |  | ||||||
| { |  | ||||||
|     PyObject *callargs, *kwdict, *result; |  | ||||||
| 
 |  | ||||||
|     if (kwnames != NULL) { |  | ||||||
|         kwdict = create_keyword_args(kwnames, pp_stack, func); |  | ||||||
|         if (kwdict == NULL) { |  | ||||||
|             return NULL; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|         kwdict = NULL; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     callargs = load_args(pp_stack, nargs); |  | ||||||
|     if (callargs == NULL) { |  | ||||||
|         Py_XDECREF(kwdict); |  | ||||||
|         return NULL; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     result = do_call_core(func, callargs, kwdict); |  | ||||||
|     Py_XDECREF(callargs); |  | ||||||
|     Py_XDECREF(kwdict); |  | ||||||
|     return result; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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