Commit 366d5384 authored by Stefan Behnel's avatar Stefan Behnel

Tweak method call fallbacks of dict.get(), dict.setdefault() and dict.pop()...

Tweak method call fallbacks of dict.get(), dict.setdefault() and dict.pop() into fast unbound method calls to the underlying C function.
parent fd9d5ce2
......@@ -509,15 +509,9 @@ class UtilityCode(UtilityCodeBase):
def externalise(matchobj):
type_cname, method_name, args = matchobj.groups()
args = [arg.strip() for arg in args[1:].split(',')]
if len(args) == 1:
call = '__Pyx_CallUnboundCMethod0'
utility_code.add("CallUnboundCMethod0")
elif len(args) == 2:
call = '__Pyx_CallUnboundCMethod1'
utility_code.add("CallUnboundCMethod1")
else:
assert False, "CALL_UNBOUND_METHOD() requires 1 or 2 call arguments"
assert 1 <= len(args) <= 3, "CALL_UNBOUND_METHOD() does not support %d call arguments" % len(args)
call = '__Pyx_CallUnboundCMethod%d' % (len(args) - 1,)
utility_code.add("CallUnboundCMethod%d" % (len(args) - 1,))
cname = output.get_cached_unbound_method(type_cname, method_name, len(args))
return '%s(&%s, %s)' % (call, cname, ', '.join(args))
......
......@@ -1304,6 +1304,7 @@ static int __Pyx_TryUnpackUnboundCMethod(__Pyx_CachedCFunction* target) {
static PyObject* __Pyx__CallUnboundCMethod0(__Pyx_CachedCFunction* cfunc, PyObject* self); /*proto*/
#if CYTHON_COMPILING_IN_CPYTHON
// FASTCALL methods receive "&empty_tuple" as simple "PyObject[0]*"
#define __Pyx_CallUnboundCMethod0(cfunc, self) \
((likely((cfunc)->func)) ? \
(likely((cfunc)->flag == METH_NOARGS) ? (*((cfunc)->func))(self, NULL) : \
......@@ -1311,10 +1312,10 @@ static PyObject* __Pyx__CallUnboundCMethod0(__Pyx_CachedCFunction* cfunc, PyObje
((cfunc)->flag == METH_VARARGS ? (*((cfunc)->func))(self, $empty_tuple) : \
(PY_VERSION_HEX >= 0x030600B1 && (cfunc)->flag == METH_FASTCALL ? \
(PY_VERSION_HEX >= 0x030700A0 ? \
(*(__Pyx_PyCFunctionFast)(cfunc)->func)(self, &PyTuple_GET_ITEM($empty_tuple, 0), 0) : \
(*(__Pyx_PyCFunctionFastWithKeywords)(cfunc)->func)(self, &PyTuple_GET_ITEM($empty_tuple, 0), 0, NULL)) : \
(*(__Pyx_PyCFunctionFast)(cfunc)->func)(self, &$empty_tuple, 0) : \
(*(__Pyx_PyCFunctionFastWithKeywords)(cfunc)->func)(self, &$empty_tuple, 0, NULL)) : \
(PY_VERSION_HEX >= 0x030700A0 && (cfunc)->flag == (METH_FASTCALL | METH_KEYWORDS) ? \
(*(__Pyx_PyCFunctionFastWithKeywords)(cfunc)->func)(self, &PyTuple_GET_ITEM($empty_tuple, 0), 0, NULL) : \
(*(__Pyx_PyCFunctionFastWithKeywords)(cfunc)->func)(self, &$empty_tuple, 0, NULL) : \
__Pyx__CallUnboundCMethod0(cfunc, self)))))) : \
__Pyx__CallUnboundCMethod0(cfunc, self))
#else
......@@ -1368,7 +1369,7 @@ static PyObject* __Pyx__CallUnboundCMethod1(__Pyx_CachedCFunction* cfunc, PyObje
static PyObject* __Pyx__CallUnboundCMethod1(__Pyx_CachedCFunction* cfunc, PyObject* self, PyObject* arg){
PyObject *args, *result = NULL;
if (unlikely(!cfunc->method) && unlikely(__Pyx_TryUnpackUnboundCMethod(cfunc) < 0)) return NULL;
if (unlikely(!cfunc->func && !cfunc->method) && unlikely(__Pyx_TryUnpackUnboundCMethod(cfunc) < 0)) return NULL;
#if CYTHON_COMPILING_IN_CPYTHON
if (cfunc->func && (cfunc->flag & METH_VARARGS)) {
args = PyTuple_New(1);
......@@ -1399,6 +1400,77 @@ bad:
}
/////////////// CallUnboundCMethod2.proto ///////////////
static PyObject* __Pyx__CallUnboundCMethod2(__Pyx_CachedCFunction* cfunc, PyObject* self, PyObject* arg1, PyObject* arg2); /*proto*/
#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030600B1
static CYTHON_INLINE PyObject *__Pyx_CallUnboundCMethod2(__Pyx_CachedCFunction *cfunc, PyObject *self, PyObject *arg1, PyObject *arg2); /*proto*/
#else
#define __Pyx_CallUnboundCMethod2(cfunc, self, arg1, arg2) __Pyx__CallUnboundCMethod2(cfunc, self, arg1, arg2)
#endif
/////////////// CallUnboundCMethod2 ///////////////
//@requires: UnpackUnboundCMethod
//@requires: PyObjectCall
#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030600B1
static CYTHON_INLINE PyObject *__Pyx_CallUnboundCMethod2(__Pyx_CachedCFunction *cfunc, PyObject *self, PyObject *arg1, PyObject *arg2) {
if (likely(cfunc->func)) {
PyObject *args[2] = {arg1, arg2};
if (cfunc->flag == METH_FASTCALL) {
#if PY_VERSION_HEX >= 0x030700A0
return (*(__Pyx_PyCFunctionFast)cfunc->func)(self, args, 2);
#else
return (*(__Pyx_PyCFunctionFastWithKeywords)cfunc->func)(self, args, 2, NULL);
#endif
}
#if PY_VERSION_HEX >= 0x030700A0
if (cfunc->flag == (METH_FASTCALL | METH_KEYWORDS))
return (*(__Pyx_PyCFunctionFastWithKeywords)cfunc->func)(self, args, 2, NULL);
#endif
}
return __Pyx__CallUnboundCMethod2(cfunc, self, arg1, arg2);
}
#endif
static PyObject* __Pyx__CallUnboundCMethod2(__Pyx_CachedCFunction* cfunc, PyObject* self, PyObject* arg1, PyObject* arg2){
PyObject *args, *result = NULL;
if (unlikely(!cfunc->func && !cfunc->method) && unlikely(__Pyx_TryUnpackUnboundCMethod(cfunc) < 0)) return NULL;
#if CYTHON_COMPILING_IN_CPYTHON
if (cfunc->func && (cfunc->flag & METH_VARARGS)) {
args = PyTuple_New(2);
if (unlikely(!args)) goto bad;
Py_INCREF(arg1);
PyTuple_SET_ITEM(args, 0, arg1);
Py_INCREF(arg2);
PyTuple_SET_ITEM(args, 1, arg2);
if (cfunc->flag & METH_KEYWORDS)
result = (*(PyCFunctionWithKeywords)cfunc->func)(self, args, NULL);
else
result = (*cfunc->func)(self, args);
} else {
args = PyTuple_New(3);
if (unlikely(!args)) goto bad;
Py_INCREF(self);
PyTuple_SET_ITEM(args, 0, self);
Py_INCREF(arg1);
PyTuple_SET_ITEM(args, 1, arg1);
Py_INCREF(arg2);
PyTuple_SET_ITEM(args, 2, arg2);
result = __Pyx_PyObject_Call(cfunc->method, args, NULL);
}
#else
args = PyTuple_Pack(3, self, arg1, arg2);
if (unlikely(!args)) goto bad;
result = __Pyx_PyObject_Call(cfunc->method, args, NULL);
#endif
bad:
Py_XDECREF(args);
return result;
}
/////////////// PyObjectCallMethod0.proto ///////////////
static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name); /*proto*/
......
......@@ -208,9 +208,9 @@ static PyObject* __Pyx_PyDict_GetItemDefault(PyObject* d, PyObject* key, PyObjec
Py_INCREF(value);
} else {
if (default_value == Py_None)
default_value = NULL;
value = PyObject_CallMethodObjArgs(
d, PYIDENT("get"), key, default_value, NULL);
value = CALL_UNBOUND_METHOD(PyDict_Type, "get", d, key);
else
value = CALL_UNBOUND_METHOD(PyDict_Type, "get", d, key, default_value);
}
#endif
return value;
......@@ -222,7 +222,6 @@ static PyObject* __Pyx_PyDict_GetItemDefault(PyObject* d, PyObject* key, PyObjec
static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value, int is_safe_type); /*proto*/
/////////////// dict_setdefault ///////////////
//@requires: ObjectHandling.c::PyObjectCallMethod2
static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value,
CYTHON_UNUSED int is_safe_type) {
......@@ -259,7 +258,7 @@ static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *ke
#endif
#endif
} else {
value = __Pyx_PyObject_CallMethod2(d, PYIDENT("setdefault"), key, default_value);
value = CALL_UNBOUND_METHOD(PyDict_Type, "setdefault", d, key, default_value);
}
return value;
}
......@@ -275,8 +274,6 @@ static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *ke
static CYTHON_INLINE PyObject *__Pyx_PyDict_Pop(PyObject *d, PyObject *key, PyObject *default_value); /*proto*/
/////////////// py_dict_pop ///////////////
//@requires: ObjectHandling.c::PyObjectCallMethod1
//@requires: ObjectHandling.c::PyObjectCallMethod2
static CYTHON_INLINE PyObject *__Pyx_PyDict_Pop(PyObject *d, PyObject *key, PyObject *default_value) {
#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX > 0x030600B3
......@@ -286,9 +283,9 @@ static CYTHON_INLINE PyObject *__Pyx_PyDict_Pop(PyObject *d, PyObject *key, PyOb
// avoid "function unused" warnings
#endif
if (default_value) {
return __Pyx_PyObject_CallMethod2(d, PYIDENT("pop"), key, default_value);
return CALL_UNBOUND_METHOD(PyDict_Type, "pop", d, key, default_value);
} else {
return __Pyx_PyObject_CallMethod1(d, PYIDENT("pop"), key);
return CALL_UNBOUND_METHOD(PyDict_Type, "pop", d, key);
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment