diff -r 496e094f4734 -r ad4a53ed1fbf .hgignore --- a/.hgignore Thu Apr 21 00:23:08 2016 -0700 +++ b/.hgignore Fri Apr 22 12:35:07 2016 +0200 @@ -98,3 +98,5 @@ Tools/msi/obj Tools/ssl/amd64 Tools/ssl/win32 +rel/ +dbg/ diff -r 496e094f4734 -r ad4a53ed1fbf Include/Python.h --- a/Include/Python.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/Python.h Fri Apr 22 12:35:07 2016 +0200 @@ -112,6 +112,7 @@ #include "pyarena.h" #include "modsupport.h" +#include "pystack.h" #include "pythonrun.h" #include "pylifecycle.h" #include "ceval.h" diff -r 496e094f4734 -r ad4a53ed1fbf Include/abstract.h --- a/Include/abstract.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/abstract.h Fri Apr 22 12:35:07 2016 +0200 @@ -266,6 +266,13 @@ PyAPI_FUNC(PyObject *) PyObject_Call(PyObject *callable_object, PyObject *args, PyObject *kw); + PyAPI_FUNC(PyObject *) _PyObject_FastCall(PyObject *callable_object, + PyObject **stack, + int na, int nk); + + PyAPI_FUNC(PyObject *) PyObject_CallNoArg(PyObject *callable_object); + PyAPI_FUNC(PyObject *) PyObject_CallArg1(PyObject *callable_object, PyObject *arg); + #ifndef Py_LIMITED_API PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *func, PyObject *result, diff -r 496e094f4734 -r ad4a53ed1fbf Include/descrobject.h --- a/Include/descrobject.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/descrobject.h Fri Apr 22 12:35:07 2016 +0200 @@ -20,6 +20,9 @@ typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args, void *wrapped); +typedef PyObject *(*fastwrapperfunc)(PyObject *self, PyObject **stack, int na, + void *wrapped); + typedef PyObject *(*wrapperfunc_kwds)(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds); @@ -31,6 +34,7 @@ char *doc; int flags; PyObject *name_strobj; + fastwrapperfunc fastwrapper; }; /* Flags for above struct */ diff -r 496e094f4734 -r ad4a53ed1fbf Include/funcobject.h --- a/Include/funcobject.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/funcobject.h Fri Apr 22 12:35:07 2016 +0200 @@ -58,6 +58,12 @@ PyAPI_FUNC(PyObject *) PyFunction_GetAnnotations(PyObject *); PyAPI_FUNC(int) PyFunction_SetAnnotations(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) _PyFunction_FastCall( + PyObject *func, + PyObject **stack, + int na, + int nk); + /* Macros for direct access to these values. Type checks are *not* done, so use with care. */ #define PyFunction_GET_CODE(func) \ diff -r 496e094f4734 -r ad4a53ed1fbf Include/methodobject.h --- a/Include/methodobject.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/methodobject.h Fri Apr 22 12:35:07 2016 +0200 @@ -71,6 +71,8 @@ #define METH_COEXIST 0x0040 +#define METH_FASTCALL 0x0080 + #ifndef Py_LIMITED_API typedef struct { PyObject_HEAD diff -r 496e094f4734 -r ad4a53ed1fbf Include/modsupport.h --- a/Include/modsupport.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/modsupport.h Fri Apr 22 12:35:07 2016 +0200 @@ -44,6 +44,13 @@ #endif PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list); +PyAPI_FUNC(PyObject**) Py_VaBuildStack( + PyObject **small_stack, Py_ssize_t stack_size, + const char *format, va_list va, int *p_na); +PyAPI_FUNC(PyObject **) _Py_VaBuildStack_SizeT( + PyObject **small_stack, Py_ssize_t stack_size, + const char *, va_list, int *); + PyAPI_FUNC(int) PyModule_AddObject(PyObject *, const char *, PyObject *); PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long); PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char *); diff -r 496e094f4734 -r ad4a53ed1fbf Include/object.h --- a/Include/object.h Thu Apr 21 00:23:08 2016 -0700 +++ b/Include/object.h Fri Apr 22 12:35:07 2016 +0200 @@ -336,6 +336,7 @@ typedef int (*initproc)(PyObject *, PyObject *, PyObject *); typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *); typedef PyObject *(*allocfunc)(struct _typeobject *, Py_ssize_t); +typedef PyObject* (*pyfastfunc) (PyObject *self, PyObject **stack, int na, int nk); #ifdef Py_LIMITED_API typedef struct _typeobject PyTypeObject; /* opaque */ @@ -420,6 +421,7 @@ unsigned int tp_version_tag; destructor tp_finalize; + pyfastfunc tp_fastcall; #ifdef COUNT_ALLOCS /* these must be last and never explicitly initialized */ diff -r 496e094f4734 -r ad4a53ed1fbf Include/pystack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Include/pystack.h Fri Apr 22 12:35:07 2016 +0200 @@ -0,0 +1,49 @@ +#ifndef Py_STACK_H +#define Py_STACK_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Number of PyObject* allocated on the C stack for small Python stack */ +#ifndef Py_DEBUG + /* 10 positional parameters or 5 (key, value) pairs for keyword parameters. + 40 bytes on 32-bit or 80 bytes on 64-bit. */ +# define _PyStack_SIZE 10 +#else + /* In debug mode, only use the buffer allocated on stack for 0, 1 or 2 + objects, to test buffer allocated on the heap. */ +# define _PyStack_SIZE 2 +#endif + +PyAPI_FUNC(PyObject**) _PyStack_Alloc(Py_ssize_t na); + +#define _PyStack_ALLOC(small_stack, count) \ + (((count) <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) \ + ? (small_stack) \ + : _PyStack_Alloc(count)) + +PyAPI_FUNC(void) _PyStack_Free(PyObject **stack, + PyObject **small_stack, + Py_ssize_t na, Py_ssize_t nk); + +PyAPI_FUNC(PyObject**) _PyStack_FromArgs( + PyObject **small_stack, Py_ssize_t stack_size, + PyObject *args, PyObject *kwargs, + int *p_na, int *p_nk); + +PyAPI_FUNC(int) _PyStack_AsArgs(PyObject **stack, + Py_ssize_t na, Py_ssize_t nk, + PyObject *func, + PyObject **args, PyObject **kwargs); + +PyAPI_FUNC(int) _PyStack_CheckArgs(PyObject **stack, + Py_ssize_t na, Py_ssize_t nk, + const char *func_name, + Py_ssize_t min_na, Py_ssize_t max_na); + +PyAPI_FUNC(int) _PyStack_CheckArgsKeywords(PyObject **stack, + Py_ssize_t na, Py_ssize_t nk, + const char *func_name, + Py_ssize_t min_na, Py_ssize_t max_na); + +#endif /* !Py_STACK_H */ diff -r 496e094f4734 -r ad4a53ed1fbf Lib/test/test_sys.py --- a/Lib/test/test_sys.py Thu Apr 21 00:23:08 2016 -0700 +++ b/Lib/test/test_sys.py Fri Apr 22 12:35:07 2016 +0200 @@ -1083,9 +1083,9 @@ check((1,2,3), vsize('') + 3*self.P) # type # static type: PyTypeObject - s = vsize('P2n15Pl4Pn9Pn11PIP') + s = vsize('P2n15Pl4Pn9Pn11PIPP') check(int, s) - s = vsize('P2n15Pl4Pn9Pn11PIP' # PyTypeObject + s = vsize('P2n15Pl4Pn9Pn11PIPP' # PyTypeObject '3P' # PyAsyncMethods '36P' # PyNumberMethods '3P' # PyMappingMethods diff -r 496e094f4734 -r ad4a53ed1fbf Makefile.pre.in --- a/Makefile.pre.in Thu Apr 21 00:23:08 2016 -0700 +++ b/Makefile.pre.in Fri Apr 22 12:35:07 2016 +0200 @@ -306,14 +306,14 @@ PARSER_OBJS= $(POBJS) Parser/myreadline.o Parser/parsetok.o Parser/tokenizer.o PGSRCS= \ - Objects/obmalloc.c \ - Python/dynamic_annotations.c \ - Python/mysnprintf.c \ - Python/pyctype.c \ - Parser/tokenizer_pgen.c \ - Parser/printgrammar.c \ - Parser/parsetok_pgen.c \ - Parser/pgenmain.c + $(srcdir)/Objects/obmalloc.c \ + $(srcdir)/Python/dynamic_annotations.c \ + $(srcdir)/Python/mysnprintf.c \ + $(srcdir)/Python/pyctype.c \ + $(srcdir)/Parser/tokenizer_pgen.c \ + $(srcdir)/Parser/printgrammar.c \ + $(srcdir)/Parser/parsetok_pgen.c \ + $(srcdir)/Parser/pgenmain.c PGOBJS= \ Objects/obmalloc.o \ @@ -412,6 +412,7 @@ Python/dtoa.o \ Python/formatter_unicode.o \ Python/fileutils.o \ + Python/pystack.o \ Python/$(DYNLOADFILE) \ $(LIBOBJS) \ $(MACHDEP_OBJS) \ diff -r 496e094f4734 -r ad4a53ed1fbf Modules/_operator.c --- a/Modules/_operator.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Modules/_operator.c Fri Apr 22 12:35:07 2016 +0200 @@ -455,13 +455,17 @@ } static PyObject * -itemgetter_call(itemgetterobject *ig, PyObject *args, PyObject *kw) +itemgetter_fastcall(PyObject *self, PyObject **stack, int na, int nk) { + itemgetterobject *ig = (itemgetterobject *)self; PyObject *obj, *result; Py_ssize_t i, nitems=ig->nitems; - if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &obj)) + if (na != 1 ||nk != 0) { + PyErr_SetNone(PyExc_TypeError); return NULL; + } + obj = stack[0]; if (nitems == 1) return PyObject_GetItem(obj, ig->item); @@ -486,6 +490,17 @@ } static PyObject * +itemgetter_call(PyObject *self, PyObject *args, PyObject *kw) +{ + PyObject *obj; + + if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &obj)) + return NULL; + return itemgetter_fastcall(self, &obj, 1, 0); +} + + +static PyObject * itemgetter_repr(itemgetterobject *ig) { PyObject *repr; @@ -568,6 +583,16 @@ 0, /* tp_alloc */ itemgetter_new, /* tp_new */ 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + itemgetter_fastcall, /* tp_fastcall */ }; diff -r 496e094f4734 -r ad4a53ed1fbf Objects/abstract.c --- a/Objects/abstract.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/abstract.c Fri Apr 22 12:35:07 2016 +0200 @@ -2093,7 +2093,12 @@ PyObject * PyObject_CallObject(PyObject *o, PyObject *a) { - return PyEval_CallObjectWithKeywords(o, a, NULL); + if (a != NULL) { + return PyEval_CallObjectWithKeywords(o, a, NULL); + } + else { + return PyObject_CallNoArg(o); + } } PyObject* @@ -2147,6 +2152,27 @@ } PyObject * +_PyObject_FastCall_FromArgs(PyObject *func, PyObject *args, PyObject *kwargs) +{ + PyObject* small_stack[_PyStack_SIZE]; + PyObject **stack; + int na, nk; + PyObject *result; + + stack = _PyStack_FromArgs(small_stack, Py_ARRAY_LENGTH(small_stack), + args, kwargs, + &na, &nk); + if (stack == NULL) { + return NULL; + } + + result = _PyObject_FastCall(func, stack, na, nk); + _PyStack_Free(stack, small_stack, na, nk); + + return result; +} + +PyObject * PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) { ternaryfunc call; @@ -2164,6 +2190,13 @@ return NULL; } + if (Py_TYPE(func)->tp_fastcall != NULL && !PyCFunction_Check(func)) { + /* if tp_fastcall is defined, prefer it over call, + but don't use this path for PyCFunction_Check since this one + may have to recreate new tuple/dict. */ + return _PyObject_FastCall_FromArgs(func, arg, kw); + } + if (Py_EnterRecursiveCall(" while calling a Python object")) return NULL; @@ -2174,101 +2207,145 @@ return _Py_CheckFunctionResult(func, result, NULL); } -static PyObject* -call_function_tail(PyObject *callable, PyObject *args) +PyObject * +_PyObject_FastCall(PyObject *func, PyObject **stack, int na, int nk) { - PyObject *retval; - - if (args == NULL) + PyObject* (*fastcall) (PyObject *self, PyObject **stack, int na, int nk); + PyObject *args, *kwargs, *res; + + /* _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); + if (na < 0 || nk < 0 || stack == NULL) { + PyErr_BadInternalCall(); return NULL; - - if (!PyTuple_Check(args)) { - PyObject *a; - - a = PyTuple_New(1); - if (a == NULL) { - Py_DECREF(args); + } + + fastcall = Py_TYPE(func)->tp_fastcall; + if (fastcall != NULL) { + if (Py_EnterRecursiveCall(" while calling a Python object")) return NULL; - } - PyTuple_SET_ITEM(a, 0, args); - args = a; + + res = fastcall(func, stack, na, nk); + + Py_LeaveRecursiveCall(); + + return res; } - retval = PyObject_Call(callable, args, NULL); - + + /* Slow-path: build a temporary tuple and maybe also a temporary dict */ + + if (_PyStack_AsArgs(stack, na, nk, func, &args, &kwargs) < 0) { + return NULL; + } + + res = PyObject_Call(func, args, kwargs); Py_DECREF(args); - - return retval; + Py_XDECREF(kwargs); + return res; +} + +PyObject * +PyObject_CallNoArg(PyObject *func) +{ + /* FIXME: avoid this unused stack variable and allow NULL as stack */ + PyObject *stack[1]; + return _PyObject_FastCall(func, stack, 0, 0); +} + +PyObject * +PyObject_CallArg1(PyObject *func, PyObject *arg) +{ + return _PyObject_FastCall(func, &arg, 1, 0); } PyObject * PyObject_CallFunction(PyObject *callable, const char *format, ...) { va_list va; - PyObject *args; - - if (callable == NULL) + PyObject **stack; + int na; + PyObject *result; + PyObject* small_stack[_PyStack_SIZE]; + + if (callable == NULL) { return null_error(); - - if (format && *format) { - va_start(va, format); - args = Py_VaBuildValue(format, va); - va_end(va); } - else - args = PyTuple_New(0); - if (args == NULL) + + va_start(va, format); + stack = Py_VaBuildStack(small_stack, Py_ARRAY_LENGTH(small_stack), + format, va, &na); + va_end(va); + + if (stack == NULL) { return NULL; - - return call_function_tail(callable, args); + } + + result = _PyObject_FastCall(callable, stack, na, 0); + _PyStack_Free(stack, small_stack, na, 0); + return result; } PyObject * _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) { va_list va; - PyObject *args; + PyObject **stack; + int na; + PyObject *result; + PyObject* small_stack[_PyStack_SIZE]; if (callable == NULL) return null_error(); - if (format && *format) { - va_start(va, format); - args = _Py_VaBuildValue_SizeT(format, va); - va_end(va); + va_start(va, format); + stack = _Py_VaBuildStack_SizeT(small_stack, Py_ARRAY_LENGTH(small_stack), + format, va, &na); + va_end(va); + + if (stack == NULL) { + return NULL; } - else - args = PyTuple_New(0); - - return call_function_tail(callable, args); + + result = _PyObject_FastCall(callable, stack, na, 0); + _PyStack_Free(stack, small_stack, na, 0); + return result; } static PyObject* callmethod(PyObject* func, const char *format, va_list va, int is_size_t) { - PyObject *retval = NULL; - PyObject *args; + PyObject **stack; + int na; + PyObject *result; + PyObject* small_stack[_PyStack_SIZE]; if (!PyCallable_Check(func)) { type_error("attribute of type '%.200s' is not callable", func); - goto exit; + Py_DECREF(func); + return NULL; } - if (format && *format) { - if (is_size_t) - args = _Py_VaBuildValue_SizeT(format, va); - else - args = Py_VaBuildValue(format, va); + if (is_size_t) { + stack = _Py_VaBuildStack_SizeT(small_stack, + Py_ARRAY_LENGTH(small_stack), + format, va, &na); } - else - args = PyTuple_New(0); - - retval = call_function_tail(func, args); - - exit: - /* args gets consumed in call_function_tail */ - Py_XDECREF(func); - - return retval; + else { + stack = Py_VaBuildStack(small_stack, Py_ARRAY_LENGTH(small_stack), + format, va, &na); + } + if (stack == NULL) { + return NULL; + } + + result = _PyObject_FastCall(func, stack, na, 0); + Py_DECREF(func); + _PyStack_Free(stack, small_stack, na, 0); + return result; } PyObject * @@ -2353,104 +2430,135 @@ return retval; } -static PyObject * -objargs_mktuple(va_list va) +Py_LOCAL_INLINE(Py_ssize_t) +objargs_count(va_list va) { - int i, n = 0; + Py_ssize_t na; va_list countva; - PyObject *result, *tmp; - - 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); - } + PyObject *obj; + + Py_VA_COPY(countva, va); + + na = 0; + while (1) { + obj = (PyObject *)va_arg(countva, PyObject *); + if (obj == NULL) + break; + na++; } - return result; + return na; +} + +Py_LOCAL_INLINE(void) +objargs_fill_stack(va_list va, int na, PyObject **stack) +{ + Py_ssize_t i; + PyObject *obj; + + for (i = 0; i < na; ++i) { + obj = (PyObject *)va_arg(va, PyObject *); + /* FIXME: does it matter to keep a strong reference? */ + Py_INCREF(obj); + stack[i] = obj; + } } PyObject * PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) { - PyObject *args, *tmp; + PyObject *func; va_list vargs; + Py_ssize_t na; + PyObject **stack; + PyObject *result; + PyObject* small_stack[_PyStack_SIZE]; if (callable == NULL || name == NULL) return null_error(); - callable = PyObject_GetAttr(callable, name); - if (callable == NULL) - return NULL; - - /* count the args */ - va_start(vargs, name); - args = objargs_mktuple(vargs); - va_end(vargs); - if (args == NULL) { - Py_DECREF(callable); + func = PyObject_GetAttr(callable, name); + if (func == NULL) { return NULL; } - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); - Py_DECREF(callable); - - return tmp; + + /* FIXME: factorize the following duplicated block */ + va_start(vargs, name); + na = objargs_count(vargs); + stack = _PyStack_ALLOC(small_stack, na); + if (stack == NULL) { + va_end(vargs); + return NULL; + } + objargs_fill_stack(vargs, na, stack); + va_end(vargs); + + result = _PyObject_FastCall(func, stack, na, 0); + Py_DECREF(func); + _PyStack_Free(stack, small_stack, na, 0); + return result; } PyObject * _PyObject_CallMethodIdObjArgs(PyObject *callable, struct _Py_Identifier *name, ...) { - PyObject *args, *tmp; + PyObject *func; va_list vargs; + Py_ssize_t na; + PyObject **stack; + PyObject *result; + PyObject* small_stack[_PyStack_SIZE]; if (callable == NULL || name == NULL) return null_error(); - callable = _PyObject_GetAttrId(callable, name); - if (callable == NULL) - return NULL; - - /* count the args */ - va_start(vargs, name); - args = objargs_mktuple(vargs); - va_end(vargs); - if (args == NULL) { - Py_DECREF(callable); + func = _PyObject_GetAttrId(callable, name); + if (func == NULL) { return NULL; } - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); - Py_DECREF(callable); - - return tmp; + + va_start(vargs, name); + na = objargs_count(vargs); + stack = _PyStack_ALLOC(small_stack, na); + if (stack == NULL) { + va_end(vargs); + return NULL; + } + objargs_fill_stack(vargs, na, stack); + va_end(vargs); + + result = _PyObject_FastCall(func, stack, na, 0); + Py_DECREF(func); + _PyStack_Free(stack, small_stack, na, 0); + return result; } PyObject * PyObject_CallFunctionObjArgs(PyObject *callable, ...) { - PyObject *args, *tmp; va_list vargs; - - if (callable == NULL) + Py_ssize_t na; + PyObject **stack; + PyObject *result; + PyObject* small_stack[_PyStack_SIZE]; + + if (callable == NULL) { return null_error(); - - /* count the args */ + } + va_start(vargs, callable); - args = objargs_mktuple(vargs); + na = objargs_count(vargs); + stack = _PyStack_ALLOC(small_stack, na); + if (stack == NULL) { + va_end(vargs); + return NULL; + } + objargs_fill_stack(vargs, na, stack); va_end(vargs); - if (args == NULL) - return NULL; - tmp = PyObject_Call(callable, args, NULL); - Py_DECREF(args); - - return tmp; + + result = _PyObject_FastCall(callable, stack, na, 0); + _PyStack_Free(stack, small_stack, na, 0); + return result; } diff -r 496e094f4734 -r ad4a53ed1fbf Objects/bytesobject.c --- a/Objects/bytesobject.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/bytesobject.c Fri Apr 22 12:35:07 2016 +0200 @@ -548,7 +548,7 @@ /* does it support __bytes__? */ func = _PyObject_LookupSpecial(v, &PyId___bytes__); if (func != NULL) { - result = PyObject_CallFunctionObjArgs(func, NULL); + result = PyObject_CallNoArg(func); Py_DECREF(func); if (result == NULL) return NULL; diff -r 496e094f4734 -r ad4a53ed1fbf Objects/classobject.c --- a/Objects/classobject.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/classobject.c Fri Apr 22 12:35:07 2016 +0200 @@ -306,33 +306,79 @@ { PyObject *self = PyMethod_GET_SELF(func); PyObject *result; + Py_ssize_t argcount; + PyObject *newarg; + int i; func = PyMethod_GET_FUNCTION(func); if (self == NULL) { PyErr_BadInternalCall(); return NULL; } - else { - Py_ssize_t argcount = PyTuple_Size(arg); - PyObject *newarg = PyTuple_New(argcount + 1); - int i; - if (newarg == NULL) - return NULL; - Py_INCREF(self); - PyTuple_SET_ITEM(newarg, 0, self); - for (i = 0; i < argcount; i++) { - PyObject *v = PyTuple_GET_ITEM(arg, i); - Py_XINCREF(v); - PyTuple_SET_ITEM(newarg, i+1, v); - } - arg = newarg; + + argcount = PyTuple_Size(arg); + if (!argcount && !kw) { + return _PyObject_FastCall((PyObject *)func, &self, 1, 0); } + + newarg = PyTuple_New(argcount + 1); + + if (newarg == NULL) + return NULL; + Py_INCREF(self); + PyTuple_SET_ITEM(newarg, 0, self); + for (i = 0; i < argcount; i++) { + PyObject *v = PyTuple_GET_ITEM(arg, i); + Py_XINCREF(v); + PyTuple_SET_ITEM(newarg, i+1, v); + } + arg = newarg; + result = PyObject_Call((PyObject *)func, arg, kw); Py_DECREF(arg); return result; } static PyObject * +method_fastcall(PyObject *func, PyObject **stack, int na, int nk) +{ + PyObject* small_stack[_PyStack_SIZE]; + const int n = na + nk * 2; + PyObject *self = PyMethod_GET_SELF(func); + PyObject *result; + int i; + PyObject **stack2; + + func = PyMethod_GET_FUNCTION(func); + if (self == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + + if (!na && !nk) { + return _PyObject_FastCall((PyObject *)func, &self, 1, 0); + } + + stack2 = _PyStack_ALLOC(small_stack, 1 + n); + if (stack2 == NULL) { + return PyErr_NoMemory(); + } + + Py_INCREF(self); + stack2[0] = self; + + for (i = 0; i < n; i++) { + PyObject *obj = stack[i]; + Py_INCREF(obj); + stack2[i+1] = obj; + } + + result = _PyObject_FastCall((PyObject *)func, stack2, 1 + na, nk); + _PyStack_Free(stack2, small_stack, 1 + n, 0); + return result; +} + +static PyObject * method_descr_get(PyObject *meth, PyObject *obj, PyObject *cls) { /* Don't rebind an already bound method of a class that's not a base @@ -366,12 +412,12 @@ method_getattro, /* tp_getattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ method_doc, /* tp_doc */ (traverseproc)method_traverse, /* tp_traverse */ 0, /* tp_clear */ method_richcompare, /* tp_richcompare */ - offsetof(PyMethodObject, im_weakreflist), /* tp_weaklistoffset */ + offsetof(PyMethodObject, im_weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ method_methods, /* tp_methods */ @@ -385,6 +431,17 @@ 0, /* tp_init */ 0, /* tp_alloc */ method_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + method_fastcall, /* tp_fastcall */ }; /* Clear out the free list */ diff -r 496e094f4734 -r ad4a53ed1fbf Objects/descrobject.c --- a/Objects/descrobject.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/descrobject.c Fri Apr 22 12:35:07 2016 +0200 @@ -227,6 +227,7 @@ return NULL; } self = PyTuple_GET_ITEM(args, 0); + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), (PyObject *)PyDescr_TYPE(descr))) { PyErr_Format(PyExc_TypeError, @@ -254,6 +255,42 @@ } static PyObject * +methoddescr_fastcall(PyMethodDescrObject *descr, PyObject **stack, int argc, int nk) +{ + PyObject *self, *func, *result; + + /* Make sure that the first argument is acceptable as 'self' */ + if (argc < 1) { + PyErr_Format(PyExc_TypeError, + "descriptor '%V' of '%.100s' " + "object needs an argument", + descr_name((PyDescrObject *)descr), "?", + PyDescr_TYPE(descr)->tp_name); + return NULL; + } + self = stack[0]; + + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)PyDescr_TYPE(descr))) { + PyErr_Format(PyExc_TypeError, + "descriptor '%V' " + "requires a '%.100s' object " + "but received a '%.100s'", + descr_name((PyDescrObject *)descr), "?", + PyDescr_TYPE(descr)->tp_name, + self->ob_type->tp_name); + return NULL; + } + + func = PyCFunction_NewEx(descr->d_method, self, NULL); + if (func == NULL) + return NULL; + result = _PyObject_FastCall(func, stack + 1, argc - 1, nk); + Py_DECREF(func); + return result; +} + +static PyObject * classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) { @@ -307,15 +344,9 @@ } static PyObject * -wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) +wrapperdescr_prepare_call(PyWrapperDescrObject *descr, PyObject *self) { - Py_ssize_t argc; - PyObject *self, *func, *result; - - /* Make sure that the first argument is acceptable as 'self' */ - assert(PyTuple_Check(args)); - argc = PyTuple_GET_SIZE(args); - if (argc < 1) { + if (self == NULL) { PyErr_Format(PyExc_TypeError, "descriptor '%V' of '%.100s' " "object needs an argument", @@ -323,7 +354,7 @@ PyDescr_TYPE(descr)->tp_name); return NULL; } - self = PyTuple_GET_ITEM(args, 0); + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), (PyObject *)PyDescr_TYPE(descr))) { PyErr_Format(PyExc_TypeError, @@ -336,9 +367,29 @@ return NULL; } - func = PyWrapper_New((PyObject *)descr, self); - if (func == NULL) + return PyWrapper_New((PyObject *)descr, self); +} + +static PyObject * +wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) +{ + Py_ssize_t argc; + PyObject *self, *func, *result; + + /* Make sure that the first argument is acceptable as 'self' */ + assert(PyTuple_Check(args)); + argc = PyTuple_GET_SIZE(args); + if (argc >= 1) { + self = PyTuple_GET_ITEM(args, 0); + } + else { + self = NULL; + } + func = wrapperdescr_prepare_call(descr, self); + if (func == NULL) { return NULL; + } + args = PyTuple_GetSlice(args, 1, argc); if (args == NULL) { Py_DECREF(func); @@ -351,6 +402,28 @@ } static PyObject * +wrapperdescr_fastcall(PyWrapperDescrObject *descr, PyObject **stack, int argc, int nk) +{ + PyObject *self, *func, *result; + + /* Make sure that the first argument is acceptable as 'self' */ + if (argc >= 1) { + self = stack[0]; + } + else { + self = NULL; + } + func = wrapperdescr_prepare_call(descr, self); + if (func == NULL) { + return NULL; + } + + result = _PyObject_FastCall(func, stack + 1, argc - 1, nk); + Py_DECREF(func); + return result; +} + +static PyObject * method_get_doc(PyMethodDescrObject *descr, void *closure) { return _PyType_GetDocFromInternalDoc(descr->d_method->ml_name, descr->d_method->ml_doc); @@ -525,6 +598,21 @@ 0, /* tp_dict */ (descrgetfunc)method_get, /* tp_descr_get */ 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + (pyfastfunc)methoddescr_fastcall, /* tp_fastcall */ }; /* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */ @@ -674,6 +762,21 @@ 0, /* tp_dict */ (descrgetfunc)wrapperdescr_get, /* tp_descr_get */ 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + (pyfastfunc)wrapperdescr_fastcall, /* tp_fastcall */ }; static PyDescrObject * @@ -1178,7 +1281,9 @@ static PyObject * wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds) { - wrapperfunc wrapper = wp->descr->d_base->wrapper; + /* FIXME: reimplement this using fastwrapper to simplify the code? */ + struct wrapperbase *d_base = wp->descr->d_base; + wrapperfunc wrapper = d_base->wrapper; PyObject *self = wp->self; if (wp->descr->d_base->flags & PyWrapperFlag_KEYWORDS) { @@ -1195,6 +1300,52 @@ return (*wrapper)(self, args, wp->descr->d_wrapped); } +static PyObject * +wrapper_fastcall(wrapperobject *wp, PyObject **stack, int na, int nk) +{ + struct wrapperbase *d_base = wp->descr->d_base; + fastwrapperfunc fastwrapper; + PyObject *self = wp->self; + + if (wp->descr->d_base->flags & PyWrapperFlag_KEYWORDS) { + wrapperfunc_kwds wrapperkw = (wrapperfunc_kwds)d_base->wrapper; + PyObject *args, *kwargs, *result; + + if (_PyStack_AsArgs(stack, na, nk, self, &args, &kwargs) < 0) { + return NULL; + } + + result = (*wrapperkw)(self, args, wp->descr->d_wrapped, kwargs); + Py_DECREF(args); + Py_XDECREF(kwargs); + return result; + } + + if (nk) { + PyErr_Format(PyExc_TypeError, + "wrapper %s doesn't take keyword arguments", + wp->descr->d_base->name); + return NULL; + } + + fastwrapper = d_base->fastwrapper; + if (!fastwrapper) { + wrapperfunc wrapper = d_base->wrapper; + PyObject *args, *kwargs, *result; + + if (_PyStack_AsArgs(stack, na, 0, self, &args, &kwargs) < 0) { + return NULL; + } + assert(kwargs == NULL); + + result = (*wrapper)(self, args, wp->descr->d_wrapped); + Py_DECREF(args); + return result; + } + + return (*fastwrapper)(self, stack, na, wp->descr->d_wrapped); +} + static int wrapper_traverse(PyObject *self, visitproc visit, void *arg) { @@ -1240,6 +1391,21 @@ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + (pyfastfunc)wrapper_fastcall, /* tp_fastcall */ }; PyObject * @@ -1372,9 +1538,6 @@ static PyObject * property_descr_get(PyObject *self, PyObject *obj, PyObject *type) { - static PyObject * volatile cached_args = NULL; - PyObject *args; - PyObject *ret; propertyobject *gs = (propertyobject *)self; if (obj == NULL || obj == Py_None) { @@ -1385,29 +1548,8 @@ PyErr_SetString(PyExc_AttributeError, "unreadable attribute"); return NULL; } - args = cached_args; - if (!args || Py_REFCNT(args) != 1) { - Py_CLEAR(cached_args); - if (!(cached_args = args = PyTuple_New(1))) - return NULL; - } - Py_INCREF(args); - assert (Py_REFCNT(args) == 2); - Py_INCREF(obj); - PyTuple_SET_ITEM(args, 0, obj); - ret = PyObject_Call(gs->prop_get, args, NULL); - if (args == cached_args) { - if (Py_REFCNT(args) == 2) { - obj = PyTuple_GET_ITEM(args, 0); - PyTuple_SET_ITEM(args, 0, NULL); - Py_XDECREF(obj); - } - else { - Py_CLEAR(cached_args); - } - } - Py_DECREF(args); - return ret; + + return _PyObject_FastCall(gs->prop_get, &obj, 1, 0); } static int @@ -1428,7 +1570,7 @@ return -1; } if (value == NULL) - res = PyObject_CallFunctionObjArgs(func, obj, NULL); + res = PyObject_CallArg1(func, obj); else res = PyObject_CallFunctionObjArgs(func, obj, value, NULL); if (res == NULL) @@ -1467,7 +1609,7 @@ doc = pold->prop_doc ? pold->prop_doc : Py_None; } - new = PyObject_CallFunction(type, "OOOO", get, set, del, doc); + new = PyObject_CallFunctionObjArgs(type, get, set, del, doc, NULL); Py_DECREF(type); if (new == NULL) return NULL; diff -r 496e094f4734 -r ad4a53ed1fbf Objects/funcobject.c --- a/Objects/funcobject.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/funcobject.c Fri Apr 22 12:35:07 2016 +0200 @@ -563,6 +563,12 @@ } static PyObject * +function_fastcall(PyObject *func, PyObject **stack, int na, int nk) +{ + return _PyFunction_FastCall(func, stack, na, nk); +} + +static PyObject * function_call(PyObject *func, PyObject *arg, PyObject *kw) { PyObject *result; @@ -664,6 +670,17 @@ 0, /* tp_init */ 0, /* tp_alloc */ func_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + function_fastcall, /* tp_fastcall */ }; diff -r 496e094f4734 -r ad4a53ed1fbf Objects/listobject.c --- a/Objects/listobject.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/listobject.c Fri Apr 22 12:35:07 2016 +0200 @@ -1962,8 +1962,7 @@ } for (i = 0; i < saved_ob_size ; i++) { - keys[i] = PyObject_CallFunctionObjArgs(keyfunc, saved_ob_item[i], - NULL); + keys[i] = PyObject_CallArg1(keyfunc, saved_ob_item[i]); if (keys[i] == NULL) { for (i=i-1 ; i>=0 ; i--) Py_DECREF(keys[i]); diff -r 496e094f4734 -r ad4a53ed1fbf Objects/methodobject.c --- a/Objects/methodobject.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/methodobject.c Fri Apr 22 12:35:07 2016 +0200 @@ -77,6 +77,27 @@ return PyCFunction_GET_FLAGS(op); } +static PyObject * +PyCFunction_FastCall_FromArgs(PyObject *func, PyObject *args, PyObject *kwds) +{ + PyObject* small_stack[_PyStack_SIZE]; + PyObject **stack; + int na, nk; + pyfastfunc meth = (pyfastfunc)PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + PyObject *result; + + assert((PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)) == METH_FASTCALL); + + stack = _PyStack_FromArgs(small_stack, Py_ARRAY_LENGTH(small_stack), + args, kwds, + &na, &nk); + + result = (*meth)(self, stack, na, nk); + _PyStack_Free(stack, small_stack, na, nk); + return result; +} + PyObject * PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) { @@ -97,6 +118,9 @@ if (flags == (METH_VARARGS | METH_KEYWORDS)) { res = (*(PyCFunctionWithKeywords)meth)(self, args, kwds); } + else if (flags == METH_FASTCALL) { + res = PyCFunction_FastCall_FromArgs(func, args, kwds); + } else { if (kwds != NULL && PyDict_Size(kwds) != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", @@ -145,6 +169,58 @@ return _Py_CheckFunctionResult(func, res, NULL); } +static PyObject * +PyCFunction_FastCall(PyObject *self, PyObject **stack, int na, int nk) +{ + PyCFunctionObject* func = (PyCFunctionObject*)self; + PyObject *args, *kwargs, *res; + int flags; + + flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + + switch (flags) + { + case METH_FASTCALL: + { + PyObject *self = PyCFunction_GET_SELF(func); + pyfastfunc meth = (pyfastfunc)PyCFunction_GET_FUNCTION(func); + return (*meth)(self, stack, na, nk); + } + break; + + case METH_NOARGS: + if (na == 0 && nk == 0) { + PyObject *self = PyCFunction_GET_SELF(func); + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + return (*meth)(self, NULL); + } + break; + + case METH_O: + if (na == 1 && nk == 0) { + PyObject *self = PyCFunction_GET_SELF(func); + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *arg = stack[0]; + return (*meth)(self, arg); + } + break; + + default: + break; + } + + /* Slow-path */ + + if (_PyStack_AsArgs(stack, na, nk, self, &args, &kwargs) < 0) { + return NULL; + } + + res = PyCFunction_Call(self, args, kwargs); + Py_DECREF(args); + Py_XDECREF(kwargs); + return res; +} + /* Methods (the standard built-in methods, that is) */ static void @@ -367,6 +443,23 @@ meth_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + (pyfastfunc)PyCFunction_FastCall, /* tp_call */ }; /* Clear out the free list */ diff -r 496e094f4734 -r ad4a53ed1fbf Objects/object.c --- a/Objects/object.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/object.c Fri Apr 22 12:35:07 2016 +0200 @@ -593,7 +593,7 @@ func = _PyObject_LookupSpecial(v, &PyId___bytes__); if (func != NULL) { - result = PyObject_CallFunctionObjArgs(func, NULL); + result = PyObject_CallNoArg(func); Py_DECREF(func); if (result == NULL) return NULL; @@ -1311,7 +1311,7 @@ return NULL; } /* use __dir__ */ - result = PyObject_CallFunctionObjArgs(dirfunc, NULL); + result = PyObject_CallNoArg(dirfunc); Py_DECREF(dirfunc); if (result == NULL) return NULL; diff -r 496e094f4734 -r ad4a53ed1fbf Objects/typeobject.c --- a/Objects/typeobject.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/typeobject.c Fri Apr 22 12:35:07 2016 +0200 @@ -1419,73 +1419,83 @@ as lookup_method to cache the interned name string object. */ static PyObject * -call_method(PyObject *o, _Py_Identifier *nameid, const char *format, ...) -{ - va_list va; - PyObject *args, *func = 0, *retval; - va_start(va, format); +get_method(PyObject *o, _Py_Identifier *nameid) +{ + PyObject *func; func = lookup_maybe(o, nameid); if (func == NULL) { - va_end(va); - if (!PyErr_Occurred()) + if (!PyErr_Occurred()) { PyErr_SetObject(PyExc_AttributeError, nameid->object); - return NULL; - } - - if (format && *format) - args = Py_VaBuildValue(format, va); - else - args = PyTuple_New(0); - - va_end(va); - - if (args == NULL) - return NULL; - - assert(PyTuple_Check(args)); - retval = PyObject_Call(func, args, NULL); - - Py_DECREF(args); + } + return NULL; + } + return func; +} + +static PyObject * +call_method_noarg(PyObject *o, _Py_Identifier *nameid) +{ + PyObject *func, *result; + + func = get_method(o, nameid); + if (func == NULL) { + return NULL; + } + + result = PyObject_CallNoArg(func); Py_DECREF(func); - - return retval; -} - -/* Clone of call_method() that returns NotImplemented when the lookup fails. */ + return result; +} static PyObject * -call_maybe(PyObject *o, _Py_Identifier *nameid, const char *format, ...) -{ - va_list va; - PyObject *args, *func = 0, *retval; - va_start(va, format); +call_method_arg1(PyObject *o, _Py_Identifier *nameid, PyObject *arg) +{ + PyObject *func, *result; + + func = get_method(o, nameid); + if (func == NULL) { + return NULL; + } + + result = _PyObject_FastCall(func, &arg, 1, 0); + Py_DECREF(func); + return result; +} + +static PyObject * +call_method_arg2(PyObject *o, _Py_Identifier *nameid, PyObject *arg1, PyObject *arg2) +{ + PyObject *func, *result; + PyObject* stack[2]; + + func = get_method(o, nameid); + if (func == NULL) { + return NULL; + } + + stack[0] = arg1; + stack[1] = arg2; + result = _PyObject_FastCall(func, stack, 2, 0); + Py_DECREF(func); + return result; +} + +/* Clone of call_method_arg1() that returns NotImplemented when the lookup fails. */ + +static PyObject * +call_maybe_arg1(PyObject *o, _Py_Identifier *nameid, PyObject *arg) +{ + PyObject *func; func = lookup_maybe(o, nameid); if (func == NULL) { - va_end(va); if (!PyErr_Occurred()) Py_RETURN_NOTIMPLEMENTED; return NULL; } - if (format && *format) - args = Py_VaBuildValue(format, va); - else - args = PyTuple_New(0); - - va_end(va); - - if (args == NULL) - return NULL; - - assert(PyTuple_Check(args)); - retval = PyObject_Call(func, args, NULL); - - Py_DECREF(args); - Py_DECREF(func); - - return retval; + return PyObject_CallArg1(func, arg); } /* @@ -1843,7 +1853,7 @@ PyObject *mro_meth = lookup_method((PyObject *)type, &PyId_mro); if (mro_meth == NULL) return NULL; - mro_result = PyObject_CallObject(mro_meth, NULL); + mro_result = PyObject_CallNoArg(mro_meth); Py_DECREF(mro_meth); } else { @@ -3424,9 +3434,7 @@ sorted = _PyDict_GetItemId(builtins, &PyId_sorted); if (sorted == NULL) goto error; - sorted_methods = PyObject_CallFunctionObjArgs(sorted, - abstract_methods, - NULL); + sorted_methods = _PyObject_FastCall(sorted, &abstract_methods, 1, 0); if (sorted_methods == NULL) goto error; comma = _PyUnicode_FromId(&comma_id); @@ -3962,7 +3970,7 @@ Py_DECREF(slotnames); } else { /* getstate != NULL */ - state = PyObject_CallObject(getstate, NULL); + state = PyObject_CallNoArg(getstate); Py_DECREF(getstate); if (state == NULL) return NULL; @@ -3987,7 +3995,7 @@ __getnewargs_ex__ on the object. */ getnewargs_ex = _PyObject_LookupSpecial(obj, &PyId___getnewargs_ex__); if (getnewargs_ex != NULL) { - PyObject *newargs = PyObject_CallObject(getnewargs_ex, NULL); + PyObject *newargs = PyObject_CallNoArg(getnewargs_ex); Py_DECREF(getnewargs_ex); if (newargs == NULL) { return -1; @@ -4040,7 +4048,7 @@ __getnewargs__ instead. */ getnewargs = _PyObject_LookupSpecial(obj, &PyId___getnewargs__); if (getnewargs != NULL) { - *args = PyObject_CallObject(getnewargs, NULL); + *args = PyObject_CallNoArg(getnewargs); Py_DECREF(getnewargs); if (*args == NULL) { return -1; @@ -4286,7 +4294,7 @@ override = (clsreduce != objreduce); Py_DECREF(clsreduce); if (override) { - res = PyObject_CallObject(reduce, NULL); + res = PyObject_CallNoArg(reduce); Py_DECREF(reduce); return res; } @@ -5082,19 +5090,25 @@ } static int -check_num_args(PyObject *ob, int n) +check_stack_num_args(Py_ssize_t na, Py_ssize_t n) +{ + if (n == na) + return 1; + PyErr_Format( + PyExc_TypeError, + "expected %zd arguments, got %zd", n, na); + return 0; +} + +static int +check_num_args(PyObject *ob, Py_ssize_t n) { if (!PyTuple_CheckExact(ob)) { PyErr_SetString(PyExc_SystemError, "PyArg_UnpackTuple() argument list is not a tuple"); return 0; } - if (n == PyTuple_GET_SIZE(ob)) - return 1; - PyErr_Format( - PyExc_TypeError, - "expected %d arguments, got %zd", n, PyTuple_GET_SIZE(ob)); - return 0; + return check_stack_num_args(PyTuple_GET_SIZE(ob), n); } /* Generic wrappers for overloadable 'operators' such as __getitem__ */ @@ -5106,12 +5120,12 @@ entries, one regular and one with reversed arguments. */ static PyObject * -wrap_lenfunc(PyObject *self, PyObject *args, void *wrapped) +wrap_fast_lenfunc(PyObject *self, PyObject **stack, int na, void *wrapped) { lenfunc func = (lenfunc)wrapped; Py_ssize_t res; - if (!check_num_args(args, 0)) + if (!check_stack_num_args(na, 0)) return NULL; res = (*func)(self); if (res == -1 && PyErr_Occurred()) @@ -5120,12 +5134,26 @@ } static PyObject * -wrap_inquirypred(PyObject *self, PyObject *args, void *wrapped) +wrap_lenfunc(PyObject *self, PyObject *args, void *wrapped) +{ + lenfunc func = (lenfunc)wrapped; + Py_ssize_t res; + + if (!check_num_args(args, 0)) + return NULL; + res = (*func)(self); + if (res == -1 && PyErr_Occurred()) + return NULL; + return PyLong_FromLong((long)res); +} + +static PyObject * +wrap_fast_inquirypred(PyObject *self, PyObject **stack, int na, void *wrapped) { inquiry func = (inquiry)wrapped; int res; - if (!check_num_args(args, 0)) + if (!check_stack_num_args(na, 0)) return NULL; res = (*func)(self); if (res == -1 && PyErr_Occurred()) @@ -5134,11 +5162,37 @@ } static PyObject * -wrap_binaryfunc(PyObject *self, PyObject *args, void *wrapped) +wrap_inquirypred(PyObject *self, PyObject *args, void *wrapped) +{ + inquiry func = (inquiry)wrapped; + int res; + + if (!check_num_args(args, 0)) + return NULL; + res = (*func)(self); + if (res == -1 && PyErr_Occurred()) + return NULL; + return PyBool_FromLong((long)res); +} + +static PyObject * +wrap_fast_binaryfunc(PyObject *self, PyObject **stack, int na, void *wrapped) { binaryfunc func = (binaryfunc)wrapped; PyObject *other; + if (!check_stack_num_args(na, 1)) + return NULL; + other = stack[0]; + return (*func)(self, other); +} + +static PyObject * +wrap_binaryfunc(PyObject *self, PyObject *args, void *wrapped) +{ + binaryfunc func = (binaryfunc)wrapped; + PyObject *other; + if (!check_num_args(args, 1)) return NULL; other = PyTuple_GET_ITEM(args, 0); @@ -5146,11 +5200,31 @@ } static PyObject * -wrap_binaryfunc_l(PyObject *self, PyObject *args, void *wrapped) -{ +wrap_fast_binaryfunc_l(PyObject *self, PyObject **stack, int na, void *wrapped) +{ + /* wrap_fast_binaryfunc_l() has the same code than wrap_fast_binaryfunc() + but both functions must have a different address for + "d->d_base->wrapper == p->wrapper" tests: + http://bugs.python.org/issue8847#msg166935 */ binaryfunc func = (binaryfunc)wrapped; PyObject *other; + if (!check_stack_num_args(na, 1)) + return NULL; + other = stack[0]; + return (*func)(self, other); +} + +static PyObject * +wrap_binaryfunc_l(PyObject *self, PyObject *args, void *wrapped) +{ + /* wrap_binaryfunc_l() has the same code than wrap_binaryfunc() + but both functions must have a different address for + "d->d_base->wrapper == p->wrapper" tests: + http://bugs.python.org/issue8847#msg166935 */ + binaryfunc func = (binaryfunc)wrapped; + PyObject *other; + if (!check_num_args(args, 1)) return NULL; other = PyTuple_GET_ITEM(args, 0); @@ -5170,7 +5244,7 @@ } static PyObject * -wrap_ternaryfunc(PyObject *self, PyObject *args, void *wrapped) +wrap_fast_pow(PyObject *self, PyObject **stack, int na, void *wrapped) { ternaryfunc func = (ternaryfunc)wrapped; PyObject *other; @@ -5178,26 +5252,66 @@ /* Note: This wrapper only works for __pow__() */ - if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third)) - return NULL; + if (_PyStack_CheckArgs(stack, na, 0, "__pow__", 1, 2) < 0) { + return NULL; + } + other = stack[0]; + third = (na >= 2) ? stack[1] : Py_None; + return (*func)(self, other, third); } static PyObject * -wrap_ternaryfunc_r(PyObject *self, PyObject *args, void *wrapped) +wrap_pow(PyObject *self, PyObject *args, void *wrapped) { ternaryfunc func = (ternaryfunc)wrapped; PyObject *other; PyObject *third = Py_None; - /* Note: This wrapper only works for __pow__() */ - if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third)) return NULL; + return (*func)(self, other, third); +} + +static PyObject * +wrap_fast_rpow(PyObject *self, PyObject **stack, int na, void *wrapped) +{ + ternaryfunc func = (ternaryfunc)wrapped; + PyObject *other; + PyObject *third = Py_None; + + if (_PyStack_CheckArgs(stack, na, 0, "__pow__", 1, 2) < 0) { + return NULL; + } + other = stack[0]; + third = (na >= 2) ? stack[1] : Py_None; + return (*func)(other, self, third); } static PyObject * +wrap_rpow(PyObject *self, PyObject *args, void *wrapped) +{ + ternaryfunc func = (ternaryfunc)wrapped; + PyObject *other; + PyObject *third = Py_None; + + if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third)) + return NULL; + return (*func)(other, self, third); +} + +static PyObject * +wrap_fast_unaryfunc(PyObject *self, PyObject **stack, int na, void *wrapped) +{ + unaryfunc func = (unaryfunc)wrapped; + + if (!check_stack_num_args(na, 0)) + return NULL; + return (*func)(self); +} + +static PyObject * wrap_unaryfunc(PyObject *self, PyObject *args, void *wrapped) { unaryfunc func = (unaryfunc)wrapped; @@ -5208,6 +5322,22 @@ } static PyObject * +wrap_fast_indexargfunc(PyObject *self, PyObject **stack, int na, void *wrapped) +{ + ssizeargfunc func = (ssizeargfunc)wrapped; + PyObject* o; + Py_ssize_t i; + + if (!check_stack_num_args(na, 1)) + return NULL; + o = stack[0]; + i = PyNumber_AsSsize_t(o, PyExc_OverflowError); + if (i == -1 && PyErr_Occurred()) + return NULL; + return (*func)(self, i); +} + +static PyObject * wrap_indexargfunc(PyObject *self, PyObject *args, void *wrapped) { ssizeargfunc func = (ssizeargfunc)wrapped; @@ -5243,34 +5373,51 @@ } static PyObject * -wrap_sq_item(PyObject *self, PyObject *args, void *wrapped) +wrap_fast_sq_item(PyObject *self, PyObject **stack, int na, void *wrapped) { ssizeargfunc func = (ssizeargfunc)wrapped; PyObject *arg; Py_ssize_t i; - if (PyTuple_GET_SIZE(args) == 1) { - arg = PyTuple_GET_ITEM(args, 0); - i = getindex(self, arg); - if (i == -1 && PyErr_Occurred()) - return NULL; - return (*func)(self, i); - } - check_num_args(args, 1); - assert(PyErr_Occurred()); - return NULL; + if (!check_stack_num_args(na, 1)) + return NULL; + + arg = stack[0]; + i = getindex(self, arg); + if (i == -1 && PyErr_Occurred()) + return NULL; + return (*func)(self, i); } static PyObject * -wrap_sq_setitem(PyObject *self, PyObject *args, void *wrapped) +wrap_sq_item(PyObject *self, PyObject *args, void *wrapped) +{ + ssizeargfunc func = (ssizeargfunc)wrapped; + PyObject *arg; + Py_ssize_t i; + + if (!check_num_args(args, 1)) + return NULL; + + arg = PyTuple_GET_ITEM(args, 0); + i = getindex(self, arg); + if (i == -1 && PyErr_Occurred()) + return NULL; + return (*func)(self, i); +} + +static PyObject * +wrap_fast_sq_setitem(PyObject *self, PyObject **stack, int na, void *wrapped) { ssizeobjargproc func = (ssizeobjargproc)wrapped; Py_ssize_t i; int res; PyObject *arg, *value; - if (!PyArg_UnpackTuple(args, "", 2, 2, &arg, &value)) - return NULL; + if (!check_stack_num_args(na, 2)) + return NULL; + arg = stack[0]; + value = stack[1]; i = getindex(self, arg); if (i == -1 && PyErr_Occurred()) return NULL; @@ -5282,13 +5429,54 @@ } static PyObject * -wrap_sq_delitem(PyObject *self, PyObject *args, void *wrapped) +wrap_sq_setitem(PyObject *self, PyObject *args, void *wrapped) +{ + ssizeobjargproc func = (ssizeobjargproc)wrapped; + Py_ssize_t i; + int res; + PyObject *arg, *value; + + if (!PyArg_UnpackTuple(args, "", 2, 2, &arg, &value)) + return NULL; + i = getindex(self, arg); + if (i == -1 && PyErr_Occurred()) + return NULL; + res = (*func)(self, i, value); + if (res == -1 && PyErr_Occurred()) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_fast_sq_delitem(PyObject *self, PyObject **stack, int na, void *wrapped) { ssizeobjargproc func = (ssizeobjargproc)wrapped; Py_ssize_t i; int res; PyObject *arg; + if (!check_stack_num_args(na, 1)) + return NULL; + arg = stack[0]; + i = getindex(self, arg); + if (i == -1 && PyErr_Occurred()) + return NULL; + res = (*func)(self, i, NULL); + if (res == -1 && PyErr_Occurred()) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_sq_delitem(PyObject *self, PyObject *args, void *wrapped) +{ + ssizeobjargproc func = (ssizeobjargproc)wrapped; + Py_ssize_t i; + int res; + PyObject *arg; + if (!check_num_args(args, 1)) return NULL; arg = PyTuple_GET_ITEM(args, 0); @@ -5304,12 +5492,29 @@ /* XXX objobjproc is a misnomer; should be objargpred */ static PyObject * -wrap_objobjproc(PyObject *self, PyObject *args, void *wrapped) +wrap_fast_objobjproc(PyObject *self, PyObject **stack, int na, void *wrapped) { objobjproc func = (objobjproc)wrapped; int res; PyObject *value; + if (!check_stack_num_args(na, 1)) + return NULL; + value = stack[0]; + res = (*func)(self, value); + if (res == -1 && PyErr_Occurred()) + return NULL; + else + return PyBool_FromLong(res); +} + +static PyObject * +wrap_objobjproc(PyObject *self, PyObject *args, void *wrapped) +{ + objobjproc func = (objobjproc)wrapped; + int res; + PyObject *value; + if (!check_num_args(args, 1)) return NULL; value = PyTuple_GET_ITEM(args, 0); @@ -5321,12 +5526,30 @@ } static PyObject * -wrap_objobjargproc(PyObject *self, PyObject *args, void *wrapped) +wrap_fast_objobjargproc(PyObject *self, PyObject **stack, int na, void *wrapped) { objobjargproc func = (objobjargproc)wrapped; int res; PyObject *key, *value; + if (!check_stack_num_args(na, 2)) + return NULL; + key = stack[0]; + value = stack[1]; + res = (*func)(self, key, value); + if (res == -1 && PyErr_Occurred()) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_objobjargproc(PyObject *self, PyObject *args, void *wrapped) +{ + objobjargproc func = (objobjargproc)wrapped; + int res; + PyObject *key, *value; + if (!PyArg_UnpackTuple(args, "", 2, 2, &key, &value)) return NULL; res = (*func)(self, key, value); @@ -5337,6 +5560,23 @@ } static PyObject * +wrap_fast_delitem(PyObject *self, PyObject **stack, int na, void *wrapped) +{ + objobjargproc func = (objobjargproc)wrapped; + int res; + PyObject *key; + + if (!check_stack_num_args(na, 1)) + return NULL; + key = stack[0]; + res = (*func)(self, key, NULL); + if (res == -1 && PyErr_Occurred()) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * wrap_delitem(PyObject *self, PyObject *args, void *wrapped) { objobjargproc func = (objobjargproc)wrapped; @@ -5392,12 +5632,51 @@ } static PyObject * -wrap_delattr(PyObject *self, PyObject *args, void *wrapped) +wrap_fast_setattr(PyObject *self, PyObject **stack, int na, void *wrapped) +{ + setattrofunc func = (setattrofunc)wrapped; + int res; + PyObject *name, *value; + + if (!check_stack_num_args(na, 2)) + return NULL; + name = stack[0]; + value = stack[1]; + if (!hackcheck(self, func, "__setattr__")) + return NULL; + res = (*func)(self, name, value); + if (res < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_fast_delattr(PyObject *self, PyObject **stack, int na, void *wrapped) { setattrofunc func = (setattrofunc)wrapped; int res; PyObject *name; + if (!check_stack_num_args(na, 1)) + return NULL; + name = stack[0]; + if (!hackcheck(self, func, "__delattr__")) + return NULL; + res = (*func)(self, name, NULL); + if (res < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_delattr(PyObject *self, PyObject *args, void *wrapped) +{ + setattrofunc func = (setattrofunc)wrapped; + int res; + PyObject *name; + if (!check_num_args(args, 1)) return NULL; name = PyTuple_GET_ITEM(args, 0); @@ -5411,6 +5690,20 @@ } static PyObject * +wrap_fast_hashfunc(PyObject *self, PyObject **stack, int na, void *wrapped) +{ + hashfunc func = (hashfunc)wrapped; + Py_hash_t res; + + if (!check_stack_num_args(na, 0)) + return NULL; + res = (*func)(self); + if (res == -1 && PyErr_Occurred()) + return NULL; + return PyLong_FromSsize_t(res); +} + +static PyObject * wrap_hashfunc(PyObject *self, PyObject *args, void *wrapped) { hashfunc func = (hashfunc)wrapped; @@ -5472,6 +5765,20 @@ RICHCMP_WRAPPER(ge, Py_GE) static PyObject * +wrap_fast_next(PyObject *self, PyObject **stack, int na, void *wrapped) +{ + unaryfunc func = (unaryfunc)wrapped; + PyObject *res; + + if (!check_stack_num_args(na, 0)) + return NULL; + res = (*func)(self); + if (res == NULL && !PyErr_Occurred()) + PyErr_SetNone(PyExc_StopIteration); + return res; +} + +static PyObject * wrap_next(PyObject *self, PyObject *args, void *wrapped) { unaryfunc func = (unaryfunc)wrapped; @@ -5643,15 +5950,17 @@ FUNCNAME(PyObject *self) \ { \ _Py_static_string(id, OPSTR); \ - return call_method(self, &id, "()"); \ -} - -#define SLOT1(FUNCNAME, OPSTR, ARG1TYPE, ARGCODES) \ + \ + return call_method_noarg(self, &id); \ +} + +#define SLOT1(FUNCNAME, OPSTR, ARG1TYPE) \ static PyObject * \ -FUNCNAME(PyObject *self, ARG1TYPE arg1) \ +FUNCNAME(PyObject *self, ARG1TYPE arg) \ { \ _Py_static_string(id, OPSTR); \ - return call_method(self, &id, "(" ARGCODES ")", arg1); \ + \ + return call_method_arg1(self, &id, arg); \ } /* Boolean helper for SLOT1BINFULL(). @@ -5704,20 +6013,20 @@ if (do_other && \ PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self)) && \ method_is_overloaded(self, other, &rop_id)) { \ - r = call_maybe(other, &rop_id, "(O)", self); \ + r = call_maybe_arg1(other, &rop_id, self); \ if (r != Py_NotImplemented) \ return r; \ Py_DECREF(r); \ do_other = 0; \ } \ - r = call_maybe(self, &op_id, "(O)", other); \ + r = call_maybe_arg1(self, &op_id, other); \ if (r != Py_NotImplemented || \ Py_TYPE(other) == Py_TYPE(self)) \ return r; \ Py_DECREF(r); \ } \ if (do_other) { \ - return call_maybe(other, &rop_id, "(O)", self); \ + return call_maybe_arg1(other, &rop_id, self); \ } \ Py_RETURN_NOTIMPLEMENTED; \ } @@ -5725,22 +6034,18 @@ #define SLOT1BIN(FUNCNAME, SLOTNAME, OPSTR, ROPSTR) \ SLOT1BINFULL(FUNCNAME, FUNCNAME, SLOTNAME, OPSTR, ROPSTR) -#define SLOT2(FUNCNAME, OPSTR, ARG1TYPE, ARG2TYPE, ARGCODES) \ -static PyObject * \ -FUNCNAME(PyObject *self, ARG1TYPE arg1, ARG2TYPE arg2) \ -{ \ - _Py_static_string(id, #OPSTR); \ - return call_method(self, &id, "(" ARGCODES ")", arg1, arg2); \ -} static Py_ssize_t slot_sq_length(PyObject *self) { - PyObject *res = call_method(self, &PyId___len__, "()"); + PyObject *res; Py_ssize_t len; - if (res == NULL) + res = call_method_noarg(self, &PyId___len__); + if (res == NULL) { return -1; + } + len = PyNumber_AsSsize_t(res, PyExc_OverflowError); Py_DECREF(res); if (len < 0) { @@ -5757,7 +6062,7 @@ static PyObject * slot_sq_item(PyObject *self, Py_ssize_t i) { - PyObject *func, *args = NULL, *ival = NULL, *retval = NULL; + PyObject *func, *ival = NULL, *retval = NULL; descrgetfunc f; func = _PyType_LookupId(Py_TYPE(self), &PyId___getitem__); @@ -5772,21 +6077,15 @@ } ival = PyLong_FromSsize_t(i); if (ival != NULL) { - args = PyTuple_New(1); - if (args != NULL) { - PyTuple_SET_ITEM(args, 0, ival); - retval = PyObject_Call(func, args, NULL); - Py_XDECREF(args); - Py_XDECREF(func); - return retval; - } + retval = _PyObject_FastCall(func, &ival, 1, 0); + Py_XDECREF(func); + return retval; } } else { PyObject *getitem_str = _PyUnicode_FromId(&PyId___getitem__); PyErr_SetObject(PyExc_AttributeError, getitem_str); } - Py_XDECREF(args); Py_XDECREF(ival); Py_XDECREF(func); return NULL; @@ -5796,11 +6095,20 @@ slot_sq_ass_item(PyObject *self, Py_ssize_t index, PyObject *value) { PyObject *res; - - if (value == NULL) - res = call_method(self, &PyId___delitem__, "(n)", index); - else - res = call_method(self, &PyId___setitem__, "(nO)", index, value); + PyObject *index_obj; + + index_obj = PyLong_FromSize_t(index); + if (index_obj == NULL) { + return -1; + } + + if (value == NULL) { + res = call_method_arg1(self, &PyId___delitem__, index_obj); + } + else { + res = call_method_arg2(self, &PyId___setitem__, index_obj, value); + } + Py_DECREF(index_obj); if (res == NULL) return -1; Py_DECREF(res); @@ -5810,19 +6118,13 @@ static int slot_sq_contains(PyObject *self, PyObject *value) { - PyObject *func, *res, *args; + PyObject *func, *res; int result = -1; _Py_IDENTIFIER(__contains__); func = lookup_maybe(self, &PyId___contains__); if (func != NULL) { - args = PyTuple_Pack(1, value); - if (args == NULL) - res = NULL; - else { - res = PyObject_Call(func, args, NULL); - Py_DECREF(args); - } + res = _PyObject_FastCall(func, &value, 1, 0); Py_DECREF(func); if (res != NULL) { result = PyObject_IsTrue(res); @@ -5839,17 +6141,19 @@ #define slot_mp_length slot_sq_length -SLOT1(slot_mp_subscript, "__getitem__", PyObject *, "O") +SLOT1(slot_mp_subscript, "__getitem__", PyObject *) static int slot_mp_ass_subscript(PyObject *self, PyObject *key, PyObject *value) { PyObject *res; - if (value == NULL) - res = call_method(self, &PyId___delitem__, "(O)", key); - else - res = call_method(self, &PyId___setitem__, "(OO)", key, value); + if (value == NULL) { + res = call_method_arg1(self, &PyId___delitem__, key); + } + else { + res = call_method_arg2(self, &PyId___setitem__, key, value); + } if (res == NULL) return -1; @@ -5880,8 +6184,9 @@ can call this when the second argument's type uses slot_nb_power, so check before calling self.__pow__. */ if (Py_TYPE(self)->tp_as_number != NULL && - Py_TYPE(self)->tp_as_number->nb_power == slot_nb_power) { - return call_method(self, &PyId___pow__, "(OO)", other, modulus); + Py_TYPE(self)->tp_as_number->nb_power == slot_nb_power) + { + return call_method_arg2(self, &PyId___pow__, other, modulus); } Py_RETURN_NOTIMPLEMENTED; } @@ -5893,7 +6198,7 @@ static int slot_nb_bool(PyObject *self) { - PyObject *func, *args; + PyObject *func, *temp; int result = -1; int using_len = 0; _Py_IDENTIFIER(__bool__); @@ -5902,33 +6207,36 @@ if (func == NULL) { if (PyErr_Occurred()) return -1; + func = lookup_maybe(self, &PyId___len__); - if (func == NULL) + if (func == NULL) { return PyErr_Occurred() ? -1 : 1; + } using_len = 1; } - args = PyTuple_New(0); - if (args != NULL) { - PyObject *temp = PyObject_Call(func, args, NULL); - Py_DECREF(args); - if (temp != NULL) { - if (using_len) { - /* enforced by slot_nb_len */ - result = PyObject_IsTrue(temp); - } - else if (PyBool_Check(temp)) { - result = PyObject_IsTrue(temp); - } - else { - PyErr_Format(PyExc_TypeError, - "__bool__ should return " - "bool, returned %s", - Py_TYPE(temp)->tp_name); - result = -1; - } - Py_DECREF(temp); - } - } + + temp = PyObject_CallNoArg(func); + if (temp == NULL) { + Py_DECREF(func); + return -1; + } + + if (using_len) { + /* enforced by slot_nb_len */ + result = PyObject_IsTrue(temp); + } + else if (PyBool_Check(temp)) { + result = PyObject_IsTrue(temp); + } + else { + PyErr_Format(PyExc_TypeError, + "__bool__ should return " + "bool, returned %s", + Py_TYPE(temp)->tp_name); + result = -1; + } + Py_DECREF(temp); + Py_DECREF(func); return result; } @@ -5938,7 +6246,8 @@ slot_nb_index(PyObject *self) { _Py_IDENTIFIER(__index__); - return call_method(self, &PyId___index__, "()"); + + return call_method_noarg(self, &PyId___index__); } @@ -5951,28 +6260,28 @@ SLOT0(slot_nb_int, "__int__") SLOT0(slot_nb_float, "__float__") -SLOT1(slot_nb_inplace_add, "__iadd__", PyObject *, "O") -SLOT1(slot_nb_inplace_subtract, "__isub__", PyObject *, "O") -SLOT1(slot_nb_inplace_multiply, "__imul__", PyObject *, "O") -SLOT1(slot_nb_inplace_matrix_multiply, "__imatmul__", PyObject *, "O") -SLOT1(slot_nb_inplace_remainder, "__imod__", PyObject *, "O") +SLOT1(slot_nb_inplace_add, "__iadd__", PyObject *) +SLOT1(slot_nb_inplace_subtract, "__isub__", PyObject *) +SLOT1(slot_nb_inplace_multiply, "__imul__", PyObject *) +SLOT1(slot_nb_inplace_matrix_multiply, "__imatmul__", PyObject *) +SLOT1(slot_nb_inplace_remainder, "__imod__", PyObject *) /* Can't use SLOT1 here, because nb_inplace_power is ternary */ static PyObject * slot_nb_inplace_power(PyObject *self, PyObject * arg1, PyObject *arg2) { _Py_IDENTIFIER(__ipow__); - return call_method(self, &PyId___ipow__, "(" "O" ")", arg1); -} -SLOT1(slot_nb_inplace_lshift, "__ilshift__", PyObject *, "O") -SLOT1(slot_nb_inplace_rshift, "__irshift__", PyObject *, "O") -SLOT1(slot_nb_inplace_and, "__iand__", PyObject *, "O") -SLOT1(slot_nb_inplace_xor, "__ixor__", PyObject *, "O") -SLOT1(slot_nb_inplace_or, "__ior__", PyObject *, "O") + return call_method_arg1(self, &PyId___ipow__, arg1); +} +SLOT1(slot_nb_inplace_lshift, "__ilshift__", PyObject *) +SLOT1(slot_nb_inplace_rshift, "__irshift__", PyObject *) +SLOT1(slot_nb_inplace_and, "__iand__", PyObject *) +SLOT1(slot_nb_inplace_xor, "__ixor__", PyObject *) +SLOT1(slot_nb_inplace_or, "__ior__", PyObject *) SLOT1BIN(slot_nb_floor_divide, nb_floor_divide, "__floordiv__", "__rfloordiv__") SLOT1BIN(slot_nb_true_divide, nb_true_divide, "__truediv__", "__rtruediv__") -SLOT1(slot_nb_inplace_floor_divide, "__ifloordiv__", PyObject *, "O") -SLOT1(slot_nb_inplace_true_divide, "__itruediv__", PyObject *, "O") +SLOT1(slot_nb_inplace_floor_divide, "__ifloordiv__", PyObject *) +SLOT1(slot_nb_inplace_true_divide, "__itruediv__", PyObject *) static PyObject * slot_tp_repr(PyObject *self) @@ -6082,7 +6391,7 @@ static PyObject * slot_tp_getattro(PyObject *self, PyObject *name) { - return call_method(self, &PyId___getattribute__, "(O)", name); + return call_method_arg1(self, &PyId___getattribute__, name); } static PyObject * @@ -6098,7 +6407,7 @@ else attr = descr; } - res = PyObject_CallFunctionObjArgs(attr, name, NULL); + res = PyObject_CallArg1(attr, name); Py_XDECREF(descr); return res; } @@ -6154,9 +6463,9 @@ _Py_IDENTIFIER(__setattr__); if (value == NULL) - res = call_method(self, &PyId___delattr__, "(O)", name); + res = call_method_arg1(self, &PyId___delattr__, name); else - res = call_method(self, &PyId___setattr__, "(OO)", name, value); + res = call_method_arg2(self, &PyId___setattr__, name, value); if (res == NULL) return -1; Py_DECREF(res); @@ -6175,20 +6484,14 @@ static PyObject * slot_tp_richcompare(PyObject *self, PyObject *other, int op) { - PyObject *func, *args, *res; + PyObject *func, *res; func = lookup_method(self, &name_op[op]); if (func == NULL) { PyErr_Clear(); Py_RETURN_NOTIMPLEMENTED; } - args = PyTuple_Pack(1, other); - if (args == NULL) - res = NULL; - else { - res = PyObject_Call(func, args, NULL); - Py_DECREF(args); - } + res = PyObject_CallArg1(func, other); Py_DECREF(func); return res; } @@ -6201,12 +6504,7 @@ func = lookup_method(self, &PyId___iter__); if (func != NULL) { - PyObject *args; - args = res = PyTuple_New(0); - if (args != NULL) { - res = PyObject_Call(func, args, NULL); - Py_DECREF(args); - } + res = PyObject_CallNoArg(func); Py_DECREF(func); return res; } @@ -6226,7 +6524,7 @@ slot_tp_iternext(PyObject *self) { _Py_IDENTIFIER(__next__); - return call_method(self, &PyId___next__, "()"); + return call_method_noarg(self, &PyId___next__); } static PyObject * @@ -6259,9 +6557,9 @@ _Py_IDENTIFIER(__set__); if (value == NULL) - res = call_method(self, &PyId___delete__, "(O)", target); + res = call_method_arg1(self, &PyId___delete__, target); else - res = call_method(self, &PyId___set__, "(OO)", target, value); + res = call_method_arg2(self, &PyId___set__, target, value); if (res == NULL) return -1; Py_DECREF(res); @@ -6427,28 +6725,35 @@ #define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ PyDoc_STR(DOC)} +#define TPSLOT_FAST(NAME, SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC) \ + {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ + PyDoc_STR(DOC), 0, NULL, FAST_WRAPPER} #define FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS) \ {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ PyDoc_STR(DOC), FLAGS} #define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ {NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ - PyDoc_STR(DOC)} -#define AMSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - ETSLOT(NAME, as_async.SLOT, FUNCTION, WRAPPER, DOC) -#define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - ETSLOT(NAME, as_sequence.SLOT, FUNCTION, WRAPPER, DOC) -#define MPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - ETSLOT(NAME, as_mapping.SLOT, FUNCTION, WRAPPER, DOC) -#define NBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, DOC) -#define UNSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \ + PyDoc_STR(DOC), 0, NULL, NULL} +#define ETSLOT_FAST(NAME, SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC) \ + {NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ + PyDoc_STR(DOC), 0, NULL, FAST_WRAPPER} +#define AMSLOT(NAME, SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC) \ + ETSLOT_FAST(NAME, as_async.SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC) +#define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC) \ + ETSLOT_FAST(NAME, as_sequence.SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC) +#define MPSLOT(NAME, SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC) \ + ETSLOT_FAST(NAME, as_mapping.SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC) +#define NBSLOT(NAME, SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC) \ + ETSLOT_FAST(NAME, as_number.SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC) +#define UNSLOT(NAME, SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC) \ + ETSLOT_FAST(NAME, as_number.SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, \ NAME "($self, /)\n--\n\n" DOC) -#define IBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ - ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \ +#define IBSLOT(NAME, SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC) \ + ETSLOT_FAST(NAME, as_number.SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, \ NAME "($self, value, /)\n--\n\nReturn self" DOC "value.") #define BINSLOT(NAME, SLOT, FUNCTION, DOC) \ - ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \ + ETSLOT_FAST(NAME, as_number.SLOT, FUNCTION, \ + wrap_binaryfunc_l, wrap_fast_binaryfunc_l, \ NAME "($self, value, /)\n--\n\nReturn self" DOC "value.") #define RBINSLOT(NAME, SLOT, FUNCTION, DOC) \ ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \ @@ -6465,22 +6770,22 @@ TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""), TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""), TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""), - TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc, + TPSLOT_FAST("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc, wrap_fast_unaryfunc, "__repr__($self, /)\n--\n\nReturn repr(self)."), - TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc, + TPSLOT_FAST("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc, wrap_fast_hashfunc, "__hash__($self, /)\n--\n\nReturn hash(self)."), FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call, "__call__($self, /, *args, **kwargs)\n--\n\nCall self as a function.", PyWrapperFlag_KEYWORDS), - TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc, + TPSLOT_FAST("__str__", tp_str, slot_tp_str, wrap_unaryfunc, wrap_fast_unaryfunc, "__str__($self, /)\n--\n\nReturn str(self)."), - TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook, - wrap_binaryfunc, + TPSLOT_FAST("__getattribute__", tp_getattro, slot_tp_getattr_hook, + wrap_binaryfunc, wrap_fast_binaryfunc, "__getattribute__($self, name, /)\n--\n\nReturn getattr(self, name)."), TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""), - TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr, + TPSLOT_FAST("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr, wrap_fast_setattr, "__setattr__($self, name, value, /)\n--\n\nImplement setattr(self, name, value)."), - TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr, + TPSLOT_FAST("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr, wrap_fast_delattr, "__delattr__($self, name, /)\n--\n\nImplement delattr(self, name)."), TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt, "__lt__($self, value, /)\n--\n\nReturn selfvalue."), TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge, "__ge__($self, value, /)\n--\n\nReturn self>=value."), - TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc, + TPSLOT_FAST("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc, wrap_fast_unaryfunc, "__iter__($self, /)\n--\n\nImplement iter(self)."), - TPSLOT("__next__", tp_iternext, slot_tp_iternext, wrap_next, + TPSLOT_FAST("__next__", tp_iternext, slot_tp_iternext, wrap_next, wrap_fast_next, "__next__($self, /)\n--\n\nImplement next(self)."), TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get, "__get__($self, instance, owner, /)\n--\n\nReturn an attribute of instance, which is of type owner."), @@ -6514,11 +6819,11 @@ "Create and return new object. See help(type) for accurate signature."), TPSLOT("__del__", tp_finalize, slot_tp_finalize, (wrapperfunc)wrap_del, ""), - AMSLOT("__await__", am_await, slot_am_await, wrap_unaryfunc, + AMSLOT("__await__", am_await, slot_am_await, wrap_unaryfunc, wrap_fast_unaryfunc, "__await__($self, /)\n--\n\nReturn an iterator to be used in await expression."), - AMSLOT("__aiter__", am_aiter, slot_am_aiter, wrap_unaryfunc, + AMSLOT("__aiter__", am_aiter, slot_am_aiter, wrap_unaryfunc, wrap_fast_unaryfunc, "__aiter__($self, /)\n--\n\nReturn an awaitable, that resolves in asynchronous iterator."), - AMSLOT("__anext__", am_anext, slot_am_anext, wrap_unaryfunc, + AMSLOT("__anext__", am_anext, slot_am_anext, wrap_unaryfunc, wrap_fast_unaryfunc, "__anext__($self, /)\n--\n\nReturn a value or raise StopAsyncIteration."), BINSLOT("__add__", nb_add, slot_nb_add, @@ -6541,17 +6846,17 @@ "Return divmod(self, value)."), RBINSLOTNOTINFIX("__rdivmod__", nb_divmod, slot_nb_divmod, "Return divmod(value, self)."), - NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc, + NBSLOT("__pow__", nb_power, slot_nb_power, wrap_pow, wrap_fast_pow, "__pow__($self, value, mod=None, /)\n--\n\nReturn pow(self, value, mod)."), - NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r, + NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_rpow, wrap_fast_rpow, "__rpow__($self, value, mod=None, /)\n--\n\nReturn pow(value, self, mod)."), - UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, "-self"), - UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, "+self"), - UNSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc, + UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, wrap_fast_unaryfunc, "-self"), + UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, wrap_fast_unaryfunc, "+self"), + UNSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc, wrap_fast_unaryfunc, "abs(self)"), - UNSLOT("__bool__", nb_bool, slot_nb_bool, wrap_inquirypred, + UNSLOT("__bool__", nb_bool, slot_nb_bool, wrap_inquirypred, wrap_fast_inquirypred, "self != 0"), - UNSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc, "~self"), + UNSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc, wrap_fast_unaryfunc, "~self"), BINSLOT("__lshift__", nb_lshift, slot_nb_lshift, "<<"), RBINSLOT("__rlshift__", nb_lshift, slot_nb_lshift, "<<"), BINSLOT("__rshift__", nb_rshift, slot_nb_rshift, ">>"), @@ -6562,39 +6867,39 @@ RBINSLOT("__rxor__", nb_xor, slot_nb_xor, "^"), BINSLOT("__or__", nb_or, slot_nb_or, "|"), RBINSLOT("__ror__", nb_or, slot_nb_or, "|"), - UNSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc, + UNSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc, wrap_fast_unaryfunc, "int(self)"), - UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc, + UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc, wrap_fast_unaryfunc, "float(self)"), IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add, - wrap_binaryfunc, "+="), + wrap_binaryfunc, wrap_fast_binaryfunc,"+="), IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract, - wrap_binaryfunc, "-="), + wrap_binaryfunc, wrap_fast_binaryfunc,"-="), IBSLOT("__imul__", nb_inplace_multiply, slot_nb_inplace_multiply, - wrap_binaryfunc, "*="), + wrap_binaryfunc, wrap_fast_binaryfunc,"*="), IBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder, - wrap_binaryfunc, "%="), + wrap_binaryfunc, wrap_fast_binaryfunc,"%="), IBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power, - wrap_binaryfunc, "**="), + wrap_binaryfunc, wrap_fast_binaryfunc,"**="), IBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift, - wrap_binaryfunc, "<<="), + wrap_binaryfunc, wrap_fast_binaryfunc,"<<="), IBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift, - wrap_binaryfunc, ">>="), + wrap_binaryfunc, wrap_fast_binaryfunc,">>="), IBSLOT("__iand__", nb_inplace_and, slot_nb_inplace_and, - wrap_binaryfunc, "&="), + wrap_binaryfunc, wrap_fast_binaryfunc,"&="), IBSLOT("__ixor__", nb_inplace_xor, slot_nb_inplace_xor, - wrap_binaryfunc, "^="), + wrap_binaryfunc, wrap_fast_binaryfunc,"^="), IBSLOT("__ior__", nb_inplace_or, slot_nb_inplace_or, - wrap_binaryfunc, "|="), + wrap_binaryfunc, wrap_fast_binaryfunc,"|="), BINSLOT("__floordiv__", nb_floor_divide, slot_nb_floor_divide, "//"), RBINSLOT("__rfloordiv__", nb_floor_divide, slot_nb_floor_divide, "//"), BINSLOT("__truediv__", nb_true_divide, slot_nb_true_divide, "/"), RBINSLOT("__rtruediv__", nb_true_divide, slot_nb_true_divide, "/"), IBSLOT("__ifloordiv__", nb_inplace_floor_divide, - slot_nb_inplace_floor_divide, wrap_binaryfunc, "//="), + slot_nb_inplace_floor_divide, wrap_binaryfunc, wrap_fast_binaryfunc,"//="), IBSLOT("__itruediv__", nb_inplace_true_divide, - slot_nb_inplace_true_divide, wrap_binaryfunc, "/="), - NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc, + slot_nb_inplace_true_divide, wrap_binaryfunc, wrap_fast_binaryfunc,"/="), + NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc, wrap_fast_unaryfunc, "__index__($self, /)\n--\n\n" "Return self converted to an integer, if self is suitable " "for use as an index into a list."), @@ -6603,45 +6908,45 @@ RBINSLOT("__rmatmul__", nb_matrix_multiply, slot_nb_matrix_multiply, "@"), IBSLOT("__imatmul__", nb_inplace_matrix_multiply, slot_nb_inplace_matrix_multiply, - wrap_binaryfunc, "@="), - MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc, + wrap_binaryfunc, wrap_fast_binaryfunc,"@="), + MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc, wrap_fast_lenfunc, "__len__($self, /)\n--\n\nReturn len(self)."), MPSLOT("__getitem__", mp_subscript, slot_mp_subscript, - wrap_binaryfunc, + wrap_binaryfunc, wrap_fast_binaryfunc, "__getitem__($self, key, /)\n--\n\nReturn self[key]."), MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript, - wrap_objobjargproc, + wrap_objobjargproc, wrap_fast_objobjargproc, "__setitem__($self, key, value, /)\n--\n\nSet self[key] to value."), MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript, - wrap_delitem, + wrap_delitem, wrap_fast_delitem, "__delitem__($self, key, /)\n--\n\nDelete self[key]."), - SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, + SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, wrap_fast_lenfunc, "__len__($self, /)\n--\n\nReturn len(self)."), /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL. The logic in abstract.c always falls back to nb_add/nb_multiply in this case. Defining both the nb_* and the sq_* slots to call the user-defined methods has unexpected side-effects, as shown by test_descr.notimplemented() */ - SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc, + SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc, wrap_fast_binaryfunc, "__add__($self, value, /)\n--\n\nReturn self+value."), - SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc, + SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc, wrap_fast_indexargfunc, "__mul__($self, value, /)\n--\n\nReturn self*value.n"), - SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc, + SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc, wrap_fast_indexargfunc, "__rmul__($self, value, /)\n--\n\nReturn self*value."), - SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item, + SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item, wrap_fast_sq_item, "__getitem__($self, key, /)\n--\n\nReturn self[key]."), - SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem, + SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem, wrap_fast_sq_setitem, "__setitem__($self, key, value, /)\n--\n\nSet self[key] to value."), - SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem, + SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem, wrap_fast_sq_delitem, "__delitem__($self, key, /)\n--\n\nDelete self[key]."), - SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc, + SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc, wrap_fast_objobjproc, "__contains__($self, key, /)\n--\n\nReturn key in self."), SQSLOT("__iadd__", sq_inplace_concat, NULL, - wrap_binaryfunc, + wrap_binaryfunc, wrap_fast_binaryfunc, "__iadd__($self, value, /)\n--\n\nImplement self+=value."), SQSLOT("__imul__", sq_inplace_repeat, NULL, - wrap_indexargfunc, + wrap_indexargfunc, wrap_fast_indexargfunc, "__imul__($self, value, /)\n--\n\nImplement self*=value."), {NULL} diff -r 496e094f4734 -r ad4a53ed1fbf Objects/weakrefobject.c --- a/Objects/weakrefobject.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Objects/weakrefobject.c Fri Apr 22 12:35:07 2016 +0200 @@ -128,13 +128,32 @@ weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw) { static char *kwlist[] = {NULL}; + PyObject *object; - if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) { - PyObject *object = PyWeakref_GET_OBJECT(self); - Py_INCREF(object); - return (object); + if (!PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) { + return NULL; } - return NULL; + + object = PyWeakref_GET_OBJECT(self); + + Py_INCREF(object); + return object; +} + + +static PyObject * +weakref_fastcall(PyWeakReference *self, PyObject **stack, int na, int nk) +{ + PyObject *object; + + if (_PyStack_CheckArgs(stack, na, nk, "__call__", 0, 0) < 0) { + return NULL; + } + + object = PyWeakref_GET_OBJECT(self); + + Py_INCREF(object); + return object; } @@ -385,6 +404,16 @@ PyType_GenericAlloc, /*tp_alloc*/ weakref___new__, /*tp_new*/ PyObject_GC_Del, /*tp_free*/ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + 0, /* tp_del */ + 0, /* tp_version_tag */ + 0, /* tp_finalize */ + (pyfastfunc)weakref_fastcall, /* tp_fastcall */ }; @@ -865,7 +894,7 @@ static void handle_callback(PyWeakReference *ref, PyObject *callback) { - PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL); + PyObject *cbresult = PyObject_CallArg1(callback, (PyObject *)ref); if (cbresult == NULL) PyErr_WriteUnraisable(callback); diff -r 496e094f4734 -r ad4a53ed1fbf PCbuild/pythoncore.vcxproj --- a/PCbuild/pythoncore.vcxproj Thu Apr 21 00:23:08 2016 -0700 +++ b/PCbuild/pythoncore.vcxproj Fri Apr 22 12:35:07 2016 +0200 @@ -144,6 +144,7 @@ + @@ -376,6 +377,7 @@ + @@ -416,4 +418,4 @@ - \ No newline at end of file + diff -r 496e094f4734 -r ad4a53ed1fbf Python/bltinmodule.c --- a/Python/bltinmodule.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Python/bltinmodule.c Fri Apr 22 12:35:07 2016 +0200 @@ -481,7 +481,7 @@ ok = PyObject_IsTrue(item); } else { PyObject *good; - good = PyObject_CallFunctionObjArgs(lz->func, item, NULL); + good = PyObject_CallArg1(lz->func, item); if (good == NULL) { Py_DECREF(item); return NULL; @@ -982,13 +982,22 @@ /* AC: cannot convert yet, as needs PEP 457 group support in inspect */ static PyObject * -builtin_getattr(PyObject *self, PyObject *args) +builtin_getattr(PyObject *self, PyObject **stack, int na, int nk) { - PyObject *v, *result, *dflt = NULL; + PyObject *v, *result, *dflt; PyObject *name; - if (!PyArg_UnpackTuple(args, "getattr", 2, 3, &v, &name, &dflt)) + if (_PyStack_CheckArgs(stack, na, nk, "getattr", 2, 3) < 0) { return NULL; + } + v = stack[0]; + name = stack[1]; + if (na >= 3) { + dflt = stack[2]; + } + else { + dflt = NULL; + } if (!PyUnicode_Check(name)) { PyErr_SetString(PyExc_TypeError, @@ -1170,26 +1179,31 @@ map_next(mapobject *lz) { PyObject *val; - PyObject *argtuple; PyObject *result; Py_ssize_t numargs, i; + PyObject* small_stack[_PyStack_SIZE]; + PyObject **stack; numargs = PyTuple_GET_SIZE(lz->iters); - argtuple = PyTuple_New(numargs); - if (argtuple == NULL) + + stack = _PyStack_ALLOC(small_stack, numargs); + if (stack == NULL) { return NULL; + } for (i=0 ; iiters, i); val = Py_TYPE(it)->tp_iternext(it); if (val == NULL) { - Py_DECREF(argtuple); + _PyStack_Free(stack, small_stack, i, 0); return NULL; } - PyTuple_SET_ITEM(argtuple, i, val); + stack[i] = val; } - result = PyObject_Call(lz->func, argtuple, NULL); - Py_DECREF(argtuple); + + result = _PyObject_FastCall(lz->func, stack, numargs, 0); + _PyStack_Free(stack, small_stack, numargs, 0); + return result; } @@ -1271,13 +1285,17 @@ /* AC: cannot convert yet, as needs PEP 457 group support in inspect */ static PyObject * -builtin_next(PyObject *self, PyObject *args) +builtin_next(PyObject *self, PyObject **stack, int na, int nk) { PyObject *it, *res; PyObject *def = NULL; - if (!PyArg_UnpackTuple(args, "next", 1, 2, &it, &def)) + if (_PyStack_CheckArgs(stack, na, nk, "next", 1, 2) < 0) { return NULL; + } + it = stack[0]; + def = (na >= 2) ? stack[1] : NULL; + if (!PyIter_Check(it)) { PyErr_Format(PyExc_TypeError, "'%.200s' object is not an iterator", @@ -1406,14 +1424,19 @@ /* AC: cannot convert yet, as needs PEP 457 group support in inspect */ static PyObject * -builtin_iter(PyObject *self, PyObject *args) +builtin_iter(PyObject *self, PyObject **stack, int na, int nk) { - PyObject *v, *w = NULL; - - if (!PyArg_UnpackTuple(args, "iter", 1, 2, &v, &w)) + PyObject *v, *w; + + if (_PyStack_CheckArgsKeywords(stack, na, nk, "iter", 1, 2) < 0) { return NULL; - if (w == NULL) + } + v = stack[0]; + if (na == 1) { return PyObject_GetIter(v); + } + + w = stack[1]; if (!PyCallable_Check(v)) { PyErr_SetString(PyExc_TypeError, "iter(v, w): v must be callable"); @@ -1516,7 +1539,7 @@ while (( item = PyIter_Next(it) )) { /* get the value from the key function */ if (keyfunc != NULL) { - val = PyObject_CallFunctionObjArgs(keyfunc, item, NULL); + val = PyObject_CallArg1(keyfunc, item); if (val == NULL) goto Fail_it_item; } @@ -2041,9 +2064,9 @@ } if (ndigits == NULL) - result = PyObject_CallFunctionObjArgs(round, NULL); + result = PyObject_CallNoArg(round); else - result = PyObject_CallFunctionObjArgs(round, ndigits, NULL); + result = PyObject_CallArg1(round, ndigits); Py_DECREF(round); return result; } @@ -2083,20 +2106,20 @@ "reverse flag can be set to request the result in descending order."); #define BUILTIN_SORTED_METHODDEF \ - {"sorted", (PyCFunction)builtin_sorted, METH_VARARGS|METH_KEYWORDS, builtin_sorted__doc__}, + {"sorted", (PyCFunction)builtin_sorted, METH_FASTCALL, builtin_sorted__doc__}, static PyObject * -builtin_sorted(PyObject *self, PyObject *args, PyObject *kwds) +builtin_sorted(PyObject *self, PyObject **stack, int na, int nk) { - PyObject *newlist, *v, *seq, *keyfunc=NULL, *newargs; + PyObject *newlist, *v, *seq; PyObject *callable; - static char *kwlist[] = {"iterable", "key", "reverse", 0}; - int reverse; /* args 1-3 should match listsort in Objects/listobject.c */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|Oi:sorted", - kwlist, &seq, &keyfunc, &reverse)) + if (_PyStack_CheckArgsKeywords(stack, na, nk, "sorted", 1, 3) < 0) { return NULL; + } + /* FIXME: validate also types: "O|Oi:sorted" and keywords? */ + seq = stack[0]; newlist = PySequence_List(seq); if (newlist == NULL) @@ -2108,15 +2131,7 @@ return NULL; } - newargs = PyTuple_GetSlice(args, 1, 4); - if (newargs == NULL) { - Py_DECREF(newlist); - Py_DECREF(callable); - return NULL; - } - - v = PyObject_Call(callable, newargs, kwds); - Py_DECREF(newargs); + v = _PyObject_FastCall(callable, stack + 1, na - 1, nk); Py_DECREF(callable); if (v == NULL) { Py_DECREF(newlist); @@ -2600,7 +2615,7 @@ BUILTIN_EVAL_METHODDEF BUILTIN_EXEC_METHODDEF BUILTIN_FORMAT_METHODDEF - {"getattr", builtin_getattr, METH_VARARGS, getattr_doc}, + {"getattr", (PyCFunction)builtin_getattr, METH_FASTCALL, getattr_doc}, BUILTIN_GLOBALS_METHODDEF BUILTIN_HASATTR_METHODDEF BUILTIN_HASH_METHODDEF @@ -2609,12 +2624,12 @@ BUILTIN_INPUT_METHODDEF BUILTIN_ISINSTANCE_METHODDEF BUILTIN_ISSUBCLASS_METHODDEF - {"iter", builtin_iter, METH_VARARGS, iter_doc}, + {"iter", (PyCFunction)builtin_iter, METH_FASTCALL, iter_doc}, BUILTIN_LEN_METHODDEF BUILTIN_LOCALS_METHODDEF {"max", (PyCFunction)builtin_max, METH_VARARGS | METH_KEYWORDS, max_doc}, {"min", (PyCFunction)builtin_min, METH_VARARGS | METH_KEYWORDS, min_doc}, - {"next", (PyCFunction)builtin_next, METH_VARARGS, next_doc}, + {"next", (PyCFunction)builtin_next, METH_FASTCALL, next_doc}, BUILTIN_OCT_METHODDEF BUILTIN_ORD_METHODDEF BUILTIN_POW_METHODDEF diff -r 496e094f4734 -r ad4a53ed1fbf Python/ceval.c --- a/Python/ceval.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Python/ceval.c Fri Apr 22 12:35:07 2016 +0200 @@ -114,12 +114,11 @@ static PyObject * call_function(PyObject ***, int); #endif static PyObject * fast_function(PyObject *, PyObject ***, int, int, int); -static PyObject * do_call(PyObject *, PyObject ***, int, int); +static PyObject * do_call(PyObject *, PyObject **, int, int); static PyObject * ext_do_call(PyObject *, PyObject ***, int, int, int); static PyObject * update_keyword_args(PyObject *, int, PyObject ***, PyObject *); static PyObject * update_star_args(int, int, PyObject *, PyObject ***); -static PyObject * load_args(PyObject ***, int); #define CALL_FLAG_VAR 1 #define CALL_FLAG_KW 2 @@ -3044,7 +3043,7 @@ Py_DECREF(mgr); if (enter == NULL) goto error; - res = PyObject_CallFunctionObjArgs(enter, NULL); + res = PyObject_CallNoArg(enter); Py_DECREF(enter); if (res == NULL) goto error; @@ -3075,7 +3074,7 @@ Py_DECREF(mgr); if (enter == NULL) goto error; - res = PyObject_CallFunctionObjArgs(enter, NULL); + res = PyObject_CallNoArg(enter); Py_DECREF(enter); if (res == NULL) goto error; @@ -3114,6 +3113,7 @@ gotos should still be resumed.) */ + PyObject *arg_stack[3]; PyObject *exit_func; PyObject *exc = TOP(), *val = Py_None, *tb = Py_None, *res; if (exc == Py_None) { @@ -3159,8 +3159,10 @@ assert(block->b_type == EXCEPT_HANDLER); block->b_level--; } - /* XXX Not the fastest way to call it... */ - res = PyObject_CallFunctionObjArgs(exit_func, exc, val, tb, NULL); + arg_stack[0] = exc; + arg_stack[1] = val; + arg_stack[2] = tb; + res = _PyObject_FastCall(exit_func, arg_stack, 3, 0); Py_DECREF(exit_func); if (res == NULL) goto error; @@ -4034,7 +4036,8 @@ if (is_coro && coro_wrapper != NULL) { PyObject *wrapped; tstate->in_coroutine_wrapper = 1; - wrapped = PyObject_CallFunction(coro_wrapper, "N", gen); + wrapped = _PyObject_FastCall(coro_wrapper, &gen, 1, 0); + Py_DECREF(gen); tstate->in_coroutine_wrapper = 0; return wrapped; } @@ -4169,7 +4172,7 @@ if (PyExceptionClass_Check(exc)) { type = exc; - value = PyObject_CallObject(exc, NULL); + value = PyObject_CallNoArg(exc); if (value == NULL) goto raise_error; if (!PyExceptionInstance_Check(value)) { @@ -4197,7 +4200,7 @@ if (cause) { PyObject *fixed_cause; if (PyExceptionClass_Check(cause)) { - fixed_cause = PyObject_CallObject(cause, NULL); + fixed_cause = PyObject_CallNoArg(cause); if (fixed_cause == NULL) goto raise_error; Py_DECREF(cause); @@ -4585,17 +4588,23 @@ #endif if (arg == NULL) { + if (kw == NULL) { + return PyObject_CallNoArg(func); + } + arg = PyTuple_New(0); - if (arg == NULL) + if (arg == NULL) { return NULL; + } } else if (!PyTuple_Check(arg)) { PyErr_SetString(PyExc_TypeError, "argument list must be a tuple"); return NULL; } - else + else { Py_INCREF(arg); + } if (kw != NULL && !PyDict_Check(kw)) { PyErr_SetString(PyExc_TypeError, @@ -4636,21 +4645,6 @@ return " object"; } -static void -err_args(PyObject *func, int flags, int nargs) -{ - if (flags & METH_NOARGS) - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%d given)", - ((PyCFunctionObject *)func)->m_ml->ml_name, - nargs); - else - PyErr_Format(PyExc_TypeError, - "%.200s() takes exactly one argument (%d given)", - ((PyCFunctionObject *)func)->m_ml->ml_name, - nargs); -} - #define C_TRACE(x, call) \ if (tstate->use_tracing && tstate->c_profilefunc) { \ if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \ @@ -4691,82 +4685,38 @@ { int na = oparg & 0xff; int nk = (oparg>>8) & 0xff; - int n = na + 2 * nk; - PyObject **pfunc = (*pp_stack) - n - 1; + PyObject **pfunc = (*pp_stack) - (na + 2 * nk) - 1; PyObject *func = *pfunc; PyObject *x, *w; - /* Always dispatch PyCFunction first, because these are - presumed to be the most frequent callable object. - */ - if (PyCFunction_Check(func) && nk == 0) { - int flags = PyCFunction_GET_FLAGS(func); - PyThreadState *tstate = PyThreadState_GET(); - - PCALL(PCALL_CFUNCTION); - if (flags & (METH_NOARGS | METH_O)) { - PyCFunction meth = PyCFunction_GET_FUNCTION(func); - PyObject *self = PyCFunction_GET_SELF(func); - if (flags & METH_NOARGS && na == 0) { - C_TRACE(x, (*meth)(self,NULL)); - - x = _Py_CheckFunctionResult(func, x, NULL); - } - else if (flags & METH_O && na == 1) { - PyObject *arg = EXT_POP(*pp_stack); - C_TRACE(x, (*meth)(self,arg)); - Py_DECREF(arg); - - x = _Py_CheckFunctionResult(func, x, NULL); - } - else { - err_args(func, flags, na); - x = NULL; - } - } - else { - PyObject *callargs; - callargs = load_args(pp_stack, na); - if (callargs != NULL) { - READ_TIMESTAMP(*pintr0); - C_TRACE(x, PyCFunction_Call(func,callargs,NULL)); - READ_TIMESTAMP(*pintr1); - Py_XDECREF(callargs); - } - else { - x = NULL; - } - } + if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { + /* optimize access to bound methods */ + PyObject *self = PyMethod_GET_SELF(func); + PCALL(PCALL_METHOD); + PCALL(PCALL_BOUND_METHOD); + Py_INCREF(self); + func = PyMethod_GET_FUNCTION(func); + Py_INCREF(func); + Py_SETREF(*pfunc, self); + na++; } else { - if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { - /* optimize access to bound methods */ - PyObject *self = PyMethod_GET_SELF(func); - PCALL(PCALL_METHOD); - PCALL(PCALL_BOUND_METHOD); - Py_INCREF(self); - func = PyMethod_GET_FUNCTION(func); - Py_INCREF(func); - Py_SETREF(*pfunc, self); - na++; - n++; - } else - Py_INCREF(func); - READ_TIMESTAMP(*pintr0); - if (PyFunction_Check(func)) - x = fast_function(func, pp_stack, n, na, nk); - else - x = do_call(func, pp_stack, na, nk); - READ_TIMESTAMP(*pintr1); - Py_DECREF(func); - - assert((x != NULL) ^ (PyErr_Occurred() != NULL)); + Py_INCREF(func); } - /* Clear the stack of the function object. Also removes - the arguments in case they weren't consumed already - (fast_function() and err_args() leave them on the stack). - */ + READ_TIMESTAMP(*pintr0); + if (PyFunction_Check(func)) { + x = fast_function(func, + pp_stack, + na + 2 * nk, na, nk); + } + else { + x = do_call(func, *pp_stack - na - nk * 2, na, nk); + } + READ_TIMESTAMP(*pintr1); + Py_DECREF(func); + + /* Clear the stack of the function object. */ while ((*pp_stack) > pfunc) { w = EXT_POP(*pp_stack); Py_DECREF(w); @@ -4777,7 +4727,7 @@ return x; } -/* The fast_function() function optimize calls for which no argument +/* The _PyFunction_FastCall() function optimize calls for which no argument tuple is necessary; the objects are passed directly from the stack. For the simplest case -- a function that takes only positional arguments and is called with only positional arguments -- it @@ -4798,6 +4748,10 @@ PyObject **d = NULL; int nd = 0; + assert(PyFunction_Check(func)); + assert(na >= 0); + assert(nk >= 0); + PCALL(PCALL_FUNCTION); PCALL(PCALL_FAST_FUNCTION); if (argdefs == NULL && co->co_argcount == n && @@ -4844,6 +4798,73 @@ name, qualname); } + +/* Note: fast_function() must be a local function (declared with static) for + best performances of the CALL_FUNCTION opcode. */ +PyObject * +_PyFunction_FastCall(PyObject *func, PyObject **stack, int na, int nk) +{ + /* FIXME: try to factorize _PyFunction_FastCall() and fast_function() + without killing performances? */ + const int n = na + nk * 2; + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject *kwdefs = PyFunction_GET_KW_DEFAULTS(func); + PyObject *name = ((PyFunctionObject *)func) -> func_name; + PyObject *qualname = ((PyFunctionObject *)func) -> func_qualname; + PyObject **d = NULL; + int nd = 0; + + assert(PyFunction_Check(func)); + assert(na >= 0); + assert(nk >= 0); + + PCALL(PCALL_FUNCTION); + PCALL(PCALL_FAST_FUNCTION); + if (argdefs == NULL && co->co_argcount == n && + co->co_kwonlyargcount == 0 && nk==0 && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + PyFrameObject *f; + PyObject *retval = NULL; + PyThreadState *tstate = PyThreadState_GET(); + PyObject **fastlocals; + int i; + + PCALL(PCALL_FASTER_FUNCTION); + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) + return NULL; + + fastlocals = f->f_localsplus; + + for (i = 0; i < n; i++) { + Py_INCREF(*stack); + fastlocals[i] = *stack++; + } + retval = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return retval; + } + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = Py_SIZE(argdefs); + } + return _PyEval_EvalCodeWithName((PyObject*)co, globals, + (PyObject *)NULL, stack, na, + stack+na, nk, d, nd, kwdefs, + PyFunction_GET_CLOSURE(func), + name, qualname); +} + static PyObject * update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack, PyObject *func) @@ -4925,35 +4946,10 @@ } static PyObject * -load_args(PyObject ***pp_stack, int na) +do_call(PyObject *func, PyObject **stack, int na, int nk) { - PyObject *args = PyTuple_New(na); - PyObject *w; - - if (args == NULL) - return NULL; - while (--na >= 0) { - w = EXT_POP(*pp_stack); - PyTuple_SET_ITEM(args, na, w); - } - return args; -} - -static PyObject * -do_call(PyObject *func, PyObject ***pp_stack, int na, int nk) -{ - PyObject *callargs = NULL; - PyObject *kwdict = NULL; - PyObject *result = NULL; - - if (nk > 0) { - kwdict = update_keyword_args(NULL, nk, pp_stack, func); - if (kwdict == NULL) - goto call_fail; - } - callargs = load_args(pp_stack, na); - if (callargs == NULL) - goto call_fail; + PyObject *result; + #ifdef CALL_PROFILE /* At this point, we have to look at the type of func to update the call stats properly. Do it here so as to avoid @@ -4970,15 +4966,9 @@ else PCALL(PCALL_OTHER); #endif - if (PyCFunction_Check(func)) { - PyThreadState *tstate = PyThreadState_GET(); - C_TRACE(result, PyCFunction_Call(func, callargs, kwdict)); - } - else - result = PyObject_Call(func, callargs, kwdict); -call_fail: - Py_XDECREF(callargs); - Py_XDECREF(kwdict); + + result = _PyObject_FastCall(func, stack, na, nk); + result = _Py_CheckFunctionResult(func, result, NULL); return result; } diff -r 496e094f4734 -r ad4a53ed1fbf Python/errors.c --- a/Python/errors.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Python/errors.c Fri Apr 22 12:35:07 2016 +0200 @@ -513,6 +513,7 @@ Py_DECREF(message); if (args != NULL) { + /* FIXME: use fast */ v = PyObject_Call(exc, args, NULL); Py_DECREF(args); if (v != NULL) { @@ -731,6 +732,7 @@ if (PyDict_SetItemString(kwargs, "path", path) < 0) return NULL; + /* FIXME: use fast? */ error = PyObject_Call(PyExc_ImportError, args, kwargs); if (error != NULL) { PyErr_SetObject((PyObject *)Py_TYPE(error), error); diff -r 496e094f4734 -r ad4a53ed1fbf Python/modsupport.c --- a/Python/modsupport.c Thu Apr 21 00:23:08 2016 -0700 +++ b/Python/modsupport.c Fri Apr 22 12:35:07 2016 +0200 @@ -148,6 +148,47 @@ return v; } +static int +do_mkstack(PyObject **stack, const char **p_format, va_list *p_va, int endchar, int n, int flags) +{ + int i; + int itemfailed = 0; + + /* Note that we can't bail immediately on error as this will leak + refcounts on any 'N' arguments. */ + for (i = 0; i < n; i++) { + PyObject *w; + + if (itemfailed) { + PyObject *exception, *value, *tb; + PyErr_Fetch(&exception, &value, &tb); + w = do_mkvalue(p_format, p_va, flags); + PyErr_Restore(exception, value, tb); + } + else { + w = do_mkvalue(p_format, p_va, flags); + } + if (w == NULL) { + itemfailed = 1; + Py_INCREF(Py_None); + w = Py_None; + } + stack[i] = w; + } + if (itemfailed) { + /* do_mkvalue() should have already set an error */ + return -1; + } + if (**p_format != endchar) { + PyErr_SetString(PyExc_SystemError, + "Unmatched paren in format"); + return -1; + } + if (endchar) + ++*p_format; + return 0; +} + static PyObject * do_mktuple(const char **p_format, va_list *p_va, int endchar, int n, int flags) { @@ -445,6 +486,152 @@ return va_build_value(format, va, FLAG_SIZE_T); } +static const char* +format_strip_parenthesis(const char *format, char **p_copy) +{ + size_t len; + char *copy; + + *p_copy = NULL; + + /* FIXME: pass a flag to Py_VaBuildStack? */ + if (format[0] != '(') { + return format; + } + + len = strlen(format); + if (format[len-1] != ')') { + return format; + } + + /* Replace "(OO)" with "OO" */ + copy = PyMem_Malloc(len - 2 + 1); + if (copy == NULL) { + PyErr_NoMemory(); + return NULL; + } + Py_MEMCPY(copy, format + 1, len - 2); + copy[len-2] = '\0'; + + *p_copy = copy; + return copy; +} + +PyObject** +tuple_to_stack(PyObject *tuple, int *na) +{ + Py_ssize_t len = PyTuple_GET_SIZE(tuple); + Py_ssize_t i; + PyObject **stack; + + if (len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "too many parameters"); + return NULL; + } + + stack = PyMem_Malloc(len * sizeof(stack[0])); + if (stack == NULL) { + PyErr_NoMemory(); + return NULL; + } + + for (i=0; i < len; i++) { + PyObject *obj = PyTuple_GET_ITEM(tuple, i); + Py_INCREF(obj); + stack[i] = obj; + } + /* overflow tested below */ + *na = (int)len; + return stack; +} + +PyObject** +va_build_stack(PyObject **small_stack, Py_ssize_t stack_len, + const char *format, va_list va, int flags, int *p_na) +{ + const char *f; + int n; + va_list lva; + char *copy; + int stripped; + PyObject **stack; + + if (format == NULL || *format == '\0') { + *p_na = 0; + return small_stack; + } + + f = format_strip_parenthesis(format, ©); + if (f == NULL) { + return NULL; + } + stripped = (copy != NULL); + + n = countformat(f, '\0'); + + Py_VA_COPY(lva, va); + + if (n < 0) { + PyMem_Free(copy); + return NULL; + } + + if (n <= stack_len) { + stack = small_stack; + } + else { + stack = _PyStack_Alloc(n); + } + if (stack == NULL) { + PyErr_NoMemory(); + return NULL; + } + + if (do_mkstack(stack, &f, &lva, '\0', n, flags) < 0) { + PyMem_Free(copy); + _PyStack_Free(stack, small_stack, n, 0); + return NULL; + } + PyMem_Free(copy); + + if (stack == NULL) { + return NULL; + } + + /* if format isn't "(...)" and stack only contains one object which is a + tuple: unpack the tuple to a new stack */ + if (n == 1 && !stripped && PyTuple_Check(stack[0])) { + PyObject **stack2; + int n2; + + stack2 = tuple_to_stack(stack[0], &n2); + _PyStack_Free(stack, small_stack, n, 0); + if (stack2 == NULL) { + return NULL; + } + + stack = stack2; + n = n2; + } + + *p_na = n; + return stack; +} + +PyObject** +Py_VaBuildStack(PyObject **small_stack, Py_ssize_t stack_len, + const char *format, va_list va, int *p_na) +{ + return va_build_stack(small_stack, stack_len, format, va, 0, p_na); +} + +PyObject** +_Py_VaBuildStack_SizeT(PyObject **small_stack, Py_ssize_t stack_len, + const char *format, va_list va, int *p_na) +{ + return va_build_stack(small_stack, stack_len, format, va, FLAG_SIZE_T, p_na); +} + static PyObject * va_build_value(const char *format, va_list va, int flags) { @@ -452,7 +639,7 @@ int n = countformat(f, '\0'); va_list lva; - Py_VA_COPY(lva, va); + Py_VA_COPY(lva, va); if (n < 0) return NULL; diff -r 496e094f4734 -r ad4a53ed1fbf Python/pystack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Python/pystack.c Fri Apr 22 12:35:07 2016 +0200 @@ -0,0 +1,225 @@ +#include "Python.h" + +static void +_PyStack_FromTuple(PyObject **stack, PyObject *tuple) +{ + Py_ssize_t i, n; + + n = PyTuple_GET_SIZE(tuple); + for (i = 0; i < n; ++i) { + PyObject *item = PyTuple_GET_ITEM(tuple, i); + Py_INCREF(item); + stack[i] = item; + } +} + +PyObject** +_PyStack_FromArgs(PyObject **small_stack, Py_ssize_t stack_size, + PyObject *args, PyObject *kwargs, + int *p_na, int *p_nk) +{ + PyObject *items = NULL; + PyObject **stack; + int res; + Py_ssize_t na, nk, n; + + assert(PyTuple_Check(args)); + + na = PyTuple_GET_SIZE(args); + if (na > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "too many arguments"); + goto error; + } + + if (kwargs) { + items = PyDict_Items(kwargs); + if (items == NULL) + goto error; + + nk = PyList_GET_SIZE(items); + if (nk > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "too many keyword arguments"); + goto error; + } + } + else { + nk = 0; + } + + n = na + nk * 2; + if (n <= stack_size) { + stack = small_stack; + } + else { + stack = _PyStack_Alloc(n); + if (stack == NULL) { + goto error; + } + } + _PyStack_FromTuple(stack, args); + + if (kwargs) { + Py_ssize_t i; + PyObject **wstack; + + wstack = &stack[na]; + + for (i=0; i < nk; i++) { + PyObject *item = PyList_GET_ITEM(items, i); + PyObject *key, *value; + + assert(PyTuple_CheckExact(item) && PyTuple_GET_SIZE(item) == 2); + + key = PyTuple_GET_ITEM(item, 0); + Py_INCREF(key); + *wstack++ = key; + + value = PyTuple_GET_ITEM(item, 1); + Py_INCREF(value); + *wstack++ = value; + } + + Py_CLEAR(items); + } + + /* downcas is safe, checked for integer overflow above */ + *p_na = (int)na; + *p_nk = (int)nk; + return stack; + +error: + Py_XDECREF(items); + *p_na = 0; + *p_nk = 0; + return NULL; +} + + +PyObject** +_PyStack_Alloc(Py_ssize_t na) +{ + if (na * sizeof(PyObject *) > PY_SSIZE_T_MAX) { + PyErr_NoMemory(); + return NULL; + } + return PyMem_Malloc(na * sizeof(PyObject *)); +} + +void +_PyStack_Free(PyObject **stack, PyObject **small_stack, + Py_ssize_t na, Py_ssize_t nk) +{ + const Py_ssize_t n = na + nk * 2; + + for (Py_ssize_t i = 0; i < n; i++) { + Py_DECREF(stack[i]); + } + if (stack != small_stack) { + PyMem_Free(stack); + } +} +int +_PyStack_AsArgs(PyObject **stack, Py_ssize_t na, Py_ssize_t nk, + PyObject *func, + PyObject **p_args, PyObject **p_kwargs) +{ + PyObject *args, *kwargs; + Py_ssize_t i; + + args = PyTuple_New(na); + if (args == NULL) { + goto error; + } + + for (i=0; i < na; i++) { + PyObject *item = stack[i]; + + Py_INCREF(item); + PyTuple_SET_ITEM(args, i, item); + } + + if (nk > 0) { + kwargs = PyDict_New(); + if (kwargs == NULL) { + Py_DECREF(args); + goto error; + } + + for (i=0; i < nk; i++) { + PyObject *key = stack[na + i*2]; + PyObject *value = stack[na + i*2 + 1]; + + /* FIXME: reuse update_keyword_args() of ceval.c */ + if (PyDict_SetItem(kwargs, key, value) < 0) { + Py_DECREF(args); + Py_DECREF(kwargs); + goto error; + } + } + } + else { + kwargs = NULL; + } + + *p_args = args; + *p_kwargs = kwargs; + return 0; + +error: + *p_args = NULL; + *p_kwargs = NULL; + return -1; +} + +int +pystack_chekargs(PyObject **stack, Py_ssize_t na, Py_ssize_t nk, + const char *func_name, + Py_ssize_t min_na, Py_ssize_t max_na) +{ + if (na < min_na) { + PyErr_Format(PyExc_TypeError, + "%s() takes at least %d argument%s (%zd given)", + func_name, + min_na, + (min_na == 1) ? "" : "s", + na + nk); + return -1; + } + + if (na > max_na) { + PyErr_Format(PyExc_TypeError, + "%s() takes at most %d argument%s (%zd given)", + func_name, + max_na, + (max_na == 1) ? "" : "s", + na + nk); + return -1; + } + return 0; +} + +int +_PyStack_CheckArgs(PyObject **stack, Py_ssize_t na, Py_ssize_t nk, + const char *func_name, + Py_ssize_t min_na, Py_ssize_t max_na) +{ + if (pystack_chekargs(stack, na, nk, func_name, min_na, max_na) < 0) { + return -1; + } + + if (nk != 0) { + PyErr_Format(PyExc_TypeError, + "%s() does not take keyword arguments", + func_name); + return -1; + } + return 0; +} + +int +_PyStack_CheckArgsKeywords(PyObject **stack, Py_ssize_t na, Py_ssize_t nk, + const char *func_name, + Py_ssize_t min_na, Py_ssize_t max_na) +{ + return pystack_chekargs(stack, na, nk, func_name, min_na, max_na); +} diff -r 496e094f4734 -r ad4a53ed1fbf notes.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/notes.txt Fri Apr 22 12:35:07 2016 +0200 @@ -0,0 +1,46 @@ +TODO +==== + +* test_profile and test_cprofile are broken + + +Optimized +========= + +* namedtuple .... get attribute +* object.__setattr__(obj, attr, value) +* wrapperdescr_fastcall: _socket.socket.__init__(...) + + +Not optimized (yet?) +==================== + +type_call() is not modified, it would require to modify + tp_new + tp_init + => duplicated methods, how inheritance is handled? + + +Benchmarks +========== + +default/python -m timeit -s 'class Bytes:' -s ' def __bytes__(self): return b"abc"' -s 'b = Bytes()' 'bytes(b)' +1000000 loops, best of 3: 0.249 usec per loop +=> best of 3: 0.227 usec per loop (-8%) + +default/python -m timeit -r 11 -s "from collections import namedtuple as n; a = n('n', 'a b c')(1, 2, 3)" -- "a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a; a.a" +1000000 loops, best of 11: 0.965 usec per loop +=> best of 11: 0.718 usec per loop (-25%) + +default/python -m timeit -s 'import types; set=object.__setattr__; obj=types.SimpleNamespace()' 'set(obj, "x", 1)' +10000000 loops, best of 3: 0.163 usec per loop +=> best of 3: 0.0967 usec per loop (-40%) + +default/python -m timeit -s 'import types; get=object.__getattribute__; obj=types.SimpleNamespace(); obj.x=1' 'get(obj, "x")' +10000000 loops, best of 3: 0.144 usec per loop +=> best of 3: 0.113 usec per loop (-20%) +=> best of 3: 0.0858 usec per loop (-40%) + +taskset_isolated.py default/python -m timeit 'getattr(1, "real")' +10000000 loops, best of 3: 0.0955 usec per loop +=> best of 3: 0.0656 usec per loop (-31%)