Author: Antonio Cuni <[email protected]>
Branch: cpyext-refactor-methodobject
Changeset: r92767:cefeba1a1de2
Date: 2017-10-14 18:30 +0200
http://bitbucket.org/pypy/pypy/changeset/cefeba1a1de2/
Log: when calling a METH_VARARGS, create directly a PyTuple, instead of
passing from a w_tuple; in theory, this should make the args tuple
to die very quickly, and thus make a more effective usage of
freelists
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
@@ -15,6 +15,8 @@
build_type_checkers)
from pypy.module.cpyext.pyobject import (
decref, from_ref, make_ref, as_pyobj, make_typedescr)
+from pypy.module.cpyext.state import State
+from pypy.module.cpyext.tupleobject import PyTuple_SetItem
PyMethodDef = cts.gettype('PyMethodDef')
PyCFunction = cts.gettype('PyCFunction')
@@ -128,10 +130,18 @@
# METH_VARARGS
def descr_call(self, space, args_w):
+ state = space.fromcache(State)
w_self = self.w_self
func = self.ml.c_ml_meth
- w_args = space.newtuple(args_w)
- return generic_cpy_call(space, func, w_self, w_args)
+ n = len(args_w)
+ py_args = state.C.PyTuple_New(n)
+ for i, w_item in enumerate(args_w):
+ py_item = make_ref(space, w_item)
+ PyTuple_SetItem(space, py_args, i, py_item)
+ try:
+ return generic_cpy_call(space, func, w_self, py_args)
+ finally:
+ decref(space, py_args)
class W_PyCMethodObject(W_PyCFunctionObject):
w_self = None
diff --git a/pypy/module/cpyext/test/test_methodobject.py
b/pypy/module/cpyext/test/test_methodobject.py
--- a/pypy/module/cpyext/test/test_methodobject.py
+++ b/pypy/module/cpyext/test/test_methodobject.py
@@ -69,14 +69,26 @@
'''
),
])
- tup, _ = mod.getarg_VARARGS()
+ # check that we pass the expected tuple of arguments AND that the
+ # recnt is 1. In particular, on PyPy refcnt==1 means that we created
+ # the PyObject tuple directly, without passing from a w_tuple; as
+ # such, the tuple will be immediately freed after the call, without
+ # having to wait until the GC runs.
+ #
+ tup, refcnt = mod.getarg_VARARGS()
assert tup == ()
+ # the empty tuple is shared on CPython, so the refcnt will be >1. On
+ # PyPy it is not shared, though.
+ if not self.runappdirect:
+ assert refcnt == 1
#
- tup, _ = mod.getarg_VARARGS(1)
+ tup, refcnt = mod.getarg_VARARGS(1)
assert tup == (1,)
+ assert refcnt == 1
#
- tup, _ = mod.getarg_VARARGS(1, 2, 3)
+ tup, refcnt = mod.getarg_VARARGS(1, 2, 3)
assert tup == (1, 2, 3)
+ assert refcnt == 1
#
raises(TypeError, mod.getarg_VARARGS, k=1)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit