diff options
Diffstat (limited to 'Objects/methodobject.c')
| -rw-r--r-- | Objects/methodobject.c | 152 | 
1 files changed, 152 insertions, 0 deletions
| diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 946357f24a..c2001f0169 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -97,6 +97,11 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds)      if (flags == (METH_VARARGS | METH_KEYWORDS)) {          res = (*(PyCFunctionWithKeywords)meth)(self, args, kwds);      } +    else if (flags == METH_FASTCALL) { +        PyObject **stack = &PyTuple_GET_ITEM(args, 0); +        Py_ssize_t nargs = PyTuple_GET_SIZE(args); +        res = _PyCFunction_FastCallDict(func, stack, nargs, kwds); +    }      else {          if (kwds != NULL && PyDict_Size(kwds) != 0) {              PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", @@ -145,6 +150,153 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds)      return _Py_CheckFunctionResult(func, res, NULL);  } +PyObject * +_PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, +                          PyObject *kwargs) +{ +    PyCFunctionObject *func = (PyCFunctionObject*)func_obj; +    PyCFunction meth = PyCFunction_GET_FUNCTION(func); +    PyObject *self = PyCFunction_GET_SELF(func); +    PyObject *result; +    int flags; + +    assert(PyCFunction_Check(func)); +    assert(func != NULL); +    assert(nargs >= 0); +    assert(nargs == 0 || args != NULL); +    assert(kwargs == NULL || PyDict_Check(kwargs)); + +    /* _PyCFunction_FastCallDict() must not be called with an exception set, +       because it may clear it (directly or indirectly) and so the +       caller loses its exception */ +    assert(!PyErr_Occurred()); + +    flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + +    switch (flags) +    { +    case METH_NOARGS: +        if (kwargs != NULL && PyDict_Size(kwargs) != 0) { +            PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", +                         func->m_ml->ml_name); +            return NULL; +        } + +        if (nargs != 0) { +            PyErr_Format(PyExc_TypeError, +                "%.200s() takes no arguments (%zd given)", +                func->m_ml->ml_name, nargs); +            return NULL; +        } + +        result = (*meth) (self, NULL); +        break; + +    case METH_O: +        if (kwargs != NULL && PyDict_Size(kwargs) != 0) { +            PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", +                         func->m_ml->ml_name); +            return NULL; +        } + +        if (nargs != 1) { +            PyErr_Format(PyExc_TypeError, +                "%.200s() takes exactly one argument (%zd given)", +                func->m_ml->ml_name, nargs); +            return NULL; +        } + +        result = (*meth) (self, args[0]); +        break; + +    case METH_VARARGS: +    case METH_VARARGS | METH_KEYWORDS: +    { +        /* Slow-path: create a temporary tuple */ +        PyObject *tuple; + +        if (!(flags & METH_KEYWORDS) && kwargs != NULL && PyDict_Size(kwargs) != 0) { +            PyErr_Format(PyExc_TypeError, +                         "%.200s() takes no keyword arguments", +                         func->m_ml->ml_name); +            return NULL; +        } + +        tuple = _PyStack_AsTuple(args, nargs); +        if (tuple == NULL) { +            return NULL; +        } + +        if (flags & METH_KEYWORDS) { +            result = (*(PyCFunctionWithKeywords)meth) (self, tuple, kwargs); +        } +        else { +            result = (*meth) (self, tuple); +        } +        Py_DECREF(tuple); +        break; +    } + +    case METH_FASTCALL: +    { +        PyObject **stack; +        PyObject *kwnames; +        _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth; + +        stack = _PyStack_UnpackDict(args, nargs, kwargs, &kwnames, func_obj); +        if (stack == NULL) { +            return NULL; +        } + +        result = (*fastmeth) (self, stack, nargs, kwnames); +        if (stack != args) { +            PyMem_Free(stack); +        } +        Py_XDECREF(kwnames); +        break; +    } + +    default: +        PyErr_SetString(PyExc_SystemError, +                        "Bad call flags in PyCFunction_Call. " +                        "METH_OLDARGS is no longer supported!"); +        return NULL; +    } + +    result = _Py_CheckFunctionResult(func_obj, result, NULL); + +    return result; +} + +PyObject * +_PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack, +                              Py_ssize_t nargs, PyObject *kwnames) +{ +    PyObject *kwdict, *result; +    Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + +    assert(PyCFunction_Check(func)); +    assert(nargs >= 0); +    assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); +    assert((nargs == 0 && nkwargs == 0) || stack != NULL); +    /* kwnames must only contains str strings, no subclass, and all keys must +       be unique */ + +    if (nkwargs > 0) { +        kwdict = _PyStack_AsDict(stack + nargs, kwnames); +        if (kwdict == NULL) { +            return NULL; +        } +    } +    else { +        kwdict = NULL; +    } + +    result = _PyCFunction_FastCallDict(func, stack, nargs, kwdict); +    Py_XDECREF(kwdict); +    return result; +} +  /* Methods (the standard built-in methods, that is) */  static void | 
