Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(2)

Unified Diff: Objects/typeobject.c

Issue 29259: Add tp_fastcall to PyTypeObject: support FASTCALL calling convention for all callable objects
Patch Set: Created 3 years ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
--- a/Objects/typeobject.c Wed Jan 25 23:33:27 2017 +0100
+++ b/Objects/typeobject.c Thu Jan 26 02:43:18 2017 +0100
@@ -4690,6 +4690,35 @@ overrides_hash(PyTypeObject *type)
return 0;
}
+/* tp_call slot calling tp_fastcall */
+static PyObject *
+fastcall_wrapper(PyObject *callable, PyObject *args_tuple, PyObject *kwargs)
+{
+ PyTypeObject *type;
+ PyObject *result;
+
+ type = Py_TYPE(callable);
+ while (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_FASTCALL)
+ || type->tp_fastcall == NULL) {
+ PyTypeObject *base = type->tp_base;
+ if (base == type || base == NULL) {
+ PyErr_SetString(PyExc_SystemError,
+ "unable to find tp_fastcall in a base classes");
+ return NULL;
+ }
+ type = base;
+ }
+
+ result = _Py_RawFastCallDict(callable,
+ type->tp_fastcall,
+ &PyTuple_GET_ITEM(args_tuple, 0),
+ PyTuple_GET_SIZE(args_tuple),
+ kwargs);
+
+ result = _Py_CheckFunctionResult(callable, result, NULL);
+ return result;
+}
+
static void
inherit_slots(PyTypeObject *type, PyTypeObject *base)
{
@@ -4813,7 +4842,19 @@ inherit_slots(PyTypeObject *type, PyType
/* tp_reserved is ignored */
COPYSLOT(tp_repr);
/* tp_hash see tp_richcompare */
- COPYSLOT(tp_call);
+
+ if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_FASTCALL)
+ && PyType_HasFeature(base, Py_TPFLAGS_HAVE_FASTCALL)
+ /* don't inherit tp_fastcall if tp_call is defined */
+ && (type->tp_call == NULL || type->tp_call != fastcall_wrapper)) {
+ COPYSLOT(tp_fastcall);
+ }
+
+ if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_FASTCALL)
+ || type->tp_call != fastcall_wrapper) {
+ COPYSLOT(tp_call);
+ }
+
COPYSLOT(tp_str);
{
/* Copy comparison-related slots only when
@@ -4942,6 +4983,15 @@ PyType_Ready(PyTypeObject *type)
type->tp_dict = dict;
}
+ if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_FASTCALL)
+ && type->tp_fastcall && !type->tp_call) {
+ /* tp_fastcall defined, but not tp_call: tp_call will use a wrapper
+ calling tp_fastcall. We need to define tp_call before calling
+ add_operators(), otherwise the __call__ descriptor is not
+ defined. */
+ type->tp_call = fastcall_wrapper;
+ }
+
/* Add type-specific descriptors to tp_dict */
if (add_operators(type) < 0)
goto error;
@@ -5498,6 +5548,15 @@ wrap_call(PyObject *self, PyObject *args
}
static PyObject *
+wrap_fastcall(PyObject *self, void *wrapped,
+ PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ fastternaryfunc func = (fastternaryfunc)wrapped;
+
+ return (*func)(self, args, nargs, kwnames);
+}
+
+static PyObject *
wrap_del(PyObject *self, PyObject *args, void *wrapped)
{
destructor func = (destructor)wrapped;
@@ -6160,6 +6219,22 @@ slot_tp_call(PyObject *self, PyObject *a
return res;
}
+static PyObject *
+slot_tp_fastcall(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
+{
+ _Py_IDENTIFIER(__call__);
+ PyObject *meth = lookup_method(self, &PyId___call__);
inada.naoki 2017/01/26 10:10:38 slot_tp_call has _Py_IDENTIFIER(__call__) too. Let
+ PyObject *res;
+
+ if (meth == NULL)
+ return NULL;
+
+ res = _PyObject_FastCallKeywords(meth, args, nargs, kwnames);
+
+ Py_DECREF(meth);
+ return res;
+}
+
/* There are two slot dispatch functions for tp_getattro.
- slot_tp_getattro() is used when __getattribute__ is overridden
@@ -6513,13 +6588,16 @@ typedef struct wrapperbase slotdef;
#undef RBINSLOT
#define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
- {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \
+ {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, NULL, \
PyDoc_STR(DOC)}
#define FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS) \
- {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \
+ {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, NULL, \
+ PyDoc_STR(DOC), FLAGS}
+#define FLSLOT_FAST(NAME, SLOT, FUNCTION, WRAPPER, FAST_WRAPPER, DOC, FLAGS) \
+ {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, FAST_WRAPPER, \
PyDoc_STR(DOC), FLAGS}
#define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
- {NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \
+ {NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, NULL, \
PyDoc_STR(DOC)}
#define AMSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \
ETSLOT(NAME, as_async.SLOT, FUNCTION, WRAPPER, DOC)
@@ -6557,7 +6635,7 @@ static slotdef slotdefs[] = {
"__repr__($self, /)\n--\n\nReturn repr(self)."),
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc,
"__hash__($self, /)\n--\n\nReturn hash(self)."),
- FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call,
+ FLSLOT_FAST("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call, wrap_fastcall,
"__call__($self, /, *args, **kwargs)\n--\n\nCall self as a function.",
PyWrapperFlag_KEYWORDS),
TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc,
@@ -6831,7 +6909,7 @@ update_one_slot(PyTypeObject *type, slot
void *generic = NULL, *specific = NULL;
int use_generic = 0;
int offset = p->offset;
- void **ptr = slotptr(type, offset);
+ void **ptr = slotptr(type, offset), **ptr2 = NULL;
if (ptr == NULL) {
do {
@@ -6839,10 +6917,12 @@ update_one_slot(PyTypeObject *type, slot
} while (p->offset == offset);
return p;
}
+
do {
descr = _PyType_Lookup(type, p->name_strobj);
if (descr == NULL) {
if (ptr == (void**)&type->tp_iternext) {
+ ptr2 = NULL;
specific = (void *)_PyObject_NextNotImplemented;
}
continue;
@@ -6850,10 +6930,23 @@ update_one_slot(PyTypeObject *type, slot
if (Py_TYPE(descr) == &PyWrapperDescr_Type &&
((PyWrapperDescrObject *)descr)->d_base->name_strobj == p->name_strobj) {
void **tptr = resolve_slotdups(type, p->name_strobj);
+ int same_wrapper;
+
if (tptr == NULL || tptr == ptr)
generic = p->function;
d = (PyWrapperDescrObject *)descr;
- if (d->d_base->wrapper == p->wrapper &&
+
+ if (d->d_use_fastwrapper) {
+ same_wrapper = (d->d_base->fastwrapper == p->fastwrapper);
+
+ assert(p->wrapper == (void *)wrap_call);
+ ptr2 = (void **)&type->tp_fastcall;
+ }
+ else {
+ same_wrapper = (d->d_base->wrapper == p->wrapper);
+ }
+
+ if (same_wrapper &&
PyType_IsSubtype(type, PyDescr_TYPE(d)))
{
if (specific == NULL ||
@@ -6879,7 +6972,10 @@ update_one_slot(PyTypeObject *type, slot
sanity checks and constructing a new argument
list. Cut all that nonsense short -- this speeds
up instance creation tremendously. */
+
specific = (void *)type->tp_new;
+ ptr2 = NULL;
+
/* XXX I'm not 100% sure that there isn't a hole
in this reasoning that requires additional
sanity checks. I'll buy the first person to
@@ -6891,16 +6987,36 @@ update_one_slot(PyTypeObject *type, slot
to prevent inheritance of the default
implementation from object.__hash__ */
specific = (void *)PyObject_HashNotImplemented;
+ ptr2 = NULL;
}
else {
use_generic = 1;
generic = p->function;
}
} while ((++p)->offset == offset);
- if (specific && !use_generic)
+
+ if (specific && !use_generic) {
+ if (ptr2 != NULL) {
+ ptr = ptr2;
+ }
*ptr = specific;
- else
+ }
+ else {
*ptr = generic;
+ }
+
+ if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_FASTCALL)) {
+ /* synchronize tp_call and tp_fastcall slots */
+ if (ptr == (void **)&type->tp_call) {
+ if (type->tp_call == slot_tp_call) {
+ type->tp_fastcall = slot_tp_fastcall;
+ }
+ }
+ else if (ptr == (void **)&type->tp_fastcall) {
+ type->tp_call = fastcall_wrapper;
+ }
+ }
+
return p;
}
@@ -6992,8 +7108,9 @@ fixup_slot_dispatchers(PyTypeObject *typ
slotdef *p;
init_slotdefs();
- for (p = slotdefs; p->name; )
+ for (p = slotdefs; p->name; ) {
p = update_one_slot(type, p);
+ }
}
static void
@@ -7173,7 +7290,24 @@ add_operators(PyTypeObject *type)
return -1;
}
else {
- descr = PyDescr_NewWrapper(type, p, *ptr);
+ int use_fastwrapper;
+ void *wrapped;
+
+ if (*ptr == fastcall_wrapper) {
+ /* A wrapper must not call fastcall_wrapper() but the specific
+ tp_fastcall. fastcall_wrapper() is called with an instance.
+ From an instance, it's not possible to find the specific
+ function. */
haypo 2017/01/26 03:35:21 This comment should be rephrased.
+ use_fastwrapper = 1;
+ wrapped = type->tp_fastcall;
+ }
+ else {
+ use_fastwrapper = 0;
+ wrapped = *ptr;
+ }
+ assert(wrapped != NULL);
+
+ descr = _PyDescr_NewWrapperEx(type, p, wrapped, use_fastwrapper);
if (descr == NULL)
return -1;
if (PyDict_SetItem(dict, p->name_strobj, descr) < 0) {
« Objects/methodobject.c ('K') | « Objects/methodobject.c ('k') | Objects/weakrefobject.c » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+