From bc91176aa05a4c7e67cffaf31286a86728bc7c99 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 3 Jun 2016 21:42:55 +0300 Subject: Issue #26983: float() now always return an instance of exact float. The deprecation warning is emitted if __float__ returns an instance of a strict subclass of float. In a future versions of Python this can be an error. --- Objects/abstract.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 3e1ff97547..12dd6a16ce 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1351,21 +1351,39 @@ PyNumber_Float(PyObject *o) if (o == NULL) return null_error(); + if (PyFloat_CheckExact(o)) { + Py_INCREF(o); + return o; + } m = o->ob_type->tp_as_number; if (m && m->nb_float) { /* This should include subclasses of float */ PyObject *res = m->nb_float(o); - if (res && !PyFloat_Check(res)) { + double val; + if (!res || PyFloat_CheckExact(res)) { + return res; + } + if (!PyFloat_Check(res)) { PyErr_Format(PyExc_TypeError, - "__float__ returned non-float (type %.200s)", - res->ob_type->tp_name); + "%.50s.__float__ returned non-float (type %.50s)", + o->ob_type->tp_name, res->ob_type->tp_name); Py_DECREF(res); return NULL; } - return res; + /* Issue #26983: warn if 'res' not of exact type float. */ + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "%.50s.__float__ returned non-float (type %.50s). " + "The ability to return an instance of a strict subclass of float " + "is deprecated, and may be removed in a future version of Python.", + o->ob_type->tp_name, res->ob_type->tp_name)) { + Py_DECREF(res); + return NULL; + } + val = PyFloat_AS_DOUBLE(res); + Py_DECREF(res); + return PyFloat_FromDouble(val); } if (PyFloat_Check(o)) { /* A float subclass with nb_float == NULL */ - PyFloatObject *po = (PyFloatObject *)o; - return PyFloat_FromDouble(po->ob_fval); + return PyFloat_FromDouble(PyFloat_AS_DOUBLE(o)); } return PyFloat_FromString(o); } -- cgit v1.2.1 From e5585ad97cb7527c73b3b758df87c8b982ceb8de Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 12 Jun 2016 17:02:10 +0300 Subject: Comment fixes extracted from patch by Demur Rumed. --- Objects/abstract.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 12dd6a16ce..8ca6933226 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2132,7 +2132,7 @@ _Py_CheckFunctionResult(PyObject *func, PyObject *result, const char *where) "%s returned NULL without setting an error", where); #ifdef Py_DEBUG - /* Ensure that the bug is catched in debug mode */ + /* Ensure that the bug is caught in debug mode */ Py_FatalError("a function returned NULL without setting an error"); #endif return NULL; -- cgit v1.2.1 From d7a4362203dbd80afd88e89b46e649d7c3095821 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 16:11:43 +0200 Subject: Add _PyObject_FastCall() Issue #27128: Add _PyObject_FastCall(), a new calling convention avoiding a temporary tuple to pass positional parameters in most cases, but create a temporary tuple if needed (ex: for the tp_call slot). The API is prepared to support keyword parameters, but the full implementation will come later (_PyFunction_FastCall() doesn't support keyword parameters yet). Add also: * _PyStack_AsTuple() helper function: convert a "stack" of parameters to a tuple. * _PyCFunction_FastCall(): fast call implementation for C functions * _PyFunction_FastCall(): fast call implementation for Python functions --- Objects/abstract.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 5d8a44b172..36401a8d14 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2193,6 +2193,82 @@ PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) return _Py_CheckFunctionResult(func, result, NULL); } +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; +} + +PyObject * +_PyObject_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) +{ + ternaryfunc call; + PyObject *result = NULL; + + /* _PyObject_FastCall() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + + assert(func != NULL); + assert(nargs >= 0); + assert(nargs == 0 || args != NULL); + /* issue #27128: support for keywords will come later: + _PyFunction_FastCall() doesn't support keyword arguments yet */ + assert(kwargs == NULL); + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + if (PyFunction_Check(func)) { + result = _PyFunction_FastCall(func, args, nargs, kwargs); + } + else if (PyCFunction_Check(func)) { + result = _PyCFunction_FastCall(func, args, nargs, kwargs); + } + else { + PyObject *tuple; + + /* Slow-path: build a temporary tuple */ + call = func->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + func->ob_type->tp_name); + goto exit; + } + + tuple = _PyStack_AsTuple(args, nargs); + if (tuple == NULL) { + goto exit; + } + + result = (*call)(func, tuple, kwargs); + Py_DECREF(tuple); + } + + result = _Py_CheckFunctionResult(func, result, NULL); + +exit: + Py_LeaveRecursiveCall(); + + return result; +} + static PyObject* call_function_tail(PyObject *callable, PyObject *args) { -- cgit v1.2.1 From bc7e6abd8218c398b1cdc2fd4c531711277971c5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 16:44:19 +0200 Subject: call_function_tail() uses fast call Issue #27128: Modify call_function_tail() to use _PyObject_FastCall() when args is not a tuple to avoid the creation of a temporary tuple. call_function_tail() is used by: * PyObject_CallFunction() * PyObject_CallMethod() * _PyObject_CallMethodId() --- Objects/abstract.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 36401a8d14..1a63c6b70a 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2272,27 +2272,20 @@ exit: static PyObject* call_function_tail(PyObject *callable, PyObject *args) { - PyObject *retval; + PyObject *result; if (args == NULL) return NULL; if (!PyTuple_Check(args)) { - PyObject *a; - - a = PyTuple_New(1); - if (a == NULL) { - Py_DECREF(args); - return NULL; - } - PyTuple_SET_ITEM(a, 0, args); - args = a; + result = _PyObject_FastCall(callable, &args, 1, NULL); + } + else { + result = PyObject_Call(callable, args, NULL); } - retval = PyObject_Call(callable, args, NULL); Py_DECREF(args); - - return retval; + return result; } PyObject * -- cgit v1.2.1 From 672445b98a2077f2609db4a85380153592f99481 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 16:50:49 +0200 Subject: Cleanup call_function_tail() Make call_function_tail() less weird: don't decrement args reference counter, the caller is now responsible to do that. The caller now also checks if args is NULL. Issue #27128. --- Objects/abstract.c | 49 +++++++++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 20 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 1a63c6b70a..64b8e9096b 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2274,8 +2274,7 @@ call_function_tail(PyObject *callable, PyObject *args) { PyObject *result; - if (args == NULL) - return NULL; + assert(args != NULL); if (!PyTuple_Check(args)) { result = _PyObject_FastCall(callable, &args, 1, NULL); @@ -2284,7 +2283,6 @@ call_function_tail(PyObject *callable, PyObject *args) result = PyObject_Call(callable, args, NULL); } - Py_DECREF(args); return result; } @@ -2292,7 +2290,7 @@ PyObject * PyObject_CallFunction(PyObject *callable, const char *format, ...) { va_list va; - PyObject *args; + PyObject *args, *result; if (callable == NULL) return null_error(); @@ -2302,19 +2300,23 @@ PyObject_CallFunction(PyObject *callable, const char *format, ...) args = Py_VaBuildValue(format, va); va_end(va); } - else + else { args = PyTuple_New(0); - if (args == NULL) + } + if (args == NULL) { return NULL; + } - return call_function_tail(callable, args); + result = call_function_tail(callable, args); + Py_DECREF(args); + return result; } PyObject * _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) { va_list va; - PyObject *args; + PyObject *args, *result; if (callable == NULL) return null_error(); @@ -2324,21 +2326,27 @@ _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) args = _Py_VaBuildValue_SizeT(format, va); va_end(va); } - else + else { args = PyTuple_New(0); + } + if (args == NULL) { + return NULL; + } - return call_function_tail(callable, args); + result = call_function_tail(callable, args); + Py_DECREF(args); + return result; } static PyObject* callmethod(PyObject* func, const char *format, va_list va, int is_size_t) { - PyObject *retval = NULL; - PyObject *args; + PyObject *args, *result; if (!PyCallable_Check(func)) { type_error("attribute of type '%.200s' is not callable", func); - goto exit; + Py_XDECREF(func); + return NULL; } if (format && *format) { @@ -2347,16 +2355,17 @@ callmethod(PyObject* func, const char *format, va_list va, int is_size_t) else args = Py_VaBuildValue(format, va); } - else + else { args = PyTuple_New(0); + } + if (args == NULL) { + return NULL; + } - retval = call_function_tail(func, args); - - exit: - /* args gets consumed in call_function_tail */ + result = call_function_tail(func, args); Py_XDECREF(func); - - return retval; + Py_DECREF(args); + return result; } PyObject * -- cgit v1.2.1 From 1b6da98a2ef1fedee8f69cfd8d709b7ac7b6d6ec Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 16:56:49 +0200 Subject: Cleanup callmethod() Make callmethod() less weird: don't decrement func reference counter, the caller is now responsible to do that. Issue #27128. --- Objects/abstract.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 64b8e9096b..9e9c9aaa0e 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2343,9 +2343,10 @@ callmethod(PyObject* func, const char *format, va_list va, int is_size_t) { PyObject *args, *result; + assert(func != NULL); + if (!PyCallable_Check(func)) { type_error("attribute of type '%.200s' is not callable", func); - Py_XDECREF(func); return NULL; } @@ -2363,7 +2364,6 @@ callmethod(PyObject* func, const char *format, va_list va, int is_size_t) } result = call_function_tail(func, args); - Py_XDECREF(func); Py_DECREF(args); return result; } @@ -2385,6 +2385,7 @@ PyObject_CallMethod(PyObject *o, const char *name, const char *format, ...) va_start(va, format); retval = callmethod(func, format, va, 0); va_end(va); + Py_DECREF(func); return retval; } @@ -2406,6 +2407,7 @@ _PyObject_CallMethodId(PyObject *o, _Py_Identifier *name, va_start(va, format); retval = callmethod(func, format, va, 0); va_end(va); + Py_DECREF(func); return retval; } @@ -2426,6 +2428,7 @@ _PyObject_CallMethod_SizeT(PyObject *o, const char *name, va_start(va, format); retval = callmethod(func, format, va, 1); va_end(va); + Py_DECREF(func); return retval; } @@ -2447,6 +2450,7 @@ _PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, va_start(va, format); retval = callmethod(func, format, va, 1); va_end(va); + Py_DECREF(func); return retval; } -- cgit v1.2.1 From 80afdf97213272015522419b68fdb869ec91e009 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 16:59:55 +0200 Subject: PEP 7: add {...} around null_error() in abstract.c Issue #27128. --- Objects/abstract.c | 93 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 65 insertions(+), 28 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 9e9c9aaa0e..cec47bf774 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -32,8 +32,10 @@ PyObject_Type(PyObject *o) { PyObject *v; - if (o == NULL) + if (o == NULL) { return null_error(); + } + v = (PyObject *)o->ob_type; Py_INCREF(v); return v; @@ -137,8 +139,9 @@ PyObject_GetItem(PyObject *o, PyObject *key) { PyMappingMethods *m; - if (o == NULL || key == NULL) + if (o == NULL || key == NULL) { return null_error(); + } m = o->ob_type->tp_as_mapping; if (m && m->mp_subscript) { @@ -1125,8 +1128,10 @@ PyNumber_Negative(PyObject *o) { PyNumberMethods *m; - if (o == NULL) + if (o == NULL) { return null_error(); + } + m = o->ob_type->tp_as_number; if (m && m->nb_negative) return (*m->nb_negative)(o); @@ -1139,8 +1144,10 @@ PyNumber_Positive(PyObject *o) { PyNumberMethods *m; - if (o == NULL) + if (o == NULL) { return null_error(); + } + m = o->ob_type->tp_as_number; if (m && m->nb_positive) return (*m->nb_positive)(o); @@ -1153,8 +1160,10 @@ PyNumber_Invert(PyObject *o) { PyNumberMethods *m; - if (o == NULL) + if (o == NULL) { return null_error(); + } + m = o->ob_type->tp_as_number; if (m && m->nb_invert) return (*m->nb_invert)(o); @@ -1167,8 +1176,10 @@ PyNumber_Absolute(PyObject *o) { PyNumberMethods *m; - if (o == NULL) + if (o == NULL) { return null_error(); + } + m = o->ob_type->tp_as_number; if (m && m->nb_absolute) return m->nb_absolute(o); @@ -1184,8 +1195,10 @@ PyObject * PyNumber_Index(PyObject *item) { PyObject *result = NULL; - if (item == NULL) + if (item == NULL) { return null_error(); + } + if (PyLong_Check(item)) { Py_INCREF(item); return item; @@ -1273,8 +1286,10 @@ PyNumber_Long(PyObject *o) Py_buffer view; _Py_IDENTIFIER(__trunc__); - if (o == NULL) + if (o == NULL) { return null_error(); + } + if (PyLong_CheckExact(o)) { Py_INCREF(o); return o; @@ -1349,8 +1364,10 @@ PyNumber_Float(PyObject *o) { PyNumberMethods *m; - if (o == NULL) + if (o == NULL) { return null_error(); + } + if (PyFloat_CheckExact(o)) { Py_INCREF(o); return o; @@ -1451,8 +1468,9 @@ PySequence_Concat(PyObject *s, PyObject *o) { PySequenceMethods *m; - if (s == NULL || o == NULL) + if (s == NULL || o == NULL) { return null_error(); + } m = s->ob_type->tp_as_sequence; if (m && m->sq_concat) @@ -1475,8 +1493,9 @@ PySequence_Repeat(PyObject *o, Py_ssize_t count) { PySequenceMethods *m; - if (o == NULL) + if (o == NULL) { return null_error(); + } m = o->ob_type->tp_as_sequence; if (m && m->sq_repeat) @@ -1504,8 +1523,9 @@ PySequence_InPlaceConcat(PyObject *s, PyObject *o) { PySequenceMethods *m; - if (s == NULL || o == NULL) + if (s == NULL || o == NULL) { return null_error(); + } m = s->ob_type->tp_as_sequence; if (m && m->sq_inplace_concat) @@ -1528,8 +1548,9 @@ PySequence_InPlaceRepeat(PyObject *o, Py_ssize_t count) { PySequenceMethods *m; - if (o == NULL) + if (o == NULL) { return null_error(); + } m = o->ob_type->tp_as_sequence; if (m && m->sq_inplace_repeat) @@ -1557,8 +1578,9 @@ PySequence_GetItem(PyObject *s, Py_ssize_t i) { PySequenceMethods *m; - if (s == NULL) + if (s == NULL) { return null_error(); + } m = s->ob_type->tp_as_sequence; if (m && m->sq_item) { @@ -1583,7 +1605,9 @@ PySequence_GetSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2) { PyMappingMethods *mp; - if (!s) return null_error(); + if (!s) { + return null_error(); + } mp = s->ob_type->tp_as_mapping; if (mp && mp->mp_subscript) { @@ -1710,8 +1734,9 @@ PySequence_Tuple(PyObject *v) PyObject *result = NULL; Py_ssize_t j; - if (v == NULL) + if (v == NULL) { return null_error(); + } /* Special-case the common tuple and list cases, for efficiency. */ if (PyTuple_CheckExact(v)) { @@ -1791,8 +1816,9 @@ PySequence_List(PyObject *v) PyObject *result; /* result list */ PyObject *rv; /* return value from PyList_Extend */ - if (v == NULL) + if (v == NULL) { return null_error(); + } result = PyList_New(0); if (result == NULL) @@ -1812,8 +1838,9 @@ PySequence_Fast(PyObject *v, const char *m) { PyObject *it; - if (v == NULL) + if (v == NULL) { return null_error(); + } if (PyList_CheckExact(v) || PyTuple_CheckExact(v)) { Py_INCREF(v); @@ -1996,8 +2023,9 @@ PyMapping_GetItemString(PyObject *o, const char *key) { PyObject *okey, *r; - if (key == NULL) + if (key == NULL) { return null_error(); + } okey = PyUnicode_FromString(key); if (okey == NULL) @@ -2292,8 +2320,9 @@ PyObject_CallFunction(PyObject *callable, const char *format, ...) va_list va; PyObject *args, *result; - if (callable == NULL) + if (callable == NULL) { return null_error(); + } if (format && *format) { va_start(va, format); @@ -2318,8 +2347,9 @@ _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) va_list va; PyObject *args, *result; - if (callable == NULL) + if (callable == NULL) { return null_error(); + } if (format && *format) { va_start(va, format); @@ -2375,8 +2405,9 @@ PyObject_CallMethod(PyObject *o, const char *name, const char *format, ...) PyObject *func = NULL; PyObject *retval = NULL; - if (o == NULL || name == NULL) + if (o == NULL || name == NULL) { return null_error(); + } func = PyObject_GetAttrString(o, name); if (func == NULL) @@ -2397,8 +2428,9 @@ _PyObject_CallMethodId(PyObject *o, _Py_Identifier *name, PyObject *func = NULL; PyObject *retval = NULL; - if (o == NULL || name == NULL) + if (o == NULL || name == NULL) { return null_error(); + } func = _PyObject_GetAttrId(o, name); if (func == NULL) @@ -2419,8 +2451,9 @@ _PyObject_CallMethod_SizeT(PyObject *o, const char *name, PyObject *func = NULL; PyObject *retval; - if (o == NULL || name == NULL) + if (o == NULL || name == NULL) { return null_error(); + } func = PyObject_GetAttrString(o, name); if (func == NULL) @@ -2440,8 +2473,9 @@ _PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, PyObject *func = NULL; PyObject *retval; - if (o == NULL || name == NULL) + if (o == NULL || name == NULL) { return null_error(); + } func = _PyObject_GetAttrId(o, name); if (func == NULL) { @@ -2482,8 +2516,9 @@ PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) PyObject *args, *tmp; va_list vargs; - if (callable == NULL || name == NULL) + if (callable == NULL || name == NULL) { return null_error(); + } callable = PyObject_GetAttr(callable, name); if (callable == NULL) @@ -2511,8 +2546,9 @@ _PyObject_CallMethodIdObjArgs(PyObject *callable, PyObject *args, *tmp; va_list vargs; - if (callable == NULL || name == NULL) + if (callable == NULL || name == NULL) { return null_error(); + } callable = _PyObject_GetAttrId(callable, name); if (callable == NULL) @@ -2539,8 +2575,9 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...) PyObject *args, *tmp; va_list vargs; - if (callable == NULL) + if (callable == NULL) { return null_error(); + } /* count the args */ va_start(vargs, callable); -- cgit v1.2.1 From b1b56619853134ba7bf2ed2a0c0ad1d030ea8d03 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 17:04:54 +0200 Subject: Avoid call_function_tail() for empty format str Issue #27128, PyObject_CallFunction(), _PyObject_FastCall() and callmethod(): if the format string of parameters is empty, avoid the creation of an empty tuple: call _PyObject_FastCall() without parameters. --- Objects/abstract.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index cec47bf774..aaa6fc81b6 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2324,14 +2324,13 @@ PyObject_CallFunction(PyObject *callable, const char *format, ...) return null_error(); } - if (format && *format) { - va_start(va, format); - args = Py_VaBuildValue(format, va); - va_end(va); - } - else { - args = PyTuple_New(0); + if (!format || !*format) { + return _PyObject_FastCall(callable, NULL, 0, NULL); } + + va_start(va, format); + args = Py_VaBuildValue(format, va); + va_end(va); if (args == NULL) { return NULL; } @@ -2351,14 +2350,13 @@ _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) return null_error(); } - if (format && *format) { - va_start(va, format); - args = _Py_VaBuildValue_SizeT(format, va); - va_end(va); - } - else { - args = PyTuple_New(0); + if (!format || !*format) { + return _PyObject_FastCall(callable, NULL, 0, NULL); } + + va_start(va, format); + args = _Py_VaBuildValue_SizeT(format, va); + va_end(va); if (args == NULL) { return NULL; } @@ -2380,14 +2378,15 @@ callmethod(PyObject* func, const char *format, va_list va, int is_size_t) return NULL; } - if (format && *format) { - if (is_size_t) - args = _Py_VaBuildValue_SizeT(format, va); - else - args = Py_VaBuildValue(format, va); + if (!format || !*format) { + return _PyObject_FastCall(func, NULL, 0, NULL); + } + + if (is_size_t) { + args = _Py_VaBuildValue_SizeT(format, va); } else { - args = PyTuple_New(0); + args = Py_VaBuildValue(format, va); } if (args == NULL) { return NULL; -- cgit v1.2.1 From 06f5b1d3dd2314af2e1f97e8da45bb28b0969f5e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 19 Aug 2016 17:12:23 +0200 Subject: Fix PyObject_Call() parameter names Issue #27128: arg=>args, kw=>kwargs. Same change for PyEval_CallObjectWithKeywords(). --- Objects/abstract.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index aaa6fc81b6..dcf3eb5545 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2194,7 +2194,7 @@ _Py_CheckFunctionResult(PyObject *func, PyObject *result, const char *where) } PyObject * -PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) +PyObject_Call(PyObject *func, PyObject *args, PyObject *kwargs) { ternaryfunc call; PyObject *result; @@ -2203,6 +2203,8 @@ PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) because it may 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 = func->ob_type->tp_call; if (call == NULL) { @@ -2214,7 +2216,7 @@ PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) if (Py_EnterRecursiveCall(" while calling a Python object")) return NULL; - result = (*call)(func, arg, kw); + result = (*call)(func, args, kwargs); Py_LeaveRecursiveCall(); -- cgit v1.2.1 From 40bc2958ebd0639b025c56a3269b08d402548019 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 21 Aug 2016 20:03:08 +0300 Subject: Issue #26984: int() now always returns an instance of exact int. --- Objects/abstract.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index dcf3eb5545..32d4575788 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1281,6 +1281,7 @@ PyNumber_AsSsize_t(PyObject *item, PyObject *err) PyObject * PyNumber_Long(PyObject *o) { + PyObject *result; PyNumberMethods *m; PyObject *trunc_func; Py_buffer view; @@ -1296,29 +1297,39 @@ PyNumber_Long(PyObject *o) } m = o->ob_type->tp_as_number; if (m && m->nb_int) { /* This should include subclasses of int */ - return (PyObject *)_PyLong_FromNbInt(o); + result = (PyObject *)_PyLong_FromNbInt(o); + if (result != NULL && !PyLong_CheckExact(result)) { + Py_SETREF(result, _PyLong_Copy((PyLongObject *)result)); + } + return result; } trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__); if (trunc_func) { - PyObject *truncated = PyEval_CallObject(trunc_func, NULL); - PyObject *int_instance; + result = PyEval_CallObject(trunc_func, NULL); Py_DECREF(trunc_func); - if (truncated == NULL || PyLong_Check(truncated)) - return truncated; + if (result == NULL || PyLong_CheckExact(result)) { + return result; + } + if (PyLong_Check(result)) { + Py_SETREF(result, _PyLong_Copy((PyLongObject *)result)); + return result; + } /* __trunc__ is specified to return an Integral type, but int() needs to return an int. */ - m = truncated->ob_type->tp_as_number; + m = result->ob_type->tp_as_number; if (m == NULL || m->nb_int == NULL) { PyErr_Format( PyExc_TypeError, "__trunc__ returned non-Integral (type %.200s)", - truncated->ob_type->tp_name); - Py_DECREF(truncated); + result->ob_type->tp_name); + Py_DECREF(result); return NULL; } - int_instance = (PyObject *)_PyLong_FromNbInt(truncated); - Py_DECREF(truncated); - return int_instance; + Py_SETREF(result, (PyObject *)_PyLong_FromNbInt(result)); + if (result != NULL && !PyLong_CheckExact(result)) { + Py_SETREF(result, _PyLong_Copy((PyLongObject *)result)); + } + return result; } if (PyErr_Occurred()) return NULL; @@ -1340,7 +1351,7 @@ PyNumber_Long(PyObject *o) PyByteArray_GET_SIZE(o), 10); if (PyObject_GetBuffer(o, &view, PyBUF_SIMPLE) == 0) { - PyObject *result, *bytes; + PyObject *bytes; /* Copy to NUL-terminated buffer. */ bytes = PyBytes_FromStringAndSize((const char *)view.buf, view.len); -- cgit v1.2.1 From de03c6d8066496680a1ea99ff9e67e28852b0007 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 22 Aug 2016 22:48:54 +0200 Subject: Rename _PyObject_FastCall() to _PyObject_FastCallDict() Issue #27809: * Rename _PyObject_FastCall() function to _PyObject_FastCallDict() * Add _PyObject_FastCall(), _PyObject_CallNoArg() and _PyObject_CallArg1() macros calling _PyObject_FastCallDict() --- Objects/abstract.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 32d4575788..2ce7f327e9 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2255,12 +2255,12 @@ _PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) } PyObject * -_PyObject_FastCall(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) +_PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) { ternaryfunc call; PyObject *result = NULL; - /* _PyObject_FastCall() must not be called with an exception set, + /* _PyObject_FastCallDict() must not be called with an exception set, because it may clear it (directly or indirectly) and so the caller loses its exception */ assert(!PyErr_Occurred()); @@ -2318,7 +2318,7 @@ call_function_tail(PyObject *callable, PyObject *args) assert(args != NULL); if (!PyTuple_Check(args)) { - result = _PyObject_FastCall(callable, &args, 1, NULL); + result = _PyObject_CallArg1(callable, args); } else { result = PyObject_Call(callable, args, NULL); @@ -2338,7 +2338,7 @@ PyObject_CallFunction(PyObject *callable, const char *format, ...) } if (!format || !*format) { - return _PyObject_FastCall(callable, NULL, 0, NULL); + return _PyObject_CallNoArg(callable); } va_start(va, format); @@ -2364,7 +2364,7 @@ _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) } if (!format || !*format) { - return _PyObject_FastCall(callable, NULL, 0, NULL); + return _PyObject_CallNoArg(callable); } va_start(va, format); @@ -2392,7 +2392,7 @@ callmethod(PyObject* func, const char *format, va_list va, int is_size_t) } if (!format || !*format) { - return _PyObject_FastCall(func, NULL, 0, NULL); + return _PyObject_CallNoArg(func); } if (is_size_t) { -- cgit v1.2.1 From 9dae6156b5e3127cb8bfaa1bd36cecadaad5d60b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 22 Aug 2016 23:15:44 +0200 Subject: _PyFunction_FastCallDict() supports keyword args Issue #27809: * Rename _PyFunction_FastCall() to _PyFunction_FastCallDict() * Rename _PyCFunction_FastCall() to _PyCFunction_FastCallDict() * _PyFunction_FastCallDict() now supports keyword arguments --- Objects/abstract.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 2ce7f327e9..0e67693fcf 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2255,7 +2255,8 @@ _PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) } PyObject * -_PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwargs) +_PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs, + PyObject *kwargs) { ternaryfunc call; PyObject *result = NULL; @@ -2268,19 +2269,17 @@ _PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs, PyObject *kwa assert(func != NULL); assert(nargs >= 0); assert(nargs == 0 || args != NULL); - /* issue #27128: support for keywords will come later: - _PyFunction_FastCall() doesn't support keyword arguments yet */ - assert(kwargs == NULL); + assert(kwargs == NULL || PyDict_Check(kwargs)); if (Py_EnterRecursiveCall(" while calling a Python object")) { return NULL; } if (PyFunction_Check(func)) { - result = _PyFunction_FastCall(func, args, nargs, kwargs); + result = _PyFunction_FastCallDict(func, args, nargs, kwargs); } else if (PyCFunction_Check(func)) { - result = _PyCFunction_FastCall(func, args, nargs, kwargs); + result = _PyCFunction_FastCallDict(func, args, nargs, kwargs); } else { PyObject *tuple; -- cgit v1.2.1 From 33f03402b35042f1b0f07af602472fbf33d2403c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 24 Aug 2016 00:01:56 +0200 Subject: PyObject_CallMethodObjArgs() now uses fast call Issue #27809: * PyObject_CallMethodObjArgs(), _PyObject_CallMethodIdObjArgs() and PyObject_CallFunctionObjArgs() now use fast call to avoid the creation of a temporary tuple * Rename objargs_mktuple() to objargs_mkstack() * objargs_mkstack() now stores objects in a C array using borrowed references, instead of storing arguments into a tuple objargs_mkstack() uses a small buffer allocated on the C stack for 5 arguments or less, or allocates a buffer in the heap memory. --- Objects/abstract.c | 103 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 32 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 0e67693fcf..14021ba3f4 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2499,32 +2499,52 @@ _PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, return retval; } -static PyObject * -objargs_mktuple(va_list va) +static PyObject ** +objargs_mkstack(PyObject **small_stack, Py_ssize_t small_stack_size, + va_list va, Py_ssize_t *p_nargs) { - int i, n = 0; + Py_ssize_t i, n; va_list countva; - PyObject *result, *tmp; + PyObject **stack; - Py_VA_COPY(countva, va); + /* Count the number of arguments */ + Py_VA_COPY(countva, va); - while (((PyObject *)va_arg(countva, PyObject *)) != NULL) - ++n; - result = PyTuple_New(n); - if (result != NULL && n > 0) { - for (i = 0; i < n; ++i) { - tmp = (PyObject *)va_arg(va, PyObject *); - PyTuple_SET_ITEM(result, i, tmp); - Py_INCREF(tmp); + n = 0; + while (1) { + PyObject *arg = (PyObject *)va_arg(countva, PyObject *); + if (arg == NULL) { + break; } + n++; } - return result; + *p_nargs = n; + + /* Copy arguments */ + if (small_stack_size <= n) { + stack = small_stack; + } + else { + stack = PyMem_Malloc(n * sizeof(PyObject**)); + if (stack == NULL) { + PyErr_NoMemory(); + return NULL; + } + } + + for (i = 0; i < n; ++i) { + stack[i] = va_arg(va, PyObject *); + } + return stack; } PyObject * PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) { - PyObject *args, *tmp; + PyObject *small_stack[5]; + PyObject **stack; + Py_ssize_t nargs; + PyObject *result; va_list vargs; if (callable == NULL || name == NULL) { @@ -2537,24 +2557,31 @@ PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) /* count the args */ va_start(vargs, name); - args = objargs_mktuple(vargs); + stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), + vargs, &nargs); va_end(vargs); - if (args == NULL) { + if (stack == NULL) { Py_DECREF(callable); return NULL; } - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); + + result = _PyObject_FastCall(callable, stack, nargs); Py_DECREF(callable); + if (stack != small_stack) { + PyMem_Free(stack); + } - return tmp; + return result; } PyObject * _PyObject_CallMethodIdObjArgs(PyObject *callable, struct _Py_Identifier *name, ...) { - PyObject *args, *tmp; + PyObject *small_stack[5]; + PyObject **stack; + Py_ssize_t nargs; + PyObject *result; va_list vargs; if (callable == NULL || name == NULL) { @@ -2567,23 +2594,30 @@ _PyObject_CallMethodIdObjArgs(PyObject *callable, /* count the args */ va_start(vargs, name); - args = objargs_mktuple(vargs); + stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), + vargs, &nargs); va_end(vargs); - if (args == NULL) { + if (stack == NULL) { Py_DECREF(callable); return NULL; } - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); + + result = _PyObject_FastCall(callable, stack, nargs); Py_DECREF(callable); + if (stack != small_stack) { + PyMem_Free(stack); + } - return tmp; + return result; } PyObject * PyObject_CallFunctionObjArgs(PyObject *callable, ...) { - PyObject *args, *tmp; + PyObject *small_stack[5]; + PyObject **stack; + Py_ssize_t nargs; + PyObject *result; va_list vargs; if (callable == NULL) { @@ -2592,14 +2626,19 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...) /* count the args */ va_start(vargs, callable); - args = objargs_mktuple(vargs); + stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), + vargs, &nargs); va_end(vargs); - if (args == NULL) + if (stack == NULL) { return NULL; - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); + } + + result = _PyObject_FastCall(callable, stack, nargs); + if (stack != small_stack) { + PyMem_Free(stack); + } - return tmp; + return result; } -- cgit v1.2.1 From 55fa33d025b06a79ee42adc1775dd111943bee04 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 24 Aug 2016 00:59:40 +0200 Subject: Backed out changeset 0e4f26083bbb (PyObject_CallMethodObjArgs) --- Objects/abstract.c | 103 +++++++++++++++++------------------------------------ 1 file changed, 32 insertions(+), 71 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 14021ba3f4..0e67693fcf 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2499,52 +2499,32 @@ _PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, return retval; } -static PyObject ** -objargs_mkstack(PyObject **small_stack, Py_ssize_t small_stack_size, - va_list va, Py_ssize_t *p_nargs) +static PyObject * +objargs_mktuple(va_list va) { - Py_ssize_t i, n; + int i, n = 0; va_list countva; - PyObject **stack; + PyObject *result, *tmp; - /* Count the number of arguments */ - Py_VA_COPY(countva, va); + Py_VA_COPY(countva, va); - n = 0; - while (1) { - PyObject *arg = (PyObject *)va_arg(countva, PyObject *); - if (arg == NULL) { - break; - } - n++; - } - *p_nargs = n; - - /* Copy arguments */ - if (small_stack_size <= n) { - stack = small_stack; - } - else { - stack = PyMem_Malloc(n * sizeof(PyObject**)); - if (stack == NULL) { - PyErr_NoMemory(); - return NULL; + while (((PyObject *)va_arg(countva, PyObject *)) != NULL) + ++n; + result = PyTuple_New(n); + if (result != NULL && n > 0) { + for (i = 0; i < n; ++i) { + tmp = (PyObject *)va_arg(va, PyObject *); + PyTuple_SET_ITEM(result, i, tmp); + Py_INCREF(tmp); } } - - for (i = 0; i < n; ++i) { - stack[i] = va_arg(va, PyObject *); - } - return stack; + return result; } PyObject * PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) { - PyObject *small_stack[5]; - PyObject **stack; - Py_ssize_t nargs; - PyObject *result; + PyObject *args, *tmp; va_list vargs; if (callable == NULL || name == NULL) { @@ -2557,31 +2537,24 @@ PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) /* count the args */ va_start(vargs, name); - stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), - vargs, &nargs); + args = objargs_mktuple(vargs); va_end(vargs); - if (stack == NULL) { + if (args == NULL) { Py_DECREF(callable); return NULL; } - - result = _PyObject_FastCall(callable, stack, nargs); + tmp = PyObject_Call(callable, args, NULL); + Py_DECREF(args); Py_DECREF(callable); - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; + return tmp; } PyObject * _PyObject_CallMethodIdObjArgs(PyObject *callable, struct _Py_Identifier *name, ...) { - PyObject *small_stack[5]; - PyObject **stack; - Py_ssize_t nargs; - PyObject *result; + PyObject *args, *tmp; va_list vargs; if (callable == NULL || name == NULL) { @@ -2594,30 +2567,23 @@ _PyObject_CallMethodIdObjArgs(PyObject *callable, /* count the args */ va_start(vargs, name); - stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), - vargs, &nargs); + args = objargs_mktuple(vargs); va_end(vargs); - if (stack == NULL) { + if (args == NULL) { Py_DECREF(callable); return NULL; } - - result = _PyObject_FastCall(callable, stack, nargs); + tmp = PyObject_Call(callable, args, NULL); + Py_DECREF(args); Py_DECREF(callable); - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; + return tmp; } PyObject * PyObject_CallFunctionObjArgs(PyObject *callable, ...) { - PyObject *small_stack[5]; - PyObject **stack; - Py_ssize_t nargs; - PyObject *result; + PyObject *args, *tmp; va_list vargs; if (callable == NULL) { @@ -2626,19 +2592,14 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...) /* count the args */ va_start(vargs, callable); - stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), - vargs, &nargs); + args = objargs_mktuple(vargs); va_end(vargs); - if (stack == NULL) { + if (args == NULL) return NULL; - } - - result = _PyObject_FastCall(callable, stack, nargs); - if (stack != small_stack) { - PyMem_Free(stack); - } + tmp = PyObject_Call(callable, args, NULL); + Py_DECREF(args); - return result; + return tmp; } -- cgit v1.2.1 From 952739bbc07f0d6d0ea67afbb9334237e5b51722 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 24 Aug 2016 01:14:54 +0200 Subject: PyObject_CallMethodObjArgs() now uses fast call Issue #27809: * PyObject_CallMethodObjArgs(), _PyObject_CallMethodIdObjArgs() and PyObject_CallFunctionObjArgs() now use fast call to avoid the creation of a temporary tuple * Rename objargs_mktuple() to objargs_mkstack() * objargs_mkstack() now stores objects in a C array using borrowed references, instead of storing arguments into a tuple objargs_mkstack() uses a small buffer allocated on the C stack for 5 arguments or less, or allocates a buffer in the heap memory. Note: this change is different than the change 0e4f26083bbb, I fixed the test to decide if the small stack can be used or not. sizeof(PyObject**) was also replaced with sizeof(stack[0]) since the sizeof() was wrong (but gave the same result). --- Objects/abstract.c | 103 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 71 insertions(+), 32 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 0e67693fcf..6db8c266db 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2499,32 +2499,52 @@ _PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, return retval; } -static PyObject * -objargs_mktuple(va_list va) +static PyObject ** +objargs_mkstack(PyObject **small_stack, Py_ssize_t small_stack_size, + va_list va, Py_ssize_t *p_nargs) { - int i, n = 0; + Py_ssize_t i, n; va_list countva; - PyObject *result, *tmp; + PyObject **stack; - Py_VA_COPY(countva, va); + /* Count the number of arguments */ + Py_VA_COPY(countva, va); - while (((PyObject *)va_arg(countva, PyObject *)) != NULL) - ++n; - result = PyTuple_New(n); - if (result != NULL && n > 0) { - for (i = 0; i < n; ++i) { - tmp = (PyObject *)va_arg(va, PyObject *); - PyTuple_SET_ITEM(result, i, tmp); - Py_INCREF(tmp); + n = 0; + while (1) { + PyObject *arg = (PyObject *)va_arg(countva, PyObject *); + if (arg == NULL) { + break; } + n++; } - return result; + *p_nargs = n; + + /* Copy arguments */ + if (n <= small_stack_size) { + stack = small_stack; + } + else { + stack = PyMem_Malloc(n * sizeof(stack[0])); + if (stack == NULL) { + PyErr_NoMemory(); + return NULL; + } + } + + for (i = 0; i < n; ++i) { + stack[i] = va_arg(va, PyObject *); + } + return stack; } PyObject * PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) { - PyObject *args, *tmp; + PyObject *small_stack[5]; + PyObject **stack; + Py_ssize_t nargs; + PyObject *result; va_list vargs; if (callable == NULL || name == NULL) { @@ -2537,24 +2557,31 @@ PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) /* count the args */ va_start(vargs, name); - args = objargs_mktuple(vargs); + stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), + vargs, &nargs); va_end(vargs); - if (args == NULL) { + if (stack == NULL) { Py_DECREF(callable); return NULL; } - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); + + result = _PyObject_FastCall(callable, stack, nargs); Py_DECREF(callable); + if (stack != small_stack) { + PyMem_Free(stack); + } - return tmp; + return result; } PyObject * _PyObject_CallMethodIdObjArgs(PyObject *callable, struct _Py_Identifier *name, ...) { - PyObject *args, *tmp; + PyObject *small_stack[5]; + PyObject **stack; + Py_ssize_t nargs; + PyObject *result; va_list vargs; if (callable == NULL || name == NULL) { @@ -2567,23 +2594,30 @@ _PyObject_CallMethodIdObjArgs(PyObject *callable, /* count the args */ va_start(vargs, name); - args = objargs_mktuple(vargs); + stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), + vargs, &nargs); va_end(vargs); - if (args == NULL) { + if (stack == NULL) { Py_DECREF(callable); return NULL; } - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); + + result = _PyObject_FastCall(callable, stack, nargs); Py_DECREF(callable); + if (stack != small_stack) { + PyMem_Free(stack); + } - return tmp; + return result; } PyObject * PyObject_CallFunctionObjArgs(PyObject *callable, ...) { - PyObject *args, *tmp; + PyObject *small_stack[5]; + PyObject **stack; + Py_ssize_t nargs; + PyObject *result; va_list vargs; if (callable == NULL) { @@ -2592,14 +2626,19 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...) /* count the args */ va_start(vargs, callable); - args = objargs_mktuple(vargs); + stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), + vargs, &nargs); va_end(vargs); - if (args == NULL) + if (stack == NULL) { return NULL; - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); + } + + result = _PyObject_FastCall(callable, stack, nargs); + if (stack != small_stack) { + PyMem_Free(stack); + } - return tmp; + return result; } -- cgit v1.2.1 From c79e5123bcf2d1e514a0420e89c62fa334d57ba9 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 25 Aug 2016 00:04:09 +0200 Subject: Use Py_ssize_t type for number of arguments Issue #27848: use Py_ssize_t rather than C int for the number of function positional and keyword arguments. --- Objects/abstract.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 6db8c266db..f30228198e 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2255,7 +2255,7 @@ _PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) } PyObject * -_PyObject_FastCallDict(PyObject *func, PyObject **args, int nargs, +_PyObject_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { ternaryfunc call; -- cgit v1.2.1 From 5f2acb2c1a143794ef61db34590ceee4b2d89680 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 25 Aug 2016 00:29:32 +0200 Subject: Add _PyObject_FastCallKeywords() Issue #27830: Similar to _PyObject_FastCallDict(), but keyword arguments are also passed in the same C array than positional arguments, rather than being passed as a Python dict. --- Objects/abstract.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index f30228198e..d271d9410a 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2309,6 +2309,85 @@ exit: return result; } +static PyObject * +_PyStack_AsDict(PyObject **stack, Py_ssize_t nkwargs, PyObject *func) +{ + PyObject *kwdict; + + kwdict = PyDict_New(); + if (kwdict == NULL) { + return NULL; + } + + while (--nkwargs >= 0) { + int err; + PyObject *key = *stack++; + PyObject *value = *stack++; + if (PyDict_GetItem(kwdict, key) != NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s%s got multiple values " + "for keyword argument '%U'", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + key); + Py_DECREF(kwdict); + return NULL; + } + + err = PyDict_SetItem(kwdict, key, value); + if (err) { + Py_DECREF(kwdict); + return NULL; + } + } + return kwdict; +} + +PyObject * +_PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, + Py_ssize_t nkwargs) +{ + PyObject *args, *kwdict, *result; + + /* _PyObject_FastCallKeywords() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + + assert(func != NULL); + assert(nargs >= 0); + assert(nkwargs >= 0); + assert((nargs == 0 && nkwargs == 0) || stack != NULL); + + if (PyFunction_Check(func)) { + /* Fast-path: avoid temporary tuple or dict */ + return _PyFunction_FastCallKeywords(func, stack, nargs, nkwargs); + } + + if (PyCFunction_Check(func) && nkwargs == 0) { + return _PyCFunction_FastCallDict(func, args, nargs, NULL); + } + + /* Slow-path: build temporary tuple and/or dict */ + args = _PyStack_AsTuple(stack, nargs); + + if (nkwargs > 0) { + kwdict = _PyStack_AsDict(stack + nargs, nkwargs, func); + if (kwdict == NULL) { + Py_DECREF(args); + return NULL; + } + } + else { + kwdict = NULL; + } + + result = PyObject_Call(func, args, kwdict); + Py_DECREF(args); + Py_XDECREF(kwdict); + return result; +} + static PyObject* call_function_tail(PyObject *callable, PyObject *args) { -- cgit v1.2.1 From 7fc2fcac576ab4678ac087a3c5a20bb2a69d37aa Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 25 Aug 2016 00:39:34 +0200 Subject: _PyObject_FastCallDict(): avoid _Py_CheckFunctionResult() _PyObject_FastCallDict() only requires _Py_CheckFunctionResult() for the slow-path. Other cases already check for the result. --- Objects/abstract.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index d271d9410a..db9f926a36 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2299,9 +2299,9 @@ _PyObject_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, result = (*call)(func, tuple, kwargs); Py_DECREF(tuple); - } - result = _Py_CheckFunctionResult(func, result, NULL); + result = _Py_CheckFunctionResult(func, result, NULL); + } exit: Py_LeaveRecursiveCall(); -- cgit v1.2.1 From a011e6c6c79adcca059bab962ffb9573eb28f7b1 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 25 Aug 2016 01:00:31 +0200 Subject: Issue #27830: Fix _PyObject_FastCallKeywords() Pass stack, not unrelated and uninitialized args! --- Objects/abstract.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index db9f926a36..c41fe11e3a 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2365,7 +2365,7 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, } if (PyCFunction_Check(func) && nkwargs == 0) { - return _PyCFunction_FastCallDict(func, args, nargs, NULL); + return _PyCFunction_FastCallDict(func, stack, nargs, NULL); } /* Slow-path: build temporary tuple and/or dict */ -- cgit v1.2.1 From 1de419b3db8739947ef8c2fe36ce3944d8576fd5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 25 Aug 2016 01:04:14 +0200 Subject: method_call() and slot_tp_new() now uses fast call Issue #27841: Add _PyObject_Call_Prepend() helper function to prepend an argument to existing arguments to call a function. This helper uses fast calls. Modify method_call() and slot_tp_new() to use _PyObject_Call_Prepend(). --- Objects/abstract.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index c41fe11e3a..9e5405df0a 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2388,6 +2388,45 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, return result; } +/* Positional arguments are obj followed args. */ +PyObject * +_PyObject_Call_Prepend(PyObject *func, + PyObject *obj, PyObject *args, PyObject *kwargs) +{ + PyObject *small_stack[8]; + 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; + Py_MEMCPY(&stack[1], + &PyTuple_GET_ITEM(args, 0), + argcount * sizeof(PyObject *)); + + result = _PyObject_FastCallDict(func, + stack, argcount + 1, + kwargs); + if (stack != small_stack) { + PyMem_Free(stack); + } + return result; +} + static PyObject* call_function_tail(PyObject *callable, PyObject *args) { -- cgit v1.2.1 From 2c15df27be9ecb04e0c14313de88a6d9299cb261 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 25 Aug 2016 23:26:50 +0200 Subject: Issue #27830: Revert, remove _PyFunction_FastCallKeywords() --- Objects/abstract.c | 45 --------------------------------------------- 1 file changed, 45 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 9e5405df0a..cf69b96929 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2343,51 +2343,6 @@ _PyStack_AsDict(PyObject **stack, Py_ssize_t nkwargs, PyObject *func) return kwdict; } -PyObject * -_PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, - Py_ssize_t nkwargs) -{ - PyObject *args, *kwdict, *result; - - /* _PyObject_FastCallKeywords() must not be called with an exception set, - because it may clear it (directly or indirectly) and so the - caller loses its exception */ - assert(!PyErr_Occurred()); - - assert(func != NULL); - assert(nargs >= 0); - assert(nkwargs >= 0); - assert((nargs == 0 && nkwargs == 0) || stack != NULL); - - if (PyFunction_Check(func)) { - /* Fast-path: avoid temporary tuple or dict */ - return _PyFunction_FastCallKeywords(func, stack, nargs, nkwargs); - } - - if (PyCFunction_Check(func) && nkwargs == 0) { - return _PyCFunction_FastCallDict(func, stack, nargs, NULL); - } - - /* Slow-path: build temporary tuple and/or dict */ - args = _PyStack_AsTuple(stack, nargs); - - if (nkwargs > 0) { - kwdict = _PyStack_AsDict(stack + nargs, nkwargs, func); - if (kwdict == NULL) { - Py_DECREF(args); - return NULL; - } - } - else { - kwdict = NULL; - } - - result = PyObject_Call(func, args, kwdict); - Py_DECREF(args); - Py_XDECREF(kwdict); - return result; -} - /* Positional arguments are obj followed args. */ PyObject * _PyObject_Call_Prepend(PyObject *func, -- cgit v1.2.1 From e6e25cc1f3fbcfeb94842aa82aeddfe0ba894a23 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 5 Sep 2016 11:43:18 -0700 Subject: Issue #27830: Remove unused _PyStack_AsDict() I forgot to remove this function, I made a mistake in my revert. --- Objects/abstract.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index cf69b96929..654fc0295b 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2309,40 +2309,6 @@ exit: return result; } -static PyObject * -_PyStack_AsDict(PyObject **stack, Py_ssize_t nkwargs, PyObject *func) -{ - PyObject *kwdict; - - kwdict = PyDict_New(); - if (kwdict == NULL) { - return NULL; - } - - while (--nkwargs >= 0) { - int err; - PyObject *key = *stack++; - PyObject *value = *stack++; - if (PyDict_GetItem(kwdict, key) != NULL) { - PyErr_Format(PyExc_TypeError, - "%.200s%s got multiple values " - "for keyword argument '%U'", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - key); - Py_DECREF(kwdict); - return NULL; - } - - err = PyDict_SetItem(kwdict, key, value); - if (err) { - Py_DECREF(kwdict); - return NULL; - } - } - return kwdict; -} - /* Positional arguments are obj followed args. */ PyObject * _PyObject_Call_Prepend(PyObject *func, -- cgit v1.2.1 From 0c3c0375111bde5f7586e6c951f08a0035039a39 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 6 Sep 2016 22:07:53 +0300 Subject: Issue #27078: Added BUILD_STRING opcode. Optimized f-strings evaluation. --- Objects/abstract.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 654fc0295b..d876dc5fe4 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -675,13 +675,31 @@ PyObject_Format(PyObject *obj, PyObject *format_spec) PyObject *result = NULL; _Py_IDENTIFIER(__format__); + if (format_spec != NULL && !PyUnicode_Check(format_spec)) { + PyErr_Format(PyExc_SystemError, + "Format specifier must be a string, not %.200s", + Py_TYPE(format_spec)->tp_name); + return NULL; + } + + /* Fast path for common types. */ + if (format_spec == NULL || PyUnicode_GET_LENGTH(format_spec) == 0) { + if (PyUnicode_CheckExact(obj)) { + Py_INCREF(obj); + return obj; + } + if (PyLong_CheckExact(obj)) { + return PyObject_Str(obj); + } + } + /* If no format_spec is provided, use an empty string */ if (format_spec == NULL) { empty = PyUnicode_New(0, 0); format_spec = empty; } - /* Find the (unbound!) __format__ method (a borrowed reference) */ + /* Find the (unbound!) __format__ method */ meth = _PyObject_LookupSpecial(obj, &PyId___format__); if (meth == NULL) { if (!PyErr_Occurred()) -- cgit v1.2.1 From 90854a874a441fd07a196e9e8a4a8b6c1ff0e670 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Sep 2016 12:36:44 -0700 Subject: Add _PyObject_FastCallKeywords() Issue #27830: Add _PyObject_FastCallKeywords(): avoid the creation of a temporary dictionary for keyword arguments. Other changes: * Cleanup call_function() and fast_function() (ex: rename nk to nkwargs) * Remove now useless do_call(), replaced with _PyObject_FastCallKeywords() --- Objects/abstract.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index d876dc5fe4..508fd82ac4 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2366,6 +2366,74 @@ _PyObject_Call_Prepend(PyObject *func, return result; } +static PyObject * +_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, + PyObject *func) +{ + PyObject *kwdict; + Py_ssize_t i; + + kwdict = PyDict_New(); + if (kwdict == NULL) { + return NULL; + } + + for (i=0; i < nkwargs; i++) { + int err; + PyObject *key = PyTuple_GET_ITEM(kwnames, i); + PyObject *value = *values++; + + if (PyDict_GetItem(kwdict, key) != NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s%s got multiple values " + "for keyword argument '%U'", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + key); + Py_DECREF(kwdict); + return NULL; + } + + err = PyDict_SetItem(kwdict, key, value); + if (err) { + Py_DECREF(kwdict); + return NULL; + } + } + return kwdict; +} + +PyObject * +_PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, + PyObject *kwnames) +{ + PyObject *kwdict, *result; + Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + + assert(nargs >= 0); + assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); + assert((nargs == 0 && nkwargs == 0) || stack != NULL); + + if (PyFunction_Check(func)) { + /* Fast-path: avoid temporary tuple or dict */ + return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames); + } + + if (nkwargs > 0) { + kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func); + if (kwdict == NULL) { + return NULL; + } + } + else { + kwdict = NULL; + } + + result = _PyObject_FastCallDict(func, stack, nargs, kwdict); + Py_XDECREF(kwdict); + return result; +} + static PyObject* call_function_tail(PyObject *callable, PyObject *args) { -- cgit v1.2.1 From 2615f24fb54cece9f22c5e2b1d206e8dd559631a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Sep 2016 14:07:44 -0700 Subject: Issue #27810: Add _PyCFunction_FastCallKeywords() Use _PyCFunction_FastCallKeywords() in ceval.c: it allows to remove a lot of code from ceval.c which was only used to call C functions. --- Objects/abstract.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 508fd82ac4..9de6b83344 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2366,7 +2366,7 @@ _PyObject_Call_Prepend(PyObject *func, return result; } -static PyObject * +PyObject * _PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, PyObject *func) { @@ -2415,10 +2415,13 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, assert((nargs == 0 && nkwargs == 0) || stack != NULL); if (PyFunction_Check(func)) { - /* Fast-path: avoid temporary tuple or dict */ return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames); } + if (PyCFunction_Check(func)) { + return _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames); + } + if (nkwargs > 0) { kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func); if (kwdict == NULL) { -- cgit v1.2.1 From 14e79902895c8f92b5cf80483619fac1e3832425 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Sep 2016 17:40:22 -0700 Subject: Add METH_FASTCALL calling convention Issue #27810: Add a new calling convention for C functions: PyObject* func(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames); Where args is a C array of positional arguments followed by values of keyword arguments. nargs is the number of positional arguments, kwnames are keys of keyword arguments. kwnames can be NULL. --- Objects/abstract.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 9de6b83344..f9e5009f78 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2403,6 +2403,62 @@ _PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, return kwdict; } +PyObject ** +_PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, + PyObject **p_kwnames, PyObject *func) +{ + 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)); + + nkwargs = (kwargs != NULL) ? PyDict_Size(kwargs) : 0; + if (!nkwargs) { + *p_kwnames = NULL; + return args; + } + + if ((size_t)nargs > PY_SSIZE_T_MAX / sizeof(stack[0]) - (size_t)nkwargs) { + PyErr_NoMemory(); + return NULL; + } + + stack = PyMem_Malloc((nargs + nkwargs) * sizeof(stack[0])); + if (stack == NULL) { + PyErr_NoMemory(); + return NULL; + } + + kwnames = PyTuple_New(nkwargs); + if (kwnames == NULL) { + PyMem_Free(stack); + return NULL; + } + + /* Copy position arguments (borrowed references) */ + Py_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_kwnames = kwnames; + return stack; +} + PyObject * _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, PyObject *kwnames) -- cgit v1.2.1 From e74d571e49d3fdb4389b79fa1392dd75e2acb916 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 12 Sep 2016 00:52:40 +0300 Subject: Issue #27213: Fixed different issues with reworked CALL_FUNCTION* opcodes. * BUILD_TUPLE_UNPACK and BUILD_MAP_UNPACK_WITH_CALL no longer generated with single tuple or dict. * Restored more informative error messages for incorrect var-positional and var-keyword arguments. * Removed code duplications in _PyEval_EvalCodeWithName(). * Removed redundant runtime checks and parameters in _PyStack_AsDict(). * Added a workaround and enabled previously disabled test in test_traceback. * Removed dead code from the dis module. --- Objects/abstract.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index f9e5009f78..a929be9fe6 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2367,9 +2367,9 @@ _PyObject_Call_Prepend(PyObject *func, } PyObject * -_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, - PyObject *func) +_PyStack_AsDict(PyObject **values, PyObject *kwnames) { + Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames); PyObject *kwdict; Py_ssize_t i; @@ -2378,24 +2378,12 @@ _PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, return NULL; } - for (i=0; i < nkwargs; i++) { - int err; + for (i = 0; i < nkwargs; i++) { PyObject *key = PyTuple_GET_ITEM(kwnames, i); PyObject *value = *values++; - - if (PyDict_GetItem(kwdict, key) != NULL) { - PyErr_Format(PyExc_TypeError, - "%.200s%s got multiple values " - "for keyword argument '%U'", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - key); - Py_DECREF(kwdict); - return NULL; - } - - err = PyDict_SetItem(kwdict, key, value); - if (err) { + assert(PyUnicode_CheckExact(key)); + assert(PyDict_GetItem(kwdict, key) == NULL); + if (PyDict_SetItem(kwdict, key, value)) { Py_DECREF(kwdict); return NULL; } @@ -2479,7 +2467,7 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, } if (nkwargs > 0) { - kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func); + kwdict = _PyStack_AsDict(stack + nargs, kwnames); if (kwdict == NULL) { return NULL; } -- cgit v1.2.1 From 2f777ef4d923e4c8ef9567d06d4959fc9bd3b8e9 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 12 Sep 2016 12:55:28 +0200 Subject: ssue #27213: Reintroduce checks in _PyStack_AsDict() --- Objects/abstract.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index a929be9fe6..f9e5009f78 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2367,9 +2367,9 @@ _PyObject_Call_Prepend(PyObject *func, } PyObject * -_PyStack_AsDict(PyObject **values, PyObject *kwnames) +_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, + PyObject *func) { - Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames); PyObject *kwdict; Py_ssize_t i; @@ -2378,12 +2378,24 @@ _PyStack_AsDict(PyObject **values, PyObject *kwnames) return NULL; } - for (i = 0; i < nkwargs; i++) { + for (i=0; i < nkwargs; i++) { + int err; PyObject *key = PyTuple_GET_ITEM(kwnames, i); PyObject *value = *values++; - assert(PyUnicode_CheckExact(key)); - assert(PyDict_GetItem(kwdict, key) == NULL); - if (PyDict_SetItem(kwdict, key, value)) { + + if (PyDict_GetItem(kwdict, key) != NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s%s got multiple values " + "for keyword argument '%U'", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + key); + Py_DECREF(kwdict); + return NULL; + } + + err = PyDict_SetItem(kwdict, key, value); + if (err) { Py_DECREF(kwdict); return NULL; } @@ -2467,7 +2479,7 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, } if (nkwargs > 0) { - kwdict = _PyStack_AsDict(stack + nargs, kwnames); + kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func); if (kwdict == NULL) { return NULL; } -- cgit v1.2.1 From 92011c90edeea1c883b0811039c3c9d102ccfbd9 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 12 Sep 2016 13:30:02 +0200 Subject: Revert change f860b7a775c5 Revert change "Issue #27213: Reintroduce checks in _PyStack_AsDict()", pushed by mistake. --- Objects/abstract.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index f9e5009f78..a929be9fe6 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2367,9 +2367,9 @@ _PyObject_Call_Prepend(PyObject *func, } PyObject * -_PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, - PyObject *func) +_PyStack_AsDict(PyObject **values, PyObject *kwnames) { + Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames); PyObject *kwdict; Py_ssize_t i; @@ -2378,24 +2378,12 @@ _PyStack_AsDict(PyObject **values, Py_ssize_t nkwargs, PyObject *kwnames, return NULL; } - for (i=0; i < nkwargs; i++) { - int err; + for (i = 0; i < nkwargs; i++) { PyObject *key = PyTuple_GET_ITEM(kwnames, i); PyObject *value = *values++; - - if (PyDict_GetItem(kwdict, key) != NULL) { - PyErr_Format(PyExc_TypeError, - "%.200s%s got multiple values " - "for keyword argument '%U'", - PyEval_GetFuncName(func), - PyEval_GetFuncDesc(func), - key); - Py_DECREF(kwdict); - return NULL; - } - - err = PyDict_SetItem(kwdict, key, value); - if (err) { + assert(PyUnicode_CheckExact(key)); + assert(PyDict_GetItem(kwdict, key) == NULL); + if (PyDict_SetItem(kwdict, key, value)) { Py_DECREF(kwdict); return NULL; } @@ -2479,7 +2467,7 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, } if (nkwargs > 0) { - kwdict = _PyStack_AsDict(stack + nargs, nkwargs, kwnames, func); + kwdict = _PyStack_AsDict(stack + nargs, kwnames); if (kwdict == NULL) { return NULL; } -- cgit v1.2.1 From af28671b2c1ff0e7b5c27f588b5620de8d17e676 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 12 Sep 2016 13:37:07 +0200 Subject: Document kwnames in _PyObject_FastCallKeywords() and _PyStack_AsDict() Issue #27213. --- Objects/abstract.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index a929be9fe6..17da5c999a 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2457,6 +2457,9 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, 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: these are implemented in Python/ceval.c and + _PyArg_ParseStack(). */ if (PyFunction_Check(func)) { return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames); -- cgit v1.2.1 From a516e391d34bf1983282a237d9eb60d7c2cbb82f Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Tue, 13 Sep 2016 20:22:02 +0200 Subject: Issue #28126: Replace Py_MEMCPY with memcpy(). Visual Studio can properly optimize memcpy(). --- Objects/abstract.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 17da5c999a..36f22426ac 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2353,7 +2353,7 @@ _PyObject_Call_Prepend(PyObject *func, /* use borrowed references */ stack[0] = obj; - Py_MEMCPY(&stack[1], + memcpy(&stack[1], &PyTuple_GET_ITEM(args, 0), argcount * sizeof(PyObject *)); @@ -2428,7 +2428,7 @@ _PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, } /* Copy position arguments (borrowed references) */ - Py_MEMCPY(stack, args, nargs * sizeof(stack[0])); + memcpy(stack, args, nargs * sizeof(stack[0])); kwstack = stack + nargs; pos = i = 0; -- cgit v1.2.1 From 31cb9f369965c4e70f7db1542686a0e845bb06db Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Tue, 20 Sep 2016 20:39:33 -0700 Subject: replace usage of Py_VA_COPY with the (C99) standard va_copy --- Objects/abstract.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 36f22426ac..c6c957b302 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2683,7 +2683,7 @@ objargs_mkstack(PyObject **small_stack, Py_ssize_t small_stack_size, PyObject **stack; /* Count the number of arguments */ - Py_VA_COPY(countva, va); + va_copy(countva, va); n = 0; while (1) { -- cgit v1.2.1 From dcf5141d78a919ed53f1cd8acd2542c95be2e5a6 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Wed, 21 Sep 2016 11:37:27 +0200 Subject: va_end() all va_copy()ed va_lists. --- Objects/abstract.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index c6c957b302..c1671253ec 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2702,6 +2702,7 @@ objargs_mkstack(PyObject **small_stack, Py_ssize_t small_stack_size, else { stack = PyMem_Malloc(n * sizeof(stack[0])); if (stack == NULL) { + va_end(countva); PyErr_NoMemory(); return NULL; } @@ -2710,6 +2711,7 @@ objargs_mkstack(PyObject **small_stack, Py_ssize_t small_stack_size, for (i = 0; i < n; ++i) { stack[i] = va_arg(va, PyObject *); } + va_end(countva); return stack; } -- cgit v1.2.1 From 1b72ed892900550dd552984e2f8bce1231491fc4 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Thu, 22 Sep 2016 23:39:59 -0700 Subject: remove unneeded cast --- Objects/abstract.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index c1671253ec..747eda076b 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2687,7 +2687,7 @@ objargs_mkstack(PyObject **small_stack, Py_ssize_t small_stack_size, n = 0; while (1) { - PyObject *arg = (PyObject *)va_arg(countva, PyObject *); + PyObject *arg = va_arg(countva, PyObject *); if (arg == NULL) { break; } -- cgit v1.2.1 From 3888fec2a7d9d5688a9ada16652bdbc11449869f Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 21 Oct 2016 17:09:17 +0300 Subject: Issue #28410: Added _PyErr_FormatFromCause() -- the helper for raising new exception with setting current exception as __cause__. _PyErr_FormatFromCause(exception, format, args...) is equivalent to Python raise exception(format % args) from sys.exc_info()[1] --- Objects/abstract.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index 747eda076b..f9afece815 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2198,20 +2198,18 @@ _Py_CheckFunctionResult(PyObject *func, PyObject *result, const char *where) } else { if (err_occurred) { - PyObject *exc, *val, *tb; - PyErr_Fetch(&exc, &val, &tb); - Py_DECREF(result); - if (func) - PyErr_Format(PyExc_SystemError, - "%R returned a result with an error set", - func); - else - PyErr_Format(PyExc_SystemError, - "%s returned a result with an error set", - where); - _PyErr_ChainExceptions(exc, val, tb); + if (func) { + _PyErr_FormatFromCause(PyExc_SystemError, + "%R returned a result with an error set", + func); + } + 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"); -- cgit v1.2.1 From 8fd2706e1db4130305f62e3506a985da8697b21a Mon Sep 17 00:00:00 2001 From: Martin Panter Date: Sat, 10 Dec 2016 05:32:55 +0000 Subject: Fix typos in comment and documentation --- Objects/abstract.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects/abstract.c') diff --git a/Objects/abstract.c b/Objects/abstract.c index f9afece815..d838856d45 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2325,7 +2325,7 @@ exit: return result; } -/* Positional arguments are obj followed args. */ +/* Positional arguments are obj followed by args. */ PyObject * _PyObject_Call_Prepend(PyObject *func, PyObject *obj, PyObject *args, PyObject *kwargs) -- cgit v1.2.1