LOAD_METHOD support for C methods

refer python/cpython@5566bbb8d5
refer python/cpython@93fac8dd35
refer python/cpython@7638eb892a
refer python/cpython@25b87d3567

useful to keep the latest tag of 3.7 nearby when small things like
function signatures change, helps to view the final form.
This commit is contained in:
ahgamut 2021-11-19 09:07:30 +05:30
parent 7328c09cd4
commit 281e84da03
4 changed files with 77 additions and 3 deletions

View file

@ -91,6 +91,8 @@ PyObject * PyDescr_NewMember(PyTypeObject *,
PyObject * PyDescr_NewGetSet(PyTypeObject *, PyObject * PyDescr_NewGetSet(PyTypeObject *,
struct PyGetSetDef *); struct PyGetSetDef *);
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
PyObject * _PyMethodDescr_FastCallKeywords(
PyObject *descrobj, PyObject *const *stack, Py_ssize_t nargs, PyObject *kwnames);
PyObject * PyDescr_NewWrapper(PyTypeObject *, PyObject * PyDescr_NewWrapper(PyTypeObject *,
struct wrapperbase *, void *); struct wrapperbase *, void *);
#define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL) #define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL)

View file

@ -95,12 +95,20 @@ typedef struct {
PyObject *m_module; /* The __module__ attribute, can be anything */ PyObject *m_module; /* The __module__ attribute, can be anything */
PyObject *m_weakreflist; /* List of weak references */ PyObject *m_weakreflist; /* List of weak references */
} PyCFunctionObject; } PyCFunctionObject;
PyObject * _PyMethodDef_RawFastCallDict( PyObject * _PyMethodDef_RawFastCallDict(
PyMethodDef *method, PyMethodDef *method,
PyObject *self, PyObject *self,
PyObject **args, PyObject **args,
Py_ssize_t nargs, Py_ssize_t nargs,
PyObject *kwargs); PyObject *kwargs);
PyObject * _PyMethodDef_RawFastCallKeywords(
PyMethodDef *method,
PyObject *self,
PyObject **args,
Py_ssize_t nargs,
PyObject *kwnames);
#endif #endif
int PyCFunction_ClearFreeList(void); int PyCFunction_ClearFreeList(void);

View file

@ -264,6 +264,44 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs)
return result; return result;
} }
// same to methoddescr_call(), but use FASTCALL convention.
PyObject *
_PyMethodDescr_FastCallKeywords(PyObject *descrobj,
PyObject *const *args, Py_ssize_t nargs,
PyObject *kwnames)
{
assert(Py_TYPE(descrobj) == &PyMethodDescr_Type);
PyMethodDescrObject *descr = (PyMethodDescrObject *)descrobj;
PyObject *self, *result;
/* Make sure that the first argument is acceptable as 'self' */
if (nargs < 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 = args[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;
}
result = _PyMethodDef_RawFastCallKeywords(descr->d_method, self,
args+1, nargs-1, kwnames);
result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
return result;
}
static PyObject * static PyObject *
classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
PyObject *kwds) PyObject *kwds)

View file

@ -13,6 +13,7 @@
#include "third_party/python/Include/ceval.h" #include "third_party/python/Include/ceval.h"
#include "third_party/python/Include/classobject.h" #include "third_party/python/Include/classobject.h"
#include "third_party/python/Include/code.h" #include "third_party/python/Include/code.h"
#include "third_party/python/Include/descrobject.h"
#include "third_party/python/Include/dictobject.h" #include "third_party/python/Include/dictobject.h"
#include "third_party/python/Include/eval.h" #include "third_party/python/Include/eval.h"
#include "third_party/python/Include/frameobject.h" #include "third_party/python/Include/frameobject.h"
@ -4820,16 +4821,41 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
PyObject *x, *w; PyObject *x, *w;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
Py_ssize_t nargs = oparg - nkwargs; Py_ssize_t nargs = oparg - nkwargs;
PyObject **stack; PyObject **stack = (*pp_stack) - nargs - nkwargs;
/* Always dispatch PyCFunction first, because these are /* Always dispatch PyCFunction first, because these are
presumed to be the most frequent callable object. presumed to be the most frequent callable object.
*/ */
if (PyCFunction_Check(func)) { if (PyCFunction_Check(func)) {
PyThreadState *tstate = PyThreadState_GET(); PyThreadState *tstate = PyThreadState_GET();
PCALL(PCALL_CFUNCTION); PCALL(PCALL_CFUNCTION);
stack = (*pp_stack) - nargs - nkwargs;
C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames)); C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
} }
else if (Py_TYPE(func) == &PyMethodDescr_Type) {
PyThreadState *tstate = PyThreadState_GET();
if (nargs > 0 && tstate->use_tracing) {
/* We need to create a temporary bound method as argument
for profiling.
If nargs == 0, then this cannot work because we have no
"self". In any case, the call itself would raise
TypeError (foo needs an argument), so we just skip
profiling. */
PyObject *self = stack[0];
func = Py_TYPE(func)->tp_descr_get(func, self, (PyObject*)Py_TYPE(self));
if (func != NULL) {
C_TRACE(x, _PyCFunction_FastCallKeywords(func,
stack+1, nargs-1,
kwnames));
Py_DECREF(func);
}
else {
x = NULL;
}
}
else {
x = _PyMethodDescr_FastCallKeywords(func, stack, nargs, kwnames);
}
}
else { else {
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
/* optimize access to bound methods */ /* optimize access to bound methods */
@ -4841,11 +4867,11 @@ call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
Py_INCREF(func); Py_INCREF(func);
Py_SETREF(*pfunc, self); Py_SETREF(*pfunc, self);
nargs++; nargs++;
stack--;
} }
else { else {
Py_INCREF(func); Py_INCREF(func);
} }
stack = (*pp_stack) - nargs - nkwargs;
if (PyFunction_Check(func)) { if (PyFunction_Check(func)) {
x = _PyFunction_FastCallKeywords(func, stack, nargs, kwnames); x = _PyFunction_FastCallKeywords(func, stack, nargs, kwnames);
} }