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

Reply via email to