diff -r e06af4027546 Include/abstract.h --- a/Include/abstract.h Mon Feb 06 07:15:57 2017 -0800 +++ b/Include/abstract.h Tue Feb 07 15:42:16 2017 +0100 @@ -209,6 +209,11 @@ PyAPI_FUNC(int) _PyStack_UnpackDict( 40 bytes on the stack. */ #define _PY_FASTCALL_SMALL_STACK 5 +PyAPI_FUNC(PyObject *) _PyObject_FastCall( + PyObject *callable, + PyObject **stack, + Py_ssize_t nargs); + /* Call the callable object 'callable' 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. @@ -245,11 +250,8 @@ PyAPI_FUNC(PyObject *) _PyObject_FastCal Py_ssize_t nargs, PyObject *kwnames); -#define _PyObject_FastCall(func, args, nargs) \ - _PyObject_FastCallDict((func), (args), (nargs), NULL) - #define _PyObject_CallNoArg(func) \ - _PyObject_FastCallDict((func), NULL, 0, NULL) + _PyObject_FastCall((func), NULL, 0) PyAPI_FUNC(PyObject *) _PyObject_Call_Prepend( PyObject *callable, diff -r e06af4027546 Include/ceval.h --- a/Include/ceval.h Mon Feb 06 07:15:57 2017 -0800 +++ b/Include/ceval.h Tue Feb 07 15:42:16 2017 +0100 @@ -13,8 +13,7 @@ PyAPI_FUNC(PyObject *) PyEval_CallObject PyObject *kwargs); /* Inline this */ -#define PyEval_CallObject(callable, arg) \ - PyEval_CallObjectWithKeywords(callable, arg, (PyObject *)NULL) +#define PyEval_CallObject(callable, args) PyObject_CallObject(callable, args) PyAPI_FUNC(PyObject *) PyEval_CallFunction(PyObject *callable, const char *format, ...); diff -r e06af4027546 Include/eval.h --- a/Include/eval.h Mon Feb 06 07:15:57 2017 -0800 +++ b/Include/eval.h Tue Feb 07 15:42:16 2017 +0100 @@ -9,15 +9,25 @@ extern "C" { PyAPI_FUNC(PyObject *) PyEval_EvalCode(PyObject *, PyObject *, PyObject *); -PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyObject *co, - PyObject *globals, - PyObject *locals, - PyObject **args, int argc, - PyObject **kwds, int kwdc, - PyObject **defs, int defc, - PyObject *kwdefs, PyObject *closure); +PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx( + PyObject *co, + PyObject *globals, + PyObject *locals, + PyObject **args, int argc, + PyObject **kwds, int kwdc, + PyObject **defs, int defc, + PyObject *kwdefs, PyObject *closure); #ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyEval_EvalCodeWithName( + PyObject *_co, PyObject *globals, PyObject *locals, + PyObject **args, Py_ssize_t argcount, + PyObject **kwnames, PyObject **kwargs, + Py_ssize_t kwcount, int kwstep, + PyObject **defs, Py_ssize_t defcount, + PyObject *kwdefs, PyObject *closure, + PyObject *name, PyObject *qualname); + PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args); #endif diff -r e06af4027546 Include/funcobject.h --- a/Include/funcobject.h Mon Feb 06 07:15:57 2017 -0800 +++ b/Include/funcobject.h Tue Feb 07 15:42:16 2017 +0100 @@ -59,6 +59,11 @@ PyAPI_FUNC(PyObject *) PyFunction_GetAnn PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *); #ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject*) _PyFunction_FastCall( + PyObject *func, + PyObject **args, + Py_ssize_t nargs); + PyAPI_FUNC(PyObject *) _PyFunction_FastCallDict( PyObject *func, PyObject **args, diff -r e06af4027546 Include/methodobject.h --- a/Include/methodobject.h Mon Feb 06 07:15:57 2017 -0800 +++ b/Include/methodobject.h Tue Feb 07 15:42:16 2017 +0100 @@ -40,6 +40,11 @@ PyAPI_FUNC(int) PyCFunction_GetFlags(PyO PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *); #ifndef Py_LIMITED_API +PyAPI_FUNC(PyObject *) _PyCFunction_FastCall( + PyObject *func, + PyObject **args, + Py_ssize_t nargs); + PyAPI_FUNC(PyObject *) _PyCFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, diff -r e06af4027546 Makefile.pre.in --- a/Makefile.pre.in Mon Feb 06 07:15:57 2017 -0800 +++ b/Makefile.pre.in Tue Feb 07 15:42:16 2017 +0100 @@ -409,6 +409,7 @@ OBJECT_OBJS= \ Objects/bytes_methods.o \ Objects/bytearrayobject.o \ Objects/bytesobject.o \ + Objects/call.o \ Objects/cellobject.o \ Objects/classobject.o \ Objects/codeobject.o \ diff -r e06af4027546 Objects/abstract.c --- a/Objects/abstract.c Mon Feb 06 07:15:57 2017 -0800 +++ b/Objects/abstract.c Tue Feb 07 15:42:16 2017 +0100 @@ -12,7 +12,7 @@ static PyObject * type_error(const char *msg, PyObject *obj) { - PyErr_Format(PyExc_TypeError, msg, obj->ob_type->tp_name); + PyErr_Format(PyExc_TypeError, msg, Py_TYPE(obj)->tp_name); return NULL; } @@ -2168,685 +2168,6 @@ PyMapping_Values(PyObject *o) return fast; } -/* Operations on callable objects */ - -/* XXX PyCallable_Check() is in object.c */ - -PyObject * -PyObject_CallObject(PyObject *callable, PyObject *args) -{ - return PyEval_CallObjectWithKeywords(callable, args, NULL); -} - -PyObject* -_Py_CheckFunctionResult(PyObject *callable, PyObject *result, const char *where) -{ - int err_occurred = (PyErr_Occurred() != NULL); - - assert((callable != NULL) ^ (where != NULL)); - - if (result == NULL) { - if (!err_occurred) { - if (callable) - PyErr_Format(PyExc_SystemError, - "%R returned NULL without setting an error", - callable); - else - PyErr_Format(PyExc_SystemError, - "%s returned NULL without setting an error", - where); -#ifdef Py_DEBUG - /* Ensure that the bug is caught in debug mode */ - Py_FatalError("a function returned NULL without setting an error"); -#endif - return NULL; - } - } - else { - if (err_occurred) { - Py_DECREF(result); - - if (callable) { - _PyErr_FormatFromCause(PyExc_SystemError, - "%R returned a result with an error set", - callable); - } - else { - _PyErr_FormatFromCause(PyExc_SystemError, - "%s returned a result with an error set", - where); - } -#ifdef Py_DEBUG - /* Ensure that the bug is caught in debug mode */ - Py_FatalError("a function returned a result with an error set"); -#endif - return NULL; - } - } - return result; -} - -PyObject * -PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) -{ - ternaryfunc call; - PyObject *result; - - /* PyObject_Call() must not be called with an exception set, - because it can clear it (directly or indirectly) and so the - caller loses its exception */ - assert(!PyErr_Occurred()); - assert(PyTuple_Check(args)); - assert(kwargs == NULL || PyDict_Check(kwargs)); - - call = callable->ob_type->tp_call; - if (call == NULL) { - PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - callable->ob_type->tp_name); - return NULL; - } - - if (Py_EnterRecursiveCall(" while calling a Python object")) - return NULL; - - result = (*call)(callable, args, kwargs); - - Py_LeaveRecursiveCall(); - - return _Py_CheckFunctionResult(callable, result, NULL); -} - -/* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their - stack consumption, Disable inlining to optimize the stack consumption. */ -PyObject* _Py_NO_INLINE -_PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) -{ - PyObject *args; - Py_ssize_t i; - - args = PyTuple_New(nargs); - if (args == NULL) { - return NULL; - } - - for (i=0; i < nargs; i++) { - PyObject *item = stack[i]; - Py_INCREF(item); - PyTuple_SET_ITEM(args, i, item); - } - return args; -} - -PyObject* -_PyStack_AsTupleSlice(PyObject **stack, Py_ssize_t nargs, - Py_ssize_t start, Py_ssize_t end) -{ - PyObject *args; - Py_ssize_t i; - - assert(0 <= start); - assert(end <= nargs); - assert(start <= end); - - args = PyTuple_New(end - start); - if (args == NULL) { - return NULL; - } - - for (i=start; i < end; i++) { - PyObject *item = stack[i]; - Py_INCREF(item); - PyTuple_SET_ITEM(args, i - start, item); - } - return args; -} - -PyObject * -_PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs, - PyObject *kwargs) -{ - ternaryfunc call; - PyObject *result = NULL; - - /* _PyObject_FastCallDict() must not be called with an exception set, - because it can clear it (directly or indirectly) and so the - caller loses its exception */ - assert(!PyErr_Occurred()); - - assert(callable != NULL); - assert(nargs >= 0); - assert(nargs == 0 || args != NULL); - assert(kwargs == NULL || PyDict_Check(kwargs)); - - if (Py_EnterRecursiveCall(" while calling a Python object")) { - return NULL; - } - - if (PyFunction_Check(callable)) { - result = _PyFunction_FastCallDict(callable, args, nargs, kwargs); - } - else if (PyCFunction_Check(callable)) { - result = _PyCFunction_FastCallDict(callable, args, nargs, kwargs); - } - else { - PyObject *tuple; - - /* Slow-path: build a temporary tuple */ - call = callable->ob_type->tp_call; - if (call == NULL) { - PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - callable->ob_type->tp_name); - goto exit; - } - - tuple = _PyStack_AsTuple(args, nargs); - if (tuple == NULL) { - goto exit; - } - - result = (*call)(callable, tuple, kwargs); - Py_DECREF(tuple); - - result = _Py_CheckFunctionResult(callable, result, NULL); - } - -exit: - Py_LeaveRecursiveCall(); - - return result; -} - -/* Positional arguments are obj followed by args: - call callable(obj, *args, **kwargs) */ -PyObject * -_PyObject_Call_Prepend(PyObject *callable, - PyObject *obj, PyObject *args, PyObject *kwargs) -{ - PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; - PyObject **stack; - Py_ssize_t argcount; - PyObject *result; - - assert(PyTuple_Check(args)); - - argcount = PyTuple_GET_SIZE(args); - if (argcount + 1 <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { - stack = small_stack; - } - else { - stack = PyMem_Malloc((argcount + 1) * sizeof(PyObject *)); - if (stack == NULL) { - PyErr_NoMemory(); - return NULL; - } - } - - /* use borrowed references */ - stack[0] = obj; - memcpy(&stack[1], - &PyTuple_GET_ITEM(args, 0), - argcount * sizeof(PyObject *)); - - result = _PyObject_FastCallDict(callable, - stack, argcount + 1, - kwargs); - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; -} - -PyObject * -_PyStack_AsDict(PyObject **values, PyObject *kwnames) -{ - Py_ssize_t nkwargs; - PyObject *kwdict; - Py_ssize_t i; - - assert(kwnames != NULL); - nkwargs = PyTuple_GET_SIZE(kwnames); - kwdict = _PyDict_NewPresized(nkwargs); - if (kwdict == NULL) { - return NULL; - } - - for (i = 0; i < nkwargs; i++) { - PyObject *key = PyTuple_GET_ITEM(kwnames, i); - PyObject *value = *values++; - /* If key already exists, replace it with the new value */ - if (PyDict_SetItem(kwdict, key, value)) { - Py_DECREF(kwdict); - return NULL; - } - } - return kwdict; -} - -int -_PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, - PyObject ***p_stack, PyObject **p_kwnames) -{ - PyObject **stack, **kwstack; - Py_ssize_t nkwargs; - Py_ssize_t pos, i; - PyObject *key, *value; - PyObject *kwnames; - - assert(nargs >= 0); - assert(kwargs == NULL || PyDict_CheckExact(kwargs)); - - if (kwargs == NULL || (nkwargs = PyDict_GET_SIZE(kwargs)) == 0) { - *p_stack = args; - *p_kwnames = NULL; - return 0; - } - - if ((size_t)nargs > PY_SSIZE_T_MAX / sizeof(stack[0]) - (size_t)nkwargs) { - PyErr_NoMemory(); - return -1; - } - - stack = PyMem_Malloc((nargs + nkwargs) * sizeof(stack[0])); - if (stack == NULL) { - PyErr_NoMemory(); - return -1; - } - - kwnames = PyTuple_New(nkwargs); - if (kwnames == NULL) { - PyMem_Free(stack); - return -1; - } - - /* Copy position arguments (borrowed references) */ - memcpy(stack, args, nargs * sizeof(stack[0])); - - kwstack = stack + nargs; - pos = i = 0; - /* This loop doesn't support lookup function mutating the dictionary - to change its size. It's a deliberate choice for speed, this function is - called in the performance critical hot code. */ - while (PyDict_Next(kwargs, &pos, &key, &value)) { - Py_INCREF(key); - PyTuple_SET_ITEM(kwnames, i, key); - /* The stack contains borrowed references */ - kwstack[i] = value; - i++; - } - - *p_stack = stack; - *p_kwnames = kwnames; - return 0; -} - -PyObject * -_PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t nargs, - PyObject *kwnames) -{ - /* _PyObject_FastCallKeywords() must not be called with an exception set, - because it can clear it (directly or indirectly) and so the - caller loses its exception */ - assert(!PyErr_Occurred()); - - assert(nargs >= 0); - assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - - /* kwnames must only contains str strings, no subclass, and all keys must - be unique: these checks are implemented in Python/ceval.c and - _PyArg_ParseStackAndKeywords(). */ - - if (PyFunction_Check(callable)) { - return _PyFunction_FastCallKeywords(callable, stack, nargs, kwnames); - } - if (PyCFunction_Check(callable)) { - return _PyCFunction_FastCallKeywords(callable, stack, nargs, kwnames); - } - else { - /* Slow-path: build a temporary tuple for positional arguments and a - temporary dictionary for keyword arguments (if any) */ - - ternaryfunc call; - PyObject *argtuple; - PyObject *kwdict, *result; - Py_ssize_t nkwargs; - - result = NULL; - nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); - assert((nargs == 0 && nkwargs == 0) || stack != NULL); - - if (Py_EnterRecursiveCall(" while calling a Python object")) { - return NULL; - } - - call = callable->ob_type->tp_call; - if (call == NULL) { - PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - callable->ob_type->tp_name); - goto exit; - } - - argtuple = _PyStack_AsTuple(stack, nargs); - if (argtuple == NULL) { - goto exit; - } - - if (nkwargs > 0) { - kwdict = _PyStack_AsDict(stack + nargs, kwnames); - if (kwdict == NULL) { - Py_DECREF(argtuple); - goto exit; - } - } - else { - kwdict = NULL; - } - - result = (*call)(callable, argtuple, kwdict); - Py_DECREF(argtuple); - Py_XDECREF(kwdict); - - result = _Py_CheckFunctionResult(callable, result, NULL); - - exit: - Py_LeaveRecursiveCall(); - return result; - } -} - -static PyObject * -_PyObject_CallFunctionVa(PyObject *callable, const char *format, - va_list va, int is_size_t) -{ - PyObject* small_stack[_PY_FASTCALL_SMALL_STACK]; - const Py_ssize_t small_stack_len = Py_ARRAY_LENGTH(small_stack); - PyObject **stack; - Py_ssize_t nargs, i; - PyObject *result; - - if (callable == NULL) { - return null_error(); - } - - if (!format || !*format) { - return _PyObject_CallNoArg(callable); - } - - if (is_size_t) { - stack = _Py_VaBuildStack(small_stack, small_stack_len, format, va, &nargs); - } - else { - stack = _Py_VaBuildStack_SizeT(small_stack, small_stack_len, format, va, &nargs); - } - if (stack == NULL) { - return NULL; - } - - if (nargs == 1 && PyTuple_Check(stack[0])) { - /* Special cases for backward compatibility: - - PyObject_CallFunction(func, "O", tuple) calls func(*tuple) - - PyObject_CallFunction(func, "(OOO)", arg1, arg2, arg3) calls - func(*(arg1, arg2, arg3)): func(arg1, arg2, arg3) */ - PyObject *args = stack[0]; - result = _PyObject_FastCall(callable, - &PyTuple_GET_ITEM(args, 0), - PyTuple_GET_SIZE(args)); - } - else { - result = _PyObject_FastCall(callable, stack, nargs); - } - - for (i = 0; i < nargs; ++i) { - Py_DECREF(stack[i]); - } - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; -} - -PyObject * -PyObject_CallFunction(PyObject *callable, const char *format, ...) -{ - va_list va; - PyObject *result; - - va_start(va, format); - result = _PyObject_CallFunctionVa(callable, format, va, 0); - va_end(va); - - return result; -} - -PyObject * -_PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) -{ - va_list va; - PyObject *result; - - va_start(va, format); - result = _PyObject_CallFunctionVa(callable, format, va, 1); - va_end(va); - - return result; -} - -static PyObject* -callmethod(PyObject* callable, const char *format, va_list va, int is_size_t) -{ - assert(callable != NULL); - - if (!PyCallable_Check(callable)) { - type_error("attribute of type '%.200s' is not callable", callable); - return NULL; - } - - return _PyObject_CallFunctionVa(callable, format, va, is_size_t); -} - -PyObject * -PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) -{ - va_list va; - PyObject *callable, *retval; - - if (obj == NULL || name == NULL) { - return null_error(); - } - - callable = PyObject_GetAttrString(obj, name); - if (callable == NULL) - return NULL; - - va_start(va, format); - retval = callmethod(callable, format, va, 0); - va_end(va); - - Py_DECREF(callable); - return retval; -} - -PyObject * -_PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, - const char *format, ...) -{ - va_list va; - PyObject *callable, *retval; - - if (obj == NULL || name == NULL) { - return null_error(); - } - - callable = _PyObject_GetAttrId(obj, name); - if (callable == NULL) - return NULL; - - va_start(va, format); - retval = callmethod(callable, format, va, 0); - va_end(va); - - Py_DECREF(callable); - return retval; -} - -PyObject * -_PyObject_CallMethod_SizeT(PyObject *obj, const char *name, - const char *format, ...) -{ - va_list va; - PyObject *callable, *retval; - - if (obj == NULL || name == NULL) { - return null_error(); - } - - callable = PyObject_GetAttrString(obj, name); - if (callable == NULL) - return NULL; - - va_start(va, format); - retval = callmethod(callable, format, va, 1); - va_end(va); - - Py_DECREF(callable); - return retval; -} - -PyObject * -_PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, - const char *format, ...) -{ - va_list va; - PyObject *callable, *retval; - - if (obj == NULL || name == NULL) { - return null_error(); - } - - callable = _PyObject_GetAttrId(obj, name); - if (callable == NULL) { - return NULL; - } - - va_start(va, format); - retval = callmethod(callable, format, va, 1); - va_end(va); - - Py_DECREF(callable); - return retval; -} - -static PyObject * -object_vacall(PyObject *callable, va_list vargs) -{ - PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; - PyObject **stack; - Py_ssize_t nargs; - PyObject *result; - Py_ssize_t i; - va_list countva; - - if (callable == NULL) { - return null_error(); - } - - /* Count the number of arguments */ - va_copy(countva, vargs); - nargs = 0; - while (1) { - PyObject *arg = va_arg(countva, PyObject *); - if (arg == NULL) { - break; - } - nargs++; - } - va_end(countva); - - /* Copy arguments */ - if (nargs <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { - stack = small_stack; - } - else { - stack = PyMem_Malloc(nargs * sizeof(stack[0])); - if (stack == NULL) { - PyErr_NoMemory(); - return NULL; - } - } - - for (i = 0; i < nargs; ++i) { - stack[i] = va_arg(vargs, PyObject *); - } - - /* Call the function */ - result = _PyObject_FastCall(callable, stack, nargs); - - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; -} - -PyObject * -PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) -{ - va_list vargs; - PyObject *result; - - if (callable == NULL || name == NULL) { - return null_error(); - } - - callable = PyObject_GetAttr(callable, name); - if (callable == NULL) { - return NULL; - } - - va_start(vargs, name); - result = object_vacall(callable, vargs); - va_end(vargs); - - Py_DECREF(callable); - return result; -} - -PyObject * -_PyObject_CallMethodIdObjArgs(PyObject *obj, - struct _Py_Identifier *name, ...) -{ - va_list vargs; - PyObject *callable, *result; - - if (obj == NULL || name == NULL) { - return null_error(); - } - - callable = _PyObject_GetAttrId(obj, name); - if (callable == NULL) { - return NULL; - } - - va_start(vargs, name); - result = object_vacall(callable, vargs); - va_end(vargs); - - Py_DECREF(callable); - return result; -} - -PyObject * -PyObject_CallFunctionObjArgs(PyObject *callable, ...) -{ - va_list vargs; - PyObject *result; - - va_start(vargs, callable); - result = object_vacall(callable, vargs); - va_end(vargs); - - return result; -} - - /* isinstance(), issubclass() */ /* abstract_get_bases() has logically 4 return states: diff -r e06af4027546 Objects/call.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Objects/call.c Tue Feb 07 15:42:16 2017 +0100 @@ -0,0 +1,1570 @@ +#include "Python.h" +#include "frameobject.h" + +static PyObject * +null_error(void) +{ + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_SystemError, + "null argument to internal routine"); + return NULL; +} + +/* PyObject */ + +PyObject* +_Py_CheckFunctionResult(PyObject *callable, PyObject *result, const char *where) +{ + int err_occurred = (PyErr_Occurred() != NULL); + + assert((callable != NULL) ^ (where != NULL)); + + if (result == NULL) { + if (!err_occurred) { + if (callable) + PyErr_Format(PyExc_SystemError, + "%R returned NULL without setting an error", + callable); + else + PyErr_Format(PyExc_SystemError, + "%s returned NULL without setting an error", + where); +#ifdef Py_DEBUG + /* Ensure that the bug is caught in debug mode */ + Py_FatalError("a function returned NULL without setting an error"); +#endif + return NULL; + } + } + else { + if (err_occurred) { + Py_DECREF(result); + + if (callable) { + _PyErr_FormatFromCause(PyExc_SystemError, + "%R returned a result with an error set", + callable); + } + else { + _PyErr_FormatFromCause(PyExc_SystemError, + "%s returned a result with an error set", + where); + } +#ifdef Py_DEBUG + /* Ensure that the bug is caught in debug mode */ + Py_FatalError("a function returned a result with an error set"); +#endif + return NULL; + } + } + return result; +} + + +/* Disable inlining to reduce the stack consumption */ +PyObject* +_PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) +{ + PyObject *args; + Py_ssize_t i; + + args = PyTuple_New(nargs); + if (args == NULL) { + return NULL; + } + + for (i=0; i < nargs; i++) { + PyObject *item = stack[i]; + Py_INCREF(item); + PyTuple_SET_ITEM(args, i, item); + } + return args; +} + + +/* Disable inlining to reduce the stack consumption */ +static PyObject* _Py_NO_INLINE +object_fastcall_slow(PyObject *callable, PyObject **stack, Py_ssize_t nargs) +{ + /* Slow-path: build a temporary tuple for positional arguments */ + + ternaryfunc call; + PyObject *argtuple; + PyObject *result; + + result = NULL; + assert(nargs == 0 || stack != NULL); + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + call = callable->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + callable->ob_type->tp_name); + goto exit; + } + + argtuple = _PyStack_AsTuple(stack, nargs); + if (argtuple == NULL) { + goto exit; + } + + result = (*call)(callable, argtuple, NULL); + Py_DECREF(argtuple); + + result = _Py_CheckFunctionResult(callable, result, NULL); + +exit: + Py_LeaveRecursiveCall(); + return result; +} + + +/* This function is inlined manually in _PyObject_FastCallDict() and + _PyObject_FastCallKeywords() to reduce the stack consumption and for best + performances, since these functions are performance critical. */ +PyObject * +_PyObject_FastCall(PyObject *callable, PyObject **args, Py_ssize_t nargs) +{ + /* _PyObject_FastCall() must not be called with an exception set, + because it can clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + + if (PyFunction_Check(callable)) { + return _PyFunction_FastCall(callable, args, nargs); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCall(callable, args, nargs); + } + else { + return object_fastcall_slow(callable, args, nargs); + } +} + + +/* Disable inlining to reduce the stack consumption */ +static PyObject * _Py_NO_INLINE +object_fastcalldict_slow(PyObject *callable, PyObject **args, Py_ssize_t nargs, + PyObject *kwargs) +{ + ternaryfunc call; + PyObject *tuple; + PyObject *result; + + /* Slow-path: build a temporary tuple */ + call = callable->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + callable->ob_type->tp_name); + return NULL; + } + + tuple = _PyStack_AsTuple(args, nargs); + if (tuple == NULL) { + return NULL; + } + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + Py_DECREF(tuple); + return NULL; + } + + result = (*call)(callable, tuple, kwargs); + Py_DECREF(tuple); + + Py_LeaveRecursiveCall(); + + result = _Py_CheckFunctionResult(callable, result, NULL); + + return result; +} + + +PyObject * +_PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs, + PyObject *kwargs) +{ + /* _PyObject_FastCallDict() must not be called with an exception set, + because it can clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + + assert(callable != NULL); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + assert(kwargs == NULL || PyDict_Check(kwargs)); + + if (kwargs == NULL || PyDict_GET_SIZE(kwargs) == 0) { + if (PyFunction_Check(callable)) { + return _PyFunction_FastCall(callable, args, nargs); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCall(callable, args, nargs); + } + else { + return object_fastcall_slow(callable, args, nargs); + } + } + else { + if (PyFunction_Check(callable)) { + return _PyFunction_FastCallDict(callable, args, nargs, kwargs); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCallDict(callable, args, nargs, kwargs); + } + else { + return object_fastcalldict_slow(callable, args, nargs, kwargs); + } + } +} + + +/* Disable inlining to reduce the stack consumption */ +static PyObject * _Py_NO_INLINE +object_call_slow(PyObject *callable, PyObject *args, PyObject *kwargs) +{ + /* Slow-path: build a temporary tuple for positional arguments */ + + ternaryfunc call; + PyObject *result; + + result = NULL; + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + call = callable->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + callable->ob_type->tp_name); + goto exit; + } + + result = (*call)(callable, args, kwargs); + + result = _Py_CheckFunctionResult(callable, result, NULL); + +exit: + Py_LeaveRecursiveCall(); + return result; +} + + +PyObject * +PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) +{ + PyObject **stack; + Py_ssize_t nargs; + + /* PyObject_Call() must not be called with an exception set, + because it can clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + + assert(args != NULL); + assert(PyTuple_Check(args)); + assert(kwargs == NULL || PyDict_Check(kwargs)); + + stack = &PyTuple_GET_ITEM(args, 0); + nargs = PyTuple_GET_SIZE(args); + + if (kwargs == NULL || PyDict_GET_SIZE(kwargs) == 0) { + if (PyFunction_Check(callable)) { + return _PyFunction_FastCall(callable, stack, nargs); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCall(callable, stack, nargs); + } + else { + return object_call_slow(callable, args, NULL); + } + } + else { + if (PyFunction_Check(callable)) { + return _PyFunction_FastCallDict(callable, stack, nargs, kwargs); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCallDict(callable, stack, nargs, kwargs); + } + else { + return object_call_slow(callable, args, kwargs); + } + } +} + + +PyObject * +_PyStack_AsDict(PyObject **values, PyObject *kwnames) +{ + Py_ssize_t nkwargs; + PyObject *kwdict; + Py_ssize_t i; + + assert(kwnames != NULL); + nkwargs = PyTuple_GET_SIZE(kwnames); + kwdict = _PyDict_NewPresized(nkwargs); + if (kwdict == NULL) { + return NULL; + } + + for (i = 0; i < nkwargs; i++) { + PyObject *key = PyTuple_GET_ITEM(kwnames, i); + PyObject *value = *values++; + /* If key already exists, replace it with the new value */ + if (PyDict_SetItem(kwdict, key, value)) { + Py_DECREF(kwdict); + return NULL; + } + } + return kwdict; +} + + +/* Disable inlining to reduce the stack consumption */ +static PyObject * _Py_NO_INLINE +object_fastcallkw_slow(PyObject *callable, PyObject **stack, Py_ssize_t nargs, + PyObject *kwnames) +{ + /* Slow-path: build a temporary tuple for positional arguments and a + temporary dictionary for keyword arguments (if any) */ + + ternaryfunc call; + PyObject *argtuple; + PyObject *kwdict, *result; + Py_ssize_t nkwargs; + + result = NULL; + nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + assert((nargs == 0 && nkwargs == 0) || stack != NULL); + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + call = callable->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + callable->ob_type->tp_name); + goto exit; + } + + argtuple = _PyStack_AsTuple(stack, nargs); + if (argtuple == NULL) { + goto exit; + } + + if (nkwargs > 0) { + kwdict = _PyStack_AsDict(stack + nargs, kwnames); + if (kwdict == NULL) { + Py_DECREF(argtuple); + goto exit; + } + } + else { + kwdict = NULL; + } + + result = (*call)(callable, argtuple, kwdict); + Py_DECREF(argtuple); + Py_XDECREF(kwdict); + + result = _Py_CheckFunctionResult(callable, result, NULL); + +exit: + Py_LeaveRecursiveCall(); + return result; +} + + +PyObject * +_PyObject_FastCallKeywords(PyObject *callable, PyObject **args, Py_ssize_t nargs, + PyObject *kwnames) +{ + /* _PyObject_FastCallKeywords() must not be called with an exception set, + because it can clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + + assert(nargs >= 0); + assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); + + if (kwnames == NULL || PyTuple_GET_SIZE(kwnames) == 0) { + if (PyFunction_Check(callable)) { + return _PyFunction_FastCall(callable, args, nargs); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCall(callable, args, nargs); + } + else if (Py_TYPE(callable) == &PyMethodDescr_Type) { + return _PyMethodDescr_FastCallKeywords(callable, args, nargs, NULL); + } + else { + return object_fastcall_slow(callable, args, nargs); + } + } + else { + /* kwnames must only contains str strings, no subclass, and all keys + must be unique: these checks are implemented in Python/ceval.c and + _PyArg_ParseStackAndKeywords(). */ + + if (PyFunction_Check(callable)) { + return _PyFunction_FastCallKeywords(callable, args, nargs, kwnames); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCallKeywords(callable, args, nargs, kwnames); + } + else if (Py_TYPE(callable) == &PyMethodDescr_Type) { + return _PyMethodDescr_FastCallKeywords(callable, args, nargs, kwnames); + } + else { + return object_fastcallkw_slow(callable, args, nargs, kwnames); + } + } +} + + +/* PyCFunction */ + +PyObject * +_PyCFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs) +{ + /* _PyMethodDef_RawFastCallKeywords() must not be called with an exception set, + because it can clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + + assert(func != NULL); + assert(PyCFunction_Check(func)); + + assert(nargs >= 0); + + PyMethodDef *method = ((PyCFunctionObject*)func)->m_ml; + PyCFunction meth = method->ml_meth; + PyObject *self = PyCFunction_GET_SELF(func); + int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + PyObject *result; + + switch (flags) + { + case METH_NOARGS: + if (nargs != 0) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + method->ml_name, nargs); + return NULL; + } + + result = (*meth) (self, NULL); + break; + + case METH_O: + if (nargs != 1) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%zd given)", + method->ml_name, nargs); + return NULL; + } + + result = (*meth) (self, args[0]); + break; + + case METH_FASTCALL: + result = ((_PyCFunctionFast)meth) (self, args, nargs, NULL); + break; + + case METH_VARARGS: + case METH_VARARGS | METH_KEYWORDS: + { + /* Slow-path: create a temporary tuple for positional arguments */ + PyObject *argtuple = _PyStack_AsTuple(args, nargs); + if (argtuple == NULL) { + return NULL; + } + + if (flags & METH_KEYWORDS) { + result = (*(PyCFunctionWithKeywords)meth) (self, argtuple, NULL); + } + else { + result = (*meth) (self, argtuple); + } + Py_DECREF(argtuple); + break; + } + + default: + PyErr_SetString(PyExc_SystemError, + "Bad call flags in _PyCFunction_FastCallKeywords. " + "METH_OLDARGS is no longer supported!"); + return NULL; + } + + result = _Py_CheckFunctionResult(func, result, NULL); + return result; +} + + +PyObject * +_PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, + PyObject **args, Py_ssize_t nargs, + PyObject *kwargs) +{ + PyCFunction meth; + PyObject *result; + int flags; + PyObject *argstuple; + + /* _PyMethodDef_RawFastCallDict() must not be called with an exception set, + because it can clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + + assert(method != NULL); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + assert(kwargs == NULL || PyDict_Check(kwargs)); + + meth = method->ml_meth; + flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + + switch (flags) + { + case METH_NOARGS: + if (nargs != 0) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + method->ml_name, nargs); + return NULL; + } + + if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { + goto no_keyword_error; + } + + result = (*meth) (self, NULL); + break; + + case METH_O: + if (nargs != 1) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%zd given)", + method->ml_name, nargs); + return NULL; + } + + if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { + goto no_keyword_error; + } + + result = (*meth) (self, args[0]); + break; + + case METH_VARARGS: + if (!(flags & METH_KEYWORDS) + && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { + goto no_keyword_error; + } + /* fall through next case */ + + case METH_VARARGS | METH_KEYWORDS: + /* Slow-path: create a temporary tuple for positional arguments */ + argstuple = _PyStack_AsTuple(args, nargs); + if (argstuple == NULL) { + return NULL; + } + + if (flags & METH_KEYWORDS) { + result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs); + } + else { + result = (*meth) (self, argstuple); + } + Py_DECREF(argstuple); + break; + + case METH_FASTCALL: + { + PyObject **stack; + PyObject *kwnames; + _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth; + + if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) { + return NULL; + } + + result = (*fastmeth) (self, stack, nargs, kwnames); + if (stack != args) { + PyMem_Free(stack); + } + Py_XDECREF(kwnames); + break; + } + + default: + PyErr_SetString(PyExc_SystemError, + "Bad call flags in _PyMethodDef_RawFastCallDict. " + "METH_OLDARGS is no longer supported!"); + return NULL; + } + + return result; + +no_keyword_error: + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", + method->ml_name, nargs); + + return NULL; +} + + +PyObject * +_PyCFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, + PyObject *kwargs) +{ + PyObject *result; + + assert(func != NULL); + assert(PyCFunction_Check(func)); + assert(kwargs == NULL || PyDict_Check(kwargs)); + + if (kwargs == NULL || PyDict_GET_SIZE(kwargs) == 0) { + return _PyCFunction_FastCall(func, args, nargs); + } + else { + result = _PyMethodDef_RawFastCallDict( + ((PyCFunctionObject*)func)->m_ml, + PyCFunction_GET_SELF(func), + args, nargs, kwargs); + result = _Py_CheckFunctionResult(func, result, NULL); + return result; + } +} + + +PyObject * +_PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, + PyObject **args, Py_ssize_t nargs, + PyObject *kwnames) +{ + /* _PyMethodDef_RawFastCallKeywords() must not be called with an exception set, + because it can clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + + assert(method != NULL); + assert(nargs >= 0); + assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); + /* kwnames must only contains str strings, no subclass, and all keys must + be unique */ + + PyCFunction meth = method->ml_meth; + int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_Size(kwnames); + PyObject *result; + + switch (flags) + { + case METH_NOARGS: + if (nargs != 0) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + method->ml_name, nargs); + return NULL; + } + + if (nkwargs) { + goto no_keyword_error; + } + + result = (*meth) (self, NULL); + break; + + case METH_O: + if (nargs != 1) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%zd given)", + method->ml_name, nargs); + return NULL; + } + + if (nkwargs) { + goto no_keyword_error; + } + + result = (*meth) (self, args[0]); + break; + + case METH_FASTCALL: + /* Fast-path: avoid temporary dict to pass keyword arguments */ + result = ((_PyCFunctionFast)meth) (self, args, nargs, kwnames); + break; + + case METH_VARARGS: + case METH_VARARGS | METH_KEYWORDS: + { + /* Slow-path: create a temporary tuple for positional arguments + and a temporary dict for keyword arguments */ + PyObject *argtuple; + + if (!(flags & METH_KEYWORDS) && nkwargs) { + goto no_keyword_error; + } + + argtuple = _PyStack_AsTuple(args, nargs); + if (argtuple == NULL) { + return NULL; + } + + if (flags & METH_KEYWORDS) { + PyObject *kwdict; + + if (nkwargs > 0) { + kwdict = _PyStack_AsDict(args + nargs, kwnames); + if (kwdict == NULL) { + Py_DECREF(argtuple); + return NULL; + } + } + else { + kwdict = NULL; + } + + result = (*(PyCFunctionWithKeywords)meth) (self, argtuple, kwdict); + Py_XDECREF(kwdict); + } + else { + result = (*meth) (self, argtuple); + } + Py_DECREF(argtuple); + break; + } + + default: + PyErr_SetString(PyExc_SystemError, + "Bad call flags in _PyCFunction_FastCallKeywords. " + "METH_OLDARGS is no longer supported!"); + return NULL; + } + + return result; + +no_keyword_error: + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", + method->ml_name); + return NULL; +} + + +PyObject * +_PyCFunction_FastCallKeywords(PyObject *func, PyObject **args, + Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *result; + + assert(func != NULL); + assert(PyCFunction_Check(func)); + assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); + + if (kwnames == NULL || PyTuple_GET_SIZE(kwnames) == 0) { + return _PyCFunction_FastCall(func, args, nargs); + } + else { + result = _PyMethodDef_RawFastCallKeywords(((PyCFunctionObject*)func)->m_ml, + PyCFunction_GET_SELF(func), + args, nargs, kwnames); + result = _Py_CheckFunctionResult(func, result, NULL); + return result; + } +} + + +static PyObject * +cfunction_call(PyObject *func, PyObject *args, PyObject *kwargs) +{ + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + PyObject *result; + + assert(!PyErr_Occurred()); + + if (PyCFunction_GET_FLAGS(func) & METH_KEYWORDS) { + result = (*(PyCFunctionWithKeywords)meth)(self, args, kwargs); + } + else { + if (kwargs != NULL && PyDict_Size(kwargs) != 0) { + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + ((PyCFunctionObject*)func)->m_ml->ml_name); + return NULL; + } + + result = (*meth)(self, args); + } + + return _Py_CheckFunctionResult(func, result, NULL); +} + + +PyObject * +PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs) +{ + /* first try METH_VARARGS to pass directly args tuple unchanged. + _PyMethodDef_RawFastCallDict() creates a new temporary tuple + for METH_VARARGS. */ + if (PyCFunction_GET_FLAGS(func) & METH_VARARGS) { + return cfunction_call(func, args, kwargs); + } + else if (kwargs == NULL || PyDict_GET_SIZE(kwargs) == 0) { + return _PyCFunction_FastCall(func, + &PyTuple_GET_ITEM(args, 0), + PyTuple_GET_SIZE(args)); + } + else { + PyObject *result; + + result = _PyMethodDef_RawFastCallDict( + ((PyCFunctionObject*)func)->m_ml, + PyCFunction_GET_SELF(func), + &PyTuple_GET_ITEM(args, 0), + PyTuple_GET_SIZE(args), + kwargs); + result = _Py_CheckFunctionResult(func, result, NULL); + return result; + } +} + + +/* PyFunction */ + +static PyObject* +function_code_fastcall(PyCodeObject *co, PyObject *globals, + PyObject **args, Py_ssize_t nargs) +{ + PyFrameObject *f; + PyThreadState *tstate = PyThreadState_GET(); + PyObject **fastlocals; + Py_ssize_t i; + PyObject *result; + + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + _PyFrame_New_NoTrack() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = _PyFrame_New_NoTrack(tstate, co, globals, NULL); + if (f == NULL) { + return NULL; + } + + fastlocals = f->f_localsplus; + + for (i = 0; i < nargs; i++) { + Py_INCREF(*args); + fastlocals[i] = *args++; + } + result = PyEval_EvalFrameEx(f, 0); + + if (Py_REFCNT(f) > 1) { + Py_DECREF(f); + _PyObject_GC_TRACK(f); + } + else { + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + } + return result; +} + + +PyObject* +_PyFunction_FastCall(PyObject *func, PyObject **args, Py_ssize_t nargs) +{ + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *kwdefs, *closure, *name, *qualname; + PyObject **d; + Py_ssize_t nd; + + assert(PyFunction_Check(func)); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + + if (co->co_kwonlyargcount == 0 && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) + { + if (argdefs == NULL && co->co_argcount == nargs) { + return function_code_fastcall(co, globals, args, nargs); + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + return function_code_fastcall(co, globals, + &PyTuple_GET_ITEM(argdefs, 0), + PyTuple_GET_SIZE(argdefs)); + } + } + + kwdefs = PyFunction_GET_KW_DEFAULTS(func); + closure = PyFunction_GET_CLOSURE(func); + name = ((PyFunctionObject *)func) -> func_name; + qualname = ((PyFunctionObject *)func) -> func_qualname; + + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } + return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL, + args, nargs, + NULL, NULL, 0, 0, + d, (int)nd, kwdefs, + closure, name, qualname); +} + + +PyObject * +_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, + PyObject *kwargs) +{ + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *kwdefs, *closure, *name, *qualname; + PyObject *kwtuple, **k; + PyObject **d; + Py_ssize_t nd, nk; + PyObject *result; + + assert(func != NULL); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + assert(kwargs == NULL || PyDict_Check(kwargs)); + + if (co->co_kwonlyargcount == 0 && + (kwargs == NULL || PyDict_GET_SIZE(kwargs) == 0) && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) + { + /* Fast paths */ + if (argdefs == NULL && co->co_argcount == nargs) { + return function_code_fastcall(co, globals, args, nargs); + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + return function_code_fastcall(co, globals, + &PyTuple_GET_ITEM(argdefs, 0), + Py_SIZE(argdefs)); + } + } + + nk = (kwargs != NULL) ? PyDict_GET_SIZE(kwargs) : 0; + if (nk != 0) { + Py_ssize_t pos, i; + + /* Issue #29318: Caller and callee functions must not share the + dictionary: kwargs must be copied. */ + kwtuple = PyTuple_New(2 * nk); + if (kwtuple == NULL) { + return NULL; + } + + k = &PyTuple_GET_ITEM(kwtuple, 0); + pos = i = 0; + while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { + /* We must hold strong references because keyword arguments can be + indirectly modified while the function is called: + see issue #2016 and test_extcall */ + Py_INCREF(k[i]); + Py_INCREF(k[i+1]); + i += 2; + } + nk = i / 2; + } + else { + kwtuple = NULL; + k = NULL; + } + + kwdefs = PyFunction_GET_KW_DEFAULTS(func); + closure = PyFunction_GET_CLOSURE(func); + name = ((PyFunctionObject *)func) -> func_name; + qualname = ((PyFunctionObject *)func) -> func_qualname; + + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } + + result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL, + args, nargs, + k, k + 1, nk, 2, + d, nd, kwdefs, + closure, name, qualname); + Py_XDECREF(kwtuple); + return result; +} + + +PyObject * +_PyFunction_FastCallKeywords(PyObject *func, PyObject **stack, + Py_ssize_t nargs, PyObject *kwnames) +{ + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *kwdefs, *closure, *name, *qualname; + PyObject **d; + Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + Py_ssize_t nd; + + assert(PyFunction_Check(func)); + assert(nargs >= 0); + assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); + assert((nargs == 0 && nkwargs == 0) || stack != NULL); + /* kwnames must only contains str strings, no subclass, and all keys must + be unique */ + + if (co->co_kwonlyargcount == 0 && nkwargs == 0 && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) + { + if (argdefs == NULL && co->co_argcount == nargs) { + return function_code_fastcall(co, globals, stack, nargs); + } + else if (nargs == 0 && argdefs != NULL + && co->co_argcount == Py_SIZE(argdefs)) { + /* function called with no arguments, but all parameters have + a default value: use default values as arguments .*/ + return function_code_fastcall(co, globals, + &PyTuple_GET_ITEM(argdefs, 0), + PyTuple_GET_SIZE(argdefs)); + } + } + + kwdefs = PyFunction_GET_KW_DEFAULTS(func); + closure = PyFunction_GET_CLOSURE(func); + name = ((PyFunctionObject *)func) -> func_name; + qualname = ((PyFunctionObject *)func) -> func_qualname; + + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + else { + d = NULL; + nd = 0; + } + return _PyEval_EvalCodeWithName( + (PyObject*)co, globals, (PyObject *)NULL, + stack, nargs, + (kwnames != NULL) ? &PyTuple_GET_ITEM(kwnames, 0) : NULL, + stack + nargs, + nkwargs, 1, + d, (int)nd, kwdefs, + closure, name, qualname); +} + + +/* Helper functions */ + +PyObject* +_PyStack_AsTupleSlice(PyObject **stack, Py_ssize_t nargs, + Py_ssize_t start, Py_ssize_t end) +{ + PyObject *args; + Py_ssize_t i; + + assert(0 <= start); + assert(end <= nargs); + assert(start <= end); + + args = PyTuple_New(end - start); + if (args == NULL) { + return NULL; + } + + for (i=start; i < end; i++) { + PyObject *item = stack[i]; + Py_INCREF(item); + PyTuple_SET_ITEM(args, i - start, item); + } + return args; +} + + +/* Disable inlining to reduce the stack consumption */ +int +_PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, + PyObject ***p_stack, PyObject **p_kwnames) +{ + PyObject **stack, **kwstack; + Py_ssize_t nkwargs; + Py_ssize_t pos, i; + PyObject *key, *value; + PyObject *kwnames; + + assert(nargs >= 0); + assert(kwargs == NULL || PyDict_CheckExact(kwargs)); + + if (kwargs == NULL || (nkwargs = PyDict_GET_SIZE(kwargs)) == 0) { + *p_stack = args; + *p_kwnames = NULL; + return 0; + } + + if ((size_t)nargs > PY_SSIZE_T_MAX / sizeof(stack[0]) - (size_t)nkwargs) { + PyErr_NoMemory(); + return -1; + } + + stack = PyMem_Malloc((nargs + nkwargs) * sizeof(stack[0])); + if (stack == NULL) { + PyErr_NoMemory(); + return -1; + } + + kwnames = PyTuple_New(nkwargs); + if (kwnames == NULL) { + PyMem_Free(stack); + return -1; + } + + /* Copy position arguments (borrowed references) */ + memcpy(stack, args, nargs * sizeof(stack[0])); + + kwstack = stack + nargs; + pos = i = 0; + /* This loop doesn't support lookup function mutating the dictionary + to change its size. It's a deliberate choice for speed, this function is + called in the performance critical hot code. */ + while (PyDict_Next(kwargs, &pos, &key, &value)) { + Py_INCREF(key); + PyTuple_SET_ITEM(kwnames, i, key); + /* The stack contains borrowed references */ + kwstack[i] = value; + i++; + } + + *p_stack = stack; + *p_kwnames = kwnames; + return 0; +} + + +/* Positional arguments are obj followed by args: + call callable(obj, *args, **kwargs) */ +PyObject * +_PyObject_Call_Prepend(PyObject *callable, + PyObject *obj, PyObject *args, PyObject *kwargs) +{ + PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; + PyObject **stack; + Py_ssize_t nargs; + PyObject *result; + + assert(PyTuple_Check(args)); + + nargs = PyTuple_GET_SIZE(args) + 1; + if (nargs <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { + stack = small_stack; + } + else { + stack = PyMem_Malloc(nargs * sizeof(PyObject *)); + if (stack == NULL) { + PyErr_NoMemory(); + return NULL; + } + } + + /* use borrowed references */ + stack[0] = obj; + memcpy(&stack[1], + &PyTuple_GET_ITEM(args, 0), + (nargs - 1) * sizeof(PyObject *)); + + result = _PyObject_FastCallDict(callable, stack, nargs, kwargs); + if (stack != small_stack) { + PyMem_Free(stack); + } + return result; +} + + +static PyObject * +_PyObject_CallFunctionVa(PyObject *callable, const char *format, + va_list vargs, int is_size_t) +{ + PyObject* small_stack[_PY_FASTCALL_SMALL_STACK]; + const Py_ssize_t small_stack_len = Py_ARRAY_LENGTH(small_stack); + PyObject **stack; + Py_ssize_t nargs, i; + PyObject *result; + + if (callable == NULL) { + return null_error(); + } + + if (!format || !format[0]) { + return _PyObject_CallNoArg(callable); + } + + if (is_size_t) { + stack = _Py_VaBuildStack(small_stack, small_stack_len, + format, vargs, &nargs); + } + else { + stack = _Py_VaBuildStack_SizeT(small_stack, small_stack_len, + format, vargs, &nargs); + } + if (stack == NULL) { + return NULL; + } + + if (nargs == 1 && PyTuple_Check(stack[0])) { + /* Special cases for backward compatibility: + - PyObject_CallFunction(func, "O", tuple) calls func(*tuple) + - PyObject_CallFunction(func, "(OOO)", arg1, arg2, arg3) calls + func(*(arg1, arg2, arg3)): func(arg1, arg2, arg3) */ + result = _PyObject_FastCall(callable, + &PyTuple_GET_ITEM(stack[0], 0), + PyTuple_GET_SIZE(stack[0])); + } + else { + result = _PyObject_FastCall(callable, stack, nargs); + } + + for (i = 0; i < nargs; ++i) { + Py_DECREF(stack[i]); + } + if (stack != small_stack) { + PyMem_Free(stack); + } + return result; +} + + +PyObject * +PyObject_CallFunction(PyObject *callable, const char *format, ...) +{ + va_list vargs; + PyObject *result; + + va_start(vargs, format); + result = _PyObject_CallFunctionVa(callable, format, vargs, 0); + va_end(vargs); + + return result; +} + + +PyObject * +PyEval_CallFunction(PyObject *callable, const char *format, ...) +{ + va_list vargs; + PyObject *result; + + va_start(vargs, format); + result = _PyObject_CallFunctionVa(callable, format, vargs, 0); + va_end(vargs); + + return result; +} + + +PyObject * +_PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) +{ + va_list vargs; + PyObject *result; + + va_start(vargs, format); + result = _PyObject_CallFunctionVa(callable, format, vargs, 1); + va_end(vargs); + + return result; +} + + +static PyObject* +callmethod(PyObject* callable, const char *format, va_list vargs, int is_size_t) +{ + assert(callable != NULL); + + if (!PyCallable_Check(callable)) { + PyErr_Format(PyExc_TypeError, + "attribute of type '%.200s' is not callable", + Py_TYPE(callable)->tp_name); + return NULL; + } + + return _PyObject_CallFunctionVa(callable, format, vargs, is_size_t); +} + + +PyObject * +PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) +{ + va_list vargs; + PyObject *callable, *retval; + + if (obj == NULL || name == NULL) { + return null_error(); + } + + callable = PyObject_GetAttrString(obj, name); + if (callable == NULL) + return NULL; + + va_start(vargs, format); + retval = callmethod(callable, format, vargs, 0); + va_end(vargs); + + Py_DECREF(callable); + return retval; +} + + +PyObject * +_PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, + const char *format, ...) +{ + va_list vargs; + PyObject *callable, *retval; + + if (obj == NULL || name == NULL) { + return null_error(); + } + + callable = _PyObject_GetAttrId(obj, name); + if (callable == NULL) + return NULL; + + va_start(vargs, format); + retval = callmethod(callable, format, vargs, 0); + va_end(vargs); + + Py_DECREF(callable); + return retval; +} + + +PyObject * +_PyObject_CallMethod_SizeT(PyObject *obj, const char *name, + const char *format, ...) +{ + va_list vargs; + PyObject *callable, *retval; + + if (obj == NULL || name == NULL) { + return null_error(); + } + + callable = PyObject_GetAttrString(obj, name); + if (callable == NULL) + return NULL; + + va_start(vargs, format); + retval = callmethod(callable, format, vargs, 1); + va_end(vargs); + + Py_DECREF(callable); + return retval; +} + + +PyObject * +_PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, + const char *format, ...) +{ + va_list vargs; + PyObject *callable, *retval; + + if (obj == NULL || name == NULL) { + return null_error(); + } + + callable = _PyObject_GetAttrId(obj, name); + if (callable == NULL) { + return NULL; + } + + va_start(vargs, format); + retval = callmethod(callable, format, vargs, 1); + va_end(vargs); + + Py_DECREF(callable); + return retval; +} + + +PyObject * +PyEval_CallMethod(PyObject *obj, const char *name, const char *format, ...) +{ + va_list vargs; + PyObject *callable, *result; + + callable = PyObject_GetAttrString(obj, name); + if (callable == NULL) + return NULL; + + va_start(vargs, format); + result = callmethod(callable, format, vargs, 0); + va_end(vargs); + + Py_DECREF(callable); + return result; +} + + +static PyObject * +object_vacall(PyObject *callable, va_list vargs) +{ + PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; + PyObject **stack; + Py_ssize_t nargs; + PyObject *result; + Py_ssize_t i; + va_list countva; + + if (callable == NULL) { + return null_error(); + } + + /* Count the number of arguments */ + va_copy(countva, vargs); + nargs = 0; + while (1) { + PyObject *arg = va_arg(countva, PyObject *); + if (arg == NULL) { + break; + } + nargs++; + } + va_end(countva); + + /* Copy arguments */ + if (nargs <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { + stack = small_stack; + } + else { + stack = PyMem_Malloc(nargs * sizeof(stack[0])); + if (stack == NULL) { + PyErr_NoMemory(); + return NULL; + } + } + + for (i = 0; i < nargs; ++i) { + stack[i] = va_arg(vargs, PyObject *); + } + + /* Call the function */ + result = _PyObject_FastCall(callable, stack, nargs); + + if (stack != small_stack) { + PyMem_Free(stack); + } + return result; +} + + +PyObject * +PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) +{ + va_list vargs; + PyObject *result; + + if (callable == NULL || name == NULL) { + return null_error(); + } + + callable = PyObject_GetAttr(callable, name); + if (callable == NULL) { + return NULL; + } + + va_start(vargs, name); + result = object_vacall(callable, vargs); + va_end(vargs); + + Py_DECREF(callable); + return result; +} + + +PyObject * +_PyObject_CallMethodIdObjArgs(PyObject *obj, + struct _Py_Identifier *name, ...) +{ + va_list vargs; + PyObject *callable, *result; + + if (obj == NULL || name == NULL) { + return null_error(); + } + + callable = _PyObject_GetAttrId(obj, name); + if (callable == NULL) { + return NULL; + } + + va_start(vargs, name); + result = object_vacall(callable, vargs); + va_end(vargs); + + Py_DECREF(callable); + return result; +} + + +PyObject * +PyObject_CallFunctionObjArgs(PyObject *callable, ...) +{ + va_list vargs; + PyObject *result; + + va_start(vargs, callable); + result = object_vacall(callable, vargs); + va_end(vargs); + + return result; +} + + +PyObject * +PyObject_CallObject(PyObject *callable, PyObject *args) +{ +#ifdef Py_DEBUG + /* PyObject_CallObject() must not be called with an exception + set. It raises a new exception if parameters are invalid or if + PyTuple_New() fails, and so the original exception is lost. */ + assert(!PyErr_Occurred()); +#endif + + if (args == NULL) { + return _PyObject_CallNoArg(callable); + } + + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_TypeError, + "argument list must be a tuple"); + return NULL; + } + + return PyObject_Call(callable, args, NULL); +} diff -r e06af4027546 Objects/methodobject.c --- a/Objects/methodobject.c Mon Feb 06 07:15:57 2017 -0800 +++ b/Objects/methodobject.c Tue Feb 07 15:42:16 2017 +0100 @@ -77,272 +77,6 @@ PyCFunction_GetFlags(PyObject *op) return PyCFunction_GET_FLAGS(op); } -PyObject * -PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs) -{ - return _PyCFunction_FastCallDict(func, - &PyTuple_GET_ITEM(args, 0), - PyTuple_GET_SIZE(args), - kwargs); -} - -PyObject * -_PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args, - Py_ssize_t nargs, PyObject *kwargs) -{ - PyCFunction meth; - PyObject *result; - int flags; - PyObject *argstuple; - - /* _PyMethodDef_RawFastCallDict() must not be called with an exception set, - because it can clear it (directly or indirectly) and so the - caller loses its exception */ - assert(!PyErr_Occurred()); - - assert(method != NULL); - assert(nargs >= 0); - assert(nargs == 0 || args != NULL); - assert(kwargs == NULL || PyDict_Check(kwargs)); - - meth = method->ml_meth; - flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); - - switch (flags) - { - case METH_NOARGS: - if (nargs != 0) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%zd given)", - method->ml_name, nargs); - return NULL; - } - - if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { - goto no_keyword_error; - } - - result = (*meth) (self, NULL); - break; - - case METH_O: - if (nargs != 1) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes exactly one argument (%zd given)", - method->ml_name, nargs); - return NULL; - } - - if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { - goto no_keyword_error; - } - - result = (*meth) (self, args[0]); - break; - - case METH_VARARGS: - if (!(flags & METH_KEYWORDS) - && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { - goto no_keyword_error; - } - /* fall through next case */ - - case METH_VARARGS | METH_KEYWORDS: - /* Slow-path: create a temporary tuple for positional arguments */ - argstuple = _PyStack_AsTuple(args, nargs); - if (argstuple == NULL) { - return NULL; - } - - if (flags & METH_KEYWORDS) { - result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs); - } - else { - result = (*meth) (self, argstuple); - } - Py_DECREF(argstuple); - break; - - case METH_FASTCALL: - { - PyObject **stack; - PyObject *kwnames; - _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth; - - if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) { - return NULL; - } - - result = (*fastmeth) (self, stack, nargs, kwnames); - if (stack != args) { - PyMem_Free(stack); - } - Py_XDECREF(kwnames); - break; - } - - default: - PyErr_SetString(PyExc_SystemError, - "Bad call flags in _PyMethodDef_RawFastCallDict. " - "METH_OLDARGS is no longer supported!"); - return NULL; - } - - return result; - -no_keyword_error: - PyErr_Format(PyExc_TypeError, - "%.200s() takes no keyword arguments", - method->ml_name, nargs); - - return NULL; -} - -PyObject * -_PyCFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, - PyObject *kwargs) -{ - PyObject *result; - - assert(func != NULL); - assert(PyCFunction_Check(func)); - - result = _PyMethodDef_RawFastCallDict(((PyCFunctionObject*)func)->m_ml, - PyCFunction_GET_SELF(func), - args, nargs, kwargs); - result = _Py_CheckFunctionResult(func, result, NULL); - return result; -} - -PyObject * -_PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject **args, - Py_ssize_t nargs, PyObject *kwnames) -{ - /* _PyMethodDef_RawFastCallKeywords() must not be called with an exception set, - because it can clear it (directly or indirectly) and so the - caller loses its exception */ - assert(!PyErr_Occurred()); - - assert(method != NULL); - assert(nargs >= 0); - assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - /* kwnames must only contains str strings, no subclass, and all keys must - be unique */ - - PyCFunction meth = method->ml_meth; - int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); - Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_Size(kwnames); - PyObject *result; - - switch (flags) - { - case METH_NOARGS: - if (nargs != 0) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%zd given)", - method->ml_name, nargs); - return NULL; - } - - if (nkwargs) { - goto no_keyword_error; - } - - result = (*meth) (self, NULL); - break; - - case METH_O: - if (nargs != 1) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes exactly one argument (%zd given)", - method->ml_name, nargs); - return NULL; - } - - if (nkwargs) { - goto no_keyword_error; - } - - result = (*meth) (self, args[0]); - break; - - case METH_FASTCALL: - /* Fast-path: avoid temporary dict to pass keyword arguments */ - result = ((_PyCFunctionFast)meth) (self, args, nargs, kwnames); - break; - - case METH_VARARGS: - case METH_VARARGS | METH_KEYWORDS: - { - /* Slow-path: create a temporary tuple for positional arguments - and a temporary dict for keyword arguments */ - PyObject *argtuple; - - if (!(flags & METH_KEYWORDS) && nkwargs) { - goto no_keyword_error; - } - - argtuple = _PyStack_AsTuple(args, nargs); - if (argtuple == NULL) { - return NULL; - } - - if (flags & METH_KEYWORDS) { - PyObject *kwdict; - - if (nkwargs > 0) { - kwdict = _PyStack_AsDict(args + nargs, kwnames); - if (kwdict == NULL) { - Py_DECREF(argtuple); - return NULL; - } - } - else { - kwdict = NULL; - } - - result = (*(PyCFunctionWithKeywords)meth) (self, argtuple, kwdict); - Py_XDECREF(kwdict); - } - else { - result = (*meth) (self, argtuple); - } - Py_DECREF(argtuple); - break; - } - - default: - PyErr_SetString(PyExc_SystemError, - "Bad call flags in _PyCFunction_FastCallKeywords. " - "METH_OLDARGS is no longer supported!"); - return NULL; - } - - return result; - -no_keyword_error: - PyErr_Format(PyExc_TypeError, - "%.200s() takes no keyword arguments", - method->ml_name); - return NULL; -} - -PyObject * -_PyCFunction_FastCallKeywords(PyObject *func, PyObject **args, - Py_ssize_t nargs, PyObject *kwnames) -{ - PyObject *result; - - assert(func != NULL); - assert(PyCFunction_Check(func)); - - result = _PyMethodDef_RawFastCallKeywords(((PyCFunctionObject*)func)->m_ml, - PyCFunction_GET_SELF(func), - args, nargs, kwnames); - result = _Py_CheckFunctionResult(func, result, NULL); - return result; -} - /* Methods (the standard built-in methods, that is) */ static void diff -r e06af4027546 PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj Mon Feb 06 07:15:57 2017 -0800 +++ b/PCbuild/pythoncore.vcxproj Tue Feb 07 15:42:16 2017 +0100 @@ -297,6 +297,7 @@ + diff -r e06af4027546 Python/ceval.c --- a/Python/ceval.c Mon Feb 06 07:15:57 2017 -0800 +++ b/Python/ceval.c Tue Feb 07 15:42:16 2017 +0100 @@ -37,7 +37,6 @@ typedef PyObject *(*callproc)(PyObject * /* Forward declarations */ Py_LOCAL_INLINE(PyObject *) call_function(PyObject ***, Py_ssize_t, PyObject *); -static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, PyObject *); static PyObject * do_call_core(PyObject *, PyObject *, PyObject *); #ifdef LLTRACE @@ -3895,7 +3894,7 @@ too_many_positional(PyCodeObject *co, Py PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust the test in the if statements in Misc/gdbinit (pystack and pystackv). */ -static PyObject * +PyObject * _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals, PyObject **args, Py_ssize_t argcount, PyObject **kwnames, PyObject **kwargs, @@ -4747,7 +4746,12 @@ PyEval_CallObjectWithKeywords(PyObject * #endif if (args == NULL) { - return _PyObject_FastCallDict(callable, NULL, 0, kwargs); + if (kwargs == NULL) { + return _PyObject_CallNoArg(callable); + } + else { + return _PyObject_FastCallDict(callable, NULL, 0, kwargs); + } } if (!PyTuple_Check(args)) { @@ -4865,7 +4869,7 @@ call_function(PyObject ***pp_stack, Py_s } if (PyFunction_Check(func)) { - x = fast_function(func, stack, nargs, kwnames); + x = _PyFunction_FastCallKeywords(func, stack, nargs, kwnames); } else { x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames); @@ -4877,7 +4881,7 @@ call_function(PyObject ***pp_stack, Py_s /* Clear the stack of the function object. Also removes the arguments in case they weren't consumed already - (fast_function() and err_args() leave them on the stack). + (_PyFunction_FastCallKeywords() and err_args() leave them on the stack). */ while ((*pp_stack) > pfunc) { w = EXT_POP(*pp_stack); @@ -4887,205 +4891,6 @@ call_function(PyObject ***pp_stack, Py_s return x; } -/* The fast_function() function optimize calls for which no argument - tuple is necessary; the objects are passed directly from the stack. - For the simplest case -- a function that takes only positional - arguments and is called with only positional arguments -- it - inlines the most primitive frame setup code from - PyEval_EvalCodeEx(), which vastly reduces the checks that must be - done before evaluating the frame. -*/ - -static PyObject* _Py_HOT_FUNCTION -_PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs, - PyObject *globals) -{ - PyFrameObject *f; - PyThreadState *tstate = PyThreadState_GET(); - PyObject **fastlocals; - Py_ssize_t i; - PyObject *result; - - assert(globals != NULL); - /* XXX Perhaps we should create a specialized - _PyFrame_New_NoTrack() that doesn't take locals, but does - take builtins without sanity checking them. - */ - assert(tstate != NULL); - f = _PyFrame_New_NoTrack(tstate, co, globals, NULL); - if (f == NULL) { - return NULL; - } - - fastlocals = f->f_localsplus; - - for (i = 0; i < nargs; i++) { - Py_INCREF(*args); - fastlocals[i] = *args++; - } - result = PyEval_EvalFrameEx(f,0); - - if (Py_REFCNT(f) > 1) { - Py_DECREF(f); - _PyObject_GC_TRACK(f); - } - else { - ++tstate->recursion_depth; - Py_DECREF(f); - --tstate->recursion_depth; - } - return result; -} - -static PyObject * -fast_function(PyObject *func, PyObject **stack, - Py_ssize_t nargs, PyObject *kwnames) -{ - PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); - PyObject *globals = PyFunction_GET_GLOBALS(func); - PyObject *argdefs = PyFunction_GET_DEFAULTS(func); - PyObject *kwdefs, *closure, *name, *qualname; - PyObject **d; - Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); - Py_ssize_t nd; - - assert(PyFunction_Check(func)); - assert(nargs >= 0); - assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - assert((nargs == 0 && nkwargs == 0) || stack != NULL); - /* kwnames must only contains str strings, no subclass, and all keys must - be unique */ - - if (co->co_kwonlyargcount == 0 && nkwargs == 0 && - co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) - { - if (argdefs == NULL && co->co_argcount == nargs) { - return _PyFunction_FastCall(co, stack, nargs, globals); - } - else if (nargs == 0 && argdefs != NULL - && co->co_argcount == Py_SIZE(argdefs)) { - /* function called with no arguments, but all parameters have - a default value: use default values as arguments .*/ - stack = &PyTuple_GET_ITEM(argdefs, 0); - return _PyFunction_FastCall(co, stack, Py_SIZE(argdefs), globals); - } - } - - kwdefs = PyFunction_GET_KW_DEFAULTS(func); - closure = PyFunction_GET_CLOSURE(func); - name = ((PyFunctionObject *)func) -> func_name; - qualname = ((PyFunctionObject *)func) -> func_qualname; - - if (argdefs != NULL) { - d = &PyTuple_GET_ITEM(argdefs, 0); - nd = Py_SIZE(argdefs); - } - else { - d = NULL; - nd = 0; - } - return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL, - stack, nargs, - nkwargs ? &PyTuple_GET_ITEM(kwnames, 0) : NULL, - stack + nargs, - nkwargs, 1, - d, (int)nd, kwdefs, - closure, name, qualname); -} - -PyObject * -_PyFunction_FastCallKeywords(PyObject *func, PyObject **stack, - Py_ssize_t nargs, PyObject *kwnames) -{ - return fast_function(func, stack, nargs, kwnames); -} - -PyObject * -_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, - PyObject *kwargs) -{ - PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); - PyObject *globals = PyFunction_GET_GLOBALS(func); - PyObject *argdefs = PyFunction_GET_DEFAULTS(func); - PyObject *kwdefs, *closure, *name, *qualname; - PyObject *kwtuple, **k; - PyObject **d; - Py_ssize_t nd, nk; - PyObject *result; - - assert(func != NULL); - assert(nargs >= 0); - assert(nargs == 0 || args != NULL); - assert(kwargs == NULL || PyDict_Check(kwargs)); - - if (co->co_kwonlyargcount == 0 && - (kwargs == NULL || PyDict_GET_SIZE(kwargs) == 0) && - co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) - { - /* Fast paths */ - if (argdefs == NULL && co->co_argcount == nargs) { - return _PyFunction_FastCall(co, args, nargs, globals); - } - else if (nargs == 0 && argdefs != NULL - && co->co_argcount == Py_SIZE(argdefs)) { - /* function called with no arguments, but all parameters have - a default value: use default values as arguments .*/ - args = &PyTuple_GET_ITEM(argdefs, 0); - return _PyFunction_FastCall(co, args, Py_SIZE(argdefs), globals); - } - } - - nk = (kwargs != NULL) ? PyDict_GET_SIZE(kwargs) : 0; - if (nk != 0) { - Py_ssize_t pos, i; - - /* Issue #29318: Caller and callee functions must not share the - dictionary: kwargs must be copied. */ - kwtuple = PyTuple_New(2 * nk); - if (kwtuple == NULL) { - return NULL; - } - - k = &PyTuple_GET_ITEM(kwtuple, 0); - pos = i = 0; - while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) { - /* We must hold strong references because keyword arguments can be - indirectly modified while the function is called: - see issue #2016 and test_extcall */ - Py_INCREF(k[i]); - Py_INCREF(k[i+1]); - i += 2; - } - nk = i / 2; - } - else { - kwtuple = NULL; - k = NULL; - } - - kwdefs = PyFunction_GET_KW_DEFAULTS(func); - closure = PyFunction_GET_CLOSURE(func); - name = ((PyFunctionObject *)func) -> func_name; - qualname = ((PyFunctionObject *)func) -> func_qualname; - - if (argdefs != NULL) { - d = &PyTuple_GET_ITEM(argdefs, 0); - nd = Py_SIZE(argdefs); - } - else { - d = NULL; - nd = 0; - } - - result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL, - args, nargs, - k, k + 1, nk, 2, - d, nd, kwdefs, - closure, name, qualname); - Py_XDECREF(kwtuple); - return result; -} - static PyObject * do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict) { diff -r e06af4027546 Python/modsupport.c --- a/Python/modsupport.c Mon Feb 06 07:15:57 2017 -0800 +++ b/Python/modsupport.c Tue Feb 07 15:42:16 2017 +0100 @@ -586,57 +586,6 @@ va_build_stack(PyObject **small_stack, P } -PyObject * -PyEval_CallFunction(PyObject *callable, const char *format, ...) -{ - va_list vargs; - PyObject *args; - PyObject *res; - - va_start(vargs, format); - - args = Py_VaBuildValue(format, vargs); - va_end(vargs); - - if (args == NULL) - return NULL; - - res = PyEval_CallObject(callable, args); - Py_DECREF(args); - - return res; -} - - -PyObject * -PyEval_CallMethod(PyObject *obj, const char *name, const char *format, ...) -{ - va_list vargs; - PyObject *meth; - PyObject *args; - PyObject *res; - - meth = PyObject_GetAttrString(obj, name); - if (meth == NULL) - return NULL; - - va_start(vargs, format); - - args = Py_VaBuildValue(format, vargs); - va_end(vargs); - - if (args == NULL) { - Py_DECREF(meth); - return NULL; - } - - res = PyEval_CallObject(meth, args); - Py_DECREF(meth); - Py_DECREF(args); - - return res; -} - int PyModule_AddObject(PyObject *m, const char *name, PyObject *o) {