[pypy-commit] pypy cpyext-fast-typecheck: WIP: modify the W_PyCWrapperObject call logic: instead of using a very generic logic which always build a tuple containing the arguments, we specify the expected arity and go through a specialized fast path
antocuni
pypy.commits at gmail.com
Thu Mar 22 08:04:50 EDT 2018
Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: cpyext-fast-typecheck
Changeset: r94066:ba7b2efa9585
Date: 2018-03-22 13:02 +0100
http://bitbucket.org/pypy/pypy/changeset/ba7b2efa9585/
Log: WIP: modify the W_PyCWrapperObject call logic: instead of using a
very generic logic which always build a tuple containing the
arguments, we specify the expected arity and go through a
specialized fast path
diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -213,12 +213,14 @@
(self.name, self.w_objclass.getname(self.space)))
-
class W_PyCWrapperObject(W_Root):
- def __init__(self, space, pto, method_name, wrapper_func,
+ _immutable_fields_ = ["arity"]
+
+ def __init__(self, space, pto, method_name, arity, wrapper_func,
wrapper_func_kwds, doc, func, offset=None):
self.space = space
self.method_name = method_name
+ self.arity = arity
self.wrapper_func = wrapper_func
self.wrapper_func_kwds = wrapper_func_kwds
self.doc = doc
@@ -229,18 +231,10 @@
assert isinstance(w_type, W_TypeObject)
self.w_objclass = w_type
- def descr_call(self, space, w_self, __args__):
- args_w, kw_w = __args__.unpack()
- w_args = space.newtuple(args_w)
- w_kw = space.newdict()
- for key, w_obj in kw_w.items():
- space.setitem(w_kw, space.newtext(key), w_obj)
- return self.call(space, w_self, w_args, w_kw)
-
- def call(self, space, w_self, w_args, w_kw):
+ def _get_func_to_call(self):
func_to_call = self.func
if self.offset:
- pto = as_pyobj(space, self.w_objclass)
+ pto = as_pyobj(self.space, self.w_objclass)
# make ptr the equivalent of this, using the offsets
#func_to_call = rffi.cast(rffi.VOIDP, ptr.c_tp_as_number.c_nb_multiply)
if pto:
@@ -254,6 +248,36 @@
assert False, "failed to convert w_type %s to PyObject" % str(
self.w_objclass)
assert func_to_call
+ return func_to_call
+
+ def descr_call(self, space, w_self, __args__):
+ if self.arity == -1:
+ # slow, fallback logic: eventually, this should be killed
+ args_w, kw_w = __args__.unpack()
+ w_args = space.newtuple(args_w)
+ w_kw = space.newdict()
+ for key, w_obj in kw_w.items():
+ space.setitem(w_kw, space.newtext(key), w_obj)
+ return self.call(space, w_self, w_args, w_kw)
+ #
+ # new logic
+ # XXX: check for keywords
+ length = len(__args__.arguments_w)
+ if length != self.arity:
+ raise oefmt(space.w_TypeError, "expected %d arguments, got %d",
+ self.arity, length)
+ if self.arity == 1:
+ return self.call_1(space, w_self, __args__)
+
+ assert False, 'should not arrive here'
+
+ def call_1(self, space, w_self, __args__):
+ func = self._get_func_to_call()
+ w_o = __args__.arguments_w[0]
+ return self.wrapper_func(space, func, w_self, w_o)
+
+ def call(self, space, w_self, w_args, w_kw):
+ func_to_call = self._get_func_to_call()
if self.wrapper_func is None:
assert self.wrapper_func_kwds is not None
return self.wrapper_func_kwds(space, w_self, w_args, func_to_call,
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -84,11 +84,9 @@
check_num_args(space, w_args, 0)
return generic_cpy_call(space, func_unary, w_self)
-def wrap_binaryfunc(space, w_self, w_args, func):
+def wrap_binaryfunc(space, func, w_self, w_x):
func_binary = rffi.cast(binaryfunc, func)
- check_num_args(space, w_args, 1)
- args_w = space.fixedview(w_args)
- return generic_cpy_call(space, func_binary, w_self, args_w[0])
+ return generic_cpy_call(space, func_binary, w_self, w_x)
def _get_ob_type(space, w_obj):
# please ensure that w_obj stays alive
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -338,7 +338,15 @@
continue
if wrapper_func is None and wrapper_func_kwds is None:
continue
- w_obj = W_PyCWrapperObject(space, pto, method_name, wrapper_func,
+
+ arity = -1
+ from pypy.module.cpyext.slotdefs import wrap_binaryfunc
+ if wrapper_func is wrap_binaryfunc:
+ # XXX: this is just a quick hack, we need an official way to
+ # specify the arity
+ arity = 1
+
+ w_obj = W_PyCWrapperObject(space, pto, method_name, arity, wrapper_func,
wrapper_func_kwds, doc, func_voidp, offset=offset)
dict_w[method_name] = w_obj
if pto.c_tp_doc:
More information about the pypy-commit
mailing list