diff --git a/Doc/library/re.rst b/Doc/library/re.rst index 6e9343a..adf3ddd 100644 --- a/Doc/library/re.rst +++ b/Doc/library/re.rst @@ -1465,7 +1465,7 @@ successive matches:: elif kind == 'SKIP': pass elif kind == 'MISMATCH': - raise RuntimeError(f'{value!r} unexpected on line {line_num}') + raise RuntimeError('%r unexpected on line %d' % (value, line_num)) else: if kind == 'ID' and value in keywords: kind = value diff --git a/Include/abstract.h b/Include/abstract.h index 231e209..6aaba7a 100644 --- a/Include/abstract.h +++ b/Include/abstract.h @@ -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_FastCallKeywords( 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 --git a/Include/ceval.h b/Include/ceval.h index e4be595..5404846 100644 --- a/Include/ceval.h +++ b/Include/ceval.h @@ -13,8 +13,7 @@ PyAPI_FUNC(PyObject *) PyEval_CallObjectWithKeywords( 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 --git a/Include/funcobject.h b/Include/funcobject.h index 77bb8c3..d17945d 100644 --- a/Include/funcobject.h +++ b/Include/funcobject.h @@ -59,6 +59,11 @@ PyAPI_FUNC(PyObject *) PyFunction_GetAnnotations(PyObject *); 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 --git a/Include/methodobject.h b/Include/methodobject.h index b5c4e83..23f59c3 100644 --- a/Include/methodobject.h +++ b/Include/methodobject.h @@ -40,6 +40,11 @@ PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *); 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 --git a/Lib/test/test_winconsoleio.py b/Lib/test/test_winconsoleio.py index 656483c..0d88ae3 100644 --- a/Lib/test/test_winconsoleio.py +++ b/Lib/test/test_winconsoleio.py @@ -6,7 +6,6 @@ import os import sys import tempfile import unittest -from test import support if sys.platform != 'win32': raise unittest.SkipTest("test only relevant on win32") @@ -98,28 +97,23 @@ class WindowsConsoleIOTests(unittest.TestCase): self.assertIsInstance(f, ConIO) f.close() - @unittest.skipIf(sys.getwindowsversion()[:2] <= (6, 1), - "test does not work on Windows 7 and earlier") - def test_conin_conout_names(self): - f = open(r'\\.\conin$', 'rb', buffering=0) - self.assertIsInstance(f, ConIO) - f.close() - - f = open('//?/conout$', 'wb', buffering=0) - self.assertIsInstance(f, ConIO) - f.close() - - def test_conout_path(self): - temp_path = tempfile.mkdtemp() - self.addCleanup(support.rmtree, temp_path) - - conout_path = os.path.join(temp_path, 'CONOUT$') + try: + f = open(r'\\.\conin$', 'rb', buffering=0) + except FileNotFoundError: + # If we cannot find the file, this part should be skipped + print('\\\\.\\conin$ was not found on this OS') + else: + self.assertIsInstance(f, ConIO) + f.close() - with open(conout_path, 'wb', buffering=0) as f: - if sys.getwindowsversion()[:2] > (6, 1): - self.assertIsInstance(f, ConIO) - else: - self.assertNotIsInstance(f, ConIO) + try: + f = open('//?/conout$', 'wb', buffering=0) + except FileNotFoundError: + # If we cannot find the file, this part should be skipped + print('//?/conout$ was not found on this OS') + else: + self.assertIsInstance(f, ConIO) + f.close() def assertStdinRoundTrip(self, text): stdin = open('CONIN$', 'r') diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 8615bf1..e8131ad 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -908,18 +908,12 @@ done: } static PyObject * -deque_rotate(dequeobject *deque, PyObject **args, Py_ssize_t nargs, - PyObject *kwnames) +deque_rotate(dequeobject *deque, PyObject *args) { Py_ssize_t n=1; - if (!_PyArg_NoStackKeywords("rotate", kwnames)) { + if (!PyArg_ParseTuple(args, "|n:rotate", &n)) return NULL; - } - if (!_PyArg_ParseStack(args, nargs, "|n:rotate", &n)) { - return NULL; - } - if (!_deque_rotate(deque, n)) Py_RETURN_NONE; return NULL; @@ -1048,8 +1042,7 @@ deque_len(dequeobject *deque) } static PyObject * -deque_index(dequeobject *deque, PyObject **args, Py_ssize_t nargs, - PyObject *kwnames) +deque_index(dequeobject *deque, PyObject *args) { Py_ssize_t i, n, start=0, stop=Py_SIZE(deque); PyObject *v, *item; @@ -1058,15 +1051,10 @@ deque_index(dequeobject *deque, PyObject **args, Py_ssize_t nargs, size_t start_state = deque->state; int cmp; - if (!_PyArg_NoStackKeywords("index", kwnames)) { - return NULL; - } - if (!_PyArg_ParseStack(args, nargs, "O|O&O&:index", &v, - _PyEval_SliceIndex, &start, - _PyEval_SliceIndex, &stop)) { + if (!PyArg_ParseTuple(args, "O|O&O&:index", &v, + _PyEval_SliceIndex, &start, + _PyEval_SliceIndex, &stop)) return NULL; - } - if (start < 0) { start += Py_SIZE(deque); if (start < 0) @@ -1129,21 +1117,15 @@ PyDoc_STRVAR(index_doc, */ static PyObject * -deque_insert(dequeobject *deque, PyObject **args, Py_ssize_t nargs, - PyObject *kwnames) +deque_insert(dequeobject *deque, PyObject *args) { Py_ssize_t index; Py_ssize_t n = Py_SIZE(deque); PyObject *value; PyObject *rv; - if (!_PyArg_NoStackKeywords("insert", kwnames)) { - return NULL; - } - if (!_PyArg_ParseStack(args, nargs, "nO:insert", &index, &value)) { + if (!PyArg_ParseTuple(args, "nO:insert", &index, &value)) return NULL; - } - if (deque->maxlen == Py_SIZE(deque)) { PyErr_SetString(PyExc_IndexError, "deque already at its maximum size"); return NULL; @@ -1613,9 +1595,9 @@ static PyMethodDef deque_methods[] = { {"extendleft", (PyCFunction)deque_extendleft, METH_O, extendleft_doc}, {"index", (PyCFunction)deque_index, - METH_FASTCALL, index_doc}, + METH_VARARGS, index_doc}, {"insert", (PyCFunction)deque_insert, - METH_FASTCALL, insert_doc}, + METH_VARARGS, insert_doc}, {"pop", (PyCFunction)deque_pop, METH_NOARGS, pop_doc}, {"popleft", (PyCFunction)deque_popleft, @@ -1629,7 +1611,7 @@ static PyMethodDef deque_methods[] = { {"reverse", (PyCFunction)deque_reverse, METH_NOARGS, reverse_doc}, {"rotate", (PyCFunction)deque_rotate, - METH_FASTCALL, rotate_doc}, + METH_VARARGS, rotate_doc}, {"__sizeof__", (PyCFunction)deque_sizeof, METH_NOARGS, sizeof_doc}, {NULL, NULL} /* sentinel */ diff --git a/Objects/abstract.c b/Objects/abstract.c index 1e394f8..d536705 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2175,7 +2175,24 @@ PyMapping_Values(PyObject *o) PyObject * PyObject_CallObject(PyObject *callable, PyObject *args) { - return PyEval_CallObjectWithKeywords(callable, args, NULL); +#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); } PyObject* @@ -2226,34 +2243,65 @@ _Py_CheckFunctionResult(PyObject *callable, PyObject *result, const char *where) return result; } -PyObject * -PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) +/* 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; - /* 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)); + 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); - return NULL; + callable->ob_type->tp_name); + goto exit; } - if (Py_EnterRecursiveCall(" while calling a Python object")) - return NULL; + argtuple = _PyStack_AsTuple(stack, nargs); + if (argtuple == NULL) { + goto exit; + } - result = (*call)(callable, args, kwargs); + result = (*call)(callable, argtuple, NULL); + Py_DECREF(argtuple); + result = _Py_CheckFunctionResult(callable, result, NULL); + +exit: Py_LeaveRecursiveCall(); + return result; +} - return _Py_CheckFunctionResult(callable, result, NULL); +/* 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); + } } /* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their @@ -2301,11 +2349,38 @@ _PyStack_AsTupleSlice(PyObject **stack, Py_ssize_t nargs, return args; } +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; + } + + result = (*call)(callable, tuple, kwargs); + Py_DECREF(tuple); + + result = _Py_CheckFunctionResult(callable, result, NULL); + return result; +} + 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, @@ -2318,42 +2393,88 @@ _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs, assert(nargs == 0 || args != NULL); assert(kwargs == NULL || PyDict_Check(kwargs)); - if (Py_EnterRecursiveCall(" while calling a Python object")) { - return NULL; + if (kwargs == NULL) { + 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 (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } - if (PyFunction_Check(callable)) { - result = _PyFunction_FastCallDict(callable, args, nargs, kwargs); + if (PyFunction_Check(callable)) { + result = _PyFunction_FastCallDict(callable, args, nargs, kwargs); + } + else if (PyCFunction_Check(callable)) { + result = _PyCFunction_FastCallDict(callable, args, nargs, kwargs); + } + else { + result = object_fastcalldict_slow(callable, args, nargs, kwargs); + } + + Py_LeaveRecursiveCall(); + + return result; } - else if (PyCFunction_Check(callable)) { - result = _PyCFunction_FastCallDict(callable, args, nargs, kwargs); +} + +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) { + if (PyFunction_Check(callable)) { + return _PyFunction_FastCall(callable, stack, nargs); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCall(callable, stack, nargs); + } + else { + return object_fastcall_slow(callable, stack, nargs); + } } else { - 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); - goto exit; + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; } - tuple = _PyStack_AsTuple(args, nargs); - if (tuple == NULL) { - goto exit; + if (PyFunction_Check(callable)) { + result = _PyFunction_FastCallDict(callable, stack, nargs, kwargs); + } + else if (PyCFunction_Check(callable)) { + result = _PyCFunction_FastCallDict(callable, stack, nargs, kwargs); + } + else { + result = object_fastcalldict_slow(callable, stack, nargs, kwargs); } - result = (*call)(callable, tuple, kwargs); - Py_DECREF(tuple); + Py_LeaveRecursiveCall(); - result = _Py_CheckFunctionResult(callable, result, NULL); + return result; } - -exit: - Py_LeaveRecursiveCall(); - - return result; } /* Positional arguments are obj followed by args: @@ -2479,8 +2600,63 @@ _PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, return 0; } +/* 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 **stack, Py_ssize_t nargs, +_PyObject_FastCallKeywords(PyObject *callable, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { /* _PyObject_FastCallKeywords() must not be called with an exception set, @@ -2491,71 +2667,37 @@ _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t narg 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; + if (kwnames == NULL) { + if (PyFunction_Check(callable)) { + return _PyFunction_FastCall(callable, args, nargs); } - - 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; + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCall(callable, args, nargs); } - - argtuple = _PyStack_AsTuple(stack, nargs); - if (argtuple == NULL) { - goto exit; + 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 (nkwargs > 0) { - kwdict = _PyStack_AsDict(stack + nargs, kwnames); - if (kwdict == NULL) { - Py_DECREF(argtuple); - goto exit; - } + if (PyFunction_Check(callable)) { + return _PyFunction_FastCallKeywords(callable, args, nargs, kwnames); + } + else if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCallKeywords(callable, args, nargs, kwnames); } else { - kwdict = NULL; + return object_fastcallkw_slow(callable, args, nargs, kwnames); } - - 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) + 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); @@ -2567,15 +2709,15 @@ _PyObject_CallFunctionVa(PyObject *callable, const char *format, return null_error(); } - if (!format || !*format) { + if (!format || !format[0]) { return _PyObject_CallNoArg(callable); } if (is_size_t) { - stack = _Py_VaBuildStack(small_stack, small_stack_len, format, va, &nargs); + stack = _Py_VaBuildStack(small_stack, small_stack_len, format, vargs, &nargs); } else { - stack = _Py_VaBuildStack_SizeT(small_stack, small_stack_len, format, va, &nargs); + stack = _Py_VaBuildStack_SizeT(small_stack, small_stack_len, format, vargs, &nargs); } if (stack == NULL) { return NULL; @@ -2586,10 +2728,9 @@ _PyObject_CallFunctionVa(PyObject *callable, const char *format, - 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)); + &PyTuple_GET_ITEM(stack[0], 0), + PyTuple_GET_SIZE(stack[0])); } else { result = _PyObject_FastCall(callable, stack, nargs); @@ -2607,12 +2748,25 @@ _PyObject_CallFunctionVa(PyObject *callable, const char *format, PyObject * PyObject_CallFunction(PyObject *callable, const char *format, ...) { - va_list va; + va_list vargs; PyObject *result; - va_start(va, format); - result = _PyObject_CallFunctionVa(callable, format, va, 0); - va_end(va); + 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; } @@ -2620,18 +2774,18 @@ PyObject_CallFunction(PyObject *callable, const char *format, ...) PyObject * _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) { - va_list va; + va_list vargs; PyObject *result; - va_start(va, format); - result = _PyObject_CallFunctionVa(callable, format, va, 1); - va_end(va); + 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 va, int is_size_t) +callmethod(PyObject* callable, const char *format, va_list vargs, int is_size_t) { assert(callable != NULL); @@ -2640,13 +2794,13 @@ callmethod(PyObject* callable, const char *format, va_list va, int is_size_t) return NULL; } - return _PyObject_CallFunctionVa(callable, format, va, is_size_t); + return _PyObject_CallFunctionVa(callable, format, vargs, is_size_t); } PyObject * PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) { - va_list va; + va_list vargs; PyObject *callable, *retval; if (obj == NULL || name == NULL) { @@ -2657,9 +2811,9 @@ PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) if (callable == NULL) return NULL; - va_start(va, format); - retval = callmethod(callable, format, va, 0); - va_end(va); + va_start(vargs, format); + retval = callmethod(callable, format, vargs, 0); + va_end(vargs); Py_DECREF(callable); return retval; @@ -2669,7 +2823,7 @@ PyObject * _PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, const char *format, ...) { - va_list va; + va_list vargs; PyObject *callable, *retval; if (obj == NULL || name == NULL) { @@ -2680,9 +2834,9 @@ _PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, if (callable == NULL) return NULL; - va_start(va, format); - retval = callmethod(callable, format, va, 0); - va_end(va); + va_start(vargs, format); + retval = callmethod(callable, format, vargs, 0); + va_end(vargs); Py_DECREF(callable); return retval; @@ -2692,7 +2846,7 @@ PyObject * _PyObject_CallMethod_SizeT(PyObject *obj, const char *name, const char *format, ...) { - va_list va; + va_list vargs; PyObject *callable, *retval; if (obj == NULL || name == NULL) { @@ -2703,9 +2857,9 @@ _PyObject_CallMethod_SizeT(PyObject *obj, const char *name, if (callable == NULL) return NULL; - va_start(va, format); - retval = callmethod(callable, format, va, 1); - va_end(va); + va_start(vargs, format); + retval = callmethod(callable, format, vargs, 1); + va_end(vargs); Py_DECREF(callable); return retval; @@ -2715,7 +2869,7 @@ PyObject * _PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, const char *format, ...) { - va_list va; + va_list vargs; PyObject *callable, *retval; if (obj == NULL || name == NULL) { @@ -2727,14 +2881,32 @@ _PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, return NULL; } - va_start(va, format); - retval = callmethod(callable, format, va, 1); - va_end(va); + 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) { diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 6618d78..81dd238 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -87,6 +87,83 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs) } 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) { diff --git a/Python/ceval.c b/Python/ceval.c index 5800779..fe27dd2 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4747,7 +4747,12 @@ PyEval_CallObjectWithKeywords(PyObject *callable, #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)) { @@ -4897,8 +4902,8 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames) */ static PyObject* _Py_HOT_FUNCTION -_PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs, - PyObject *globals) +function_fastcall_impl(PyCodeObject *co, PyObject **args, Py_ssize_t nargs, + PyObject *globals) { PyFrameObject *f; PyThreadState *tstate = PyThreadState_GET(); @@ -4937,6 +4942,55 @@ _PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs, 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_fastcall_impl(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 function_fastcall_impl(co, args, 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, + args, nargs, + NULL, NULL, 0, 0, + d, (int)nd, kwdefs, + closure, name, qualname); +} + static PyObject * fast_function(PyObject *func, PyObject **stack, Py_ssize_t nargs, PyObject *kwnames) @@ -4960,14 +5014,14 @@ fast_function(PyObject *func, PyObject **stack, co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { if (argdefs == NULL && co->co_argcount == nargs) { - return _PyFunction_FastCall(co, stack, nargs, globals); + return function_fastcall_impl(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); + return function_fastcall_impl(co, stack, Py_SIZE(argdefs), globals); } } @@ -5024,14 +5078,14 @@ _PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, { /* Fast paths */ if (argdefs == NULL && co->co_argcount == nargs) { - return _PyFunction_FastCall(co, args, nargs, globals); + return function_fastcall_impl(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); + return function_fastcall_impl(co, args, Py_SIZE(argdefs), globals); } } diff --git a/Python/modsupport.c b/Python/modsupport.c index e9e025b..9637191 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -586,57 +586,6 @@ va_build_stack(PyObject **small_stack, Py_ssize_t small_stack_len, } -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) { diff --git a/Tools/msi/make_zip.py b/Tools/msi/make_zip.py index 710e4a5..8dbe83e 100644 --- a/Tools/msi/make_zip.py +++ b/Tools/msi/make_zip.py @@ -29,15 +29,12 @@ DEBUG_FILES = { EXCLUDE_FROM_LIBRARY = { '__pycache__', + 'ensurepip', 'idlelib', 'pydoc_data', 'site-packages', 'tkinter', 'turtledemo', -} - -EXCLUDE_FROM_EMBEDDABLE_LIBRARY = { - 'ensurepip', 'venv', } @@ -85,12 +82,6 @@ def include_in_lib(p): suffix = p.suffix.lower() return suffix not in {'.pyc', '.pyo', '.exe'} -def include_in_embeddable_lib(p): - if p.is_dir() and p.name.lower() in EXCLUDE_FROM_EMBEDDABLE_LIBRARY: - return False - - return include_in_lib(p) - def include_in_libs(p): if not is_not_debug(p): return False @@ -123,7 +114,7 @@ EMBED_LAYOUT = [ ('/', 'PCBuild/$arch', 'python*.exe', is_not_debug), ('/', 'PCBuild/$arch', '*.pyd', is_not_debug), ('/', 'PCBuild/$arch', '*.dll', is_not_debug), - ('{}.zip'.format(BASE_NAME), 'Lib', '**/*', include_in_embeddable_lib), + ('{}.zip'.format(BASE_NAME), 'Lib', '**/*', include_in_lib), ] if os.getenv('DOC_FILENAME'):