[pypy-svn] r77594 - in pypy/branch/jitffi/pypy: jit/metainterp/test rlib/test

antocuni at codespeak.net antocuni at codespeak.net
Tue Oct 5 11:21:41 CEST 2010


Author: antocuni
Date: Tue Oct  5 11:21:39 2010
New Revision: 77594

Modified:
   pypy/branch/jitffi/pypy/jit/metainterp/test/test_fficall.py
   pypy/branch/jitffi/pypy/rlib/test/test_clibffi.py
   pypy/branch/jitffi/pypy/rlib/test/test_libffi.py
Log:
refactor the test to share most of the between test_libffi and test_fficall.
The reason is that ffi calls now really follow two different paths when jitted
or non jitted, so we need to always test both.



Modified: pypy/branch/jitffi/pypy/jit/metainterp/test/test_fficall.py
==============================================================================
--- pypy/branch/jitffi/pypy/jit/metainterp/test/test_fficall.py	(original)
+++ pypy/branch/jitffi/pypy/jit/metainterp/test/test_fficall.py	Tue Oct  5 11:21:39 2010
@@ -1,104 +1,43 @@
 
 import py
 from pypy.rlib.jit import JitDriver, hint
-from pypy.jit.metainterp.test.test_basic import LLJitMixin
-from pypy.rlib.libffi import CDLL, types, ArgChain, Func
-from pypy.tool.udir import udir
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.translator.platform import platform
+from pypy.rlib.unroll import unrolling_iterable
+from pypy.rlib.libffi import ArgChain
+from pypy.rlib.test.test_libffi import TestLibffiCall as _TestLibffiCall
 from pypy.rpython.lltypesystem import lltype, rffi
-
-class TestFfiCall(LLJitMixin):
-    def setup_class(cls):
-        # prepare C code as an example, so we can load it and call
-        # it via rlib.libffi
-        c_file = udir.ensure("test_jit_fficall", dir=1).join("xlib.c")
-        c_file.write(py.code.Source('''
-        int sum_xy(int x, double y)
-        {
-            return (x + (int)y);
-        }
-
-        float abs(double x)
-        {
-            if (x<0)
-                return -x;
-            return x;
-        }
-
-        unsigned char cast_to_uchar(int x)
-        {
-            return 200+(unsigned char)x;
-        }
-        '''))
-        eci = ExternalCompilationInfo(export_symbols=[])
-        cls.lib_name = str(platform.compile([c_file], eci, 'x',
-                                            standalone=False))
-
-    def test_simple(self):
-        driver = JitDriver(reds = ['n', 'func'], greens = [])        
-
-        def f(n):
-            cdll = CDLL(self.lib_name)
-            func = cdll.getpointer('sum_xy', [types.sint, types.double],
-                                   types.sint)
-            while n < 10:
-                driver.jit_merge_point(n=n, func=func)
-                driver.can_enter_jit(n=n, func=func)
-                func = hint(func, promote=True)
-                argchain = ArgChain()
-                argchain.arg(n).arg(1.2)
-                n = func.call(argchain, rffi.LONG)
-            return n
-            
-        res = self.meta_interp(f, [0])
-        assert res == 10
-        self.check_loops({
-                'call': 1,
-                'guard_no_exception': 1,
-                'int_lt': 1,
-                'guard_true': 1,
-                'jump': 1})
+from pypy.jit.metainterp.test.test_basic import LLJitMixin
 
 
-    def test_float_result(self):
-        driver = JitDriver(reds = ['n', 'func', 'res'], greens = [])        
+class TestFfiCall(LLJitMixin, _TestLibffiCall):
 
+    def call(self, funcspec, args, RESULT, init_result=0):
+        """
+        Call the function specified by funcspec in a loop, and let the jit to
+        see and optimize it.
+        """
+        #
+        lib, name, argtypes, restype = funcspec
+        args = unrolling_iterable(args)
+        #
+        reds = ['n', 'res', 'func']
+        if type(init_result) is float:
+            reds = ['n', 'func', 'res'] # floats must be *after* refs
+        driver = JitDriver(reds=reds, greens=[])
+        #
         def f(n):
-            cdll = CDLL(self.lib_name)
-            func = cdll.getpointer('abs', [types.double], types.double)
-            res = 0.0
+            func = lib.getpointer(name, argtypes, restype)
+            res = init_result
             while n < 10:
-                driver.jit_merge_point(n=n, func=func, res=res)
-                driver.can_enter_jit(n=n, func=func, res=res)
+                driver.jit_merge_point(n=n, res=res, func=func)
+                driver.can_enter_jit(n=n, res=res, func=func)
                 func = hint(func, promote=True)
                 argchain = ArgChain()
-                argchain.arg(float(-n))
-                res = func.call(argchain, rffi.DOUBLE)
+                for argval in args: # this loop is unrolled
+                    argchain.arg(argval)
+                res = func.call(argchain, RESULT)
                 n += 1
             return res
-            
+        #
         res = self.meta_interp(f, [0])
-        assert res == 9
-        self.check_loops(call=1)
-
-    def test_cast_result(self):
-        driver = JitDriver(reds = ['n', 'res', 'func'], greens = [])        
+        return res
 
-        def f(n):
-            cdll = CDLL(self.lib_name)
-            func = cdll.getpointer('cast_to_uchar', [types.sint],
-                                   types.uchar)
-            res = 0
-            while n < 10:
-                driver.jit_merge_point(n=n, func=func, res=res)
-                driver.can_enter_jit(n=n, func=func, res=res)
-                func = hint(func, promote=True)
-                argchain = ArgChain()
-                argchain.arg(0)
-                res = func.call(argchain, rffi.UCHAR)
-                n += 1
-            return res
-            
-        res = self.meta_interp(f, [0])
-        assert res == 200

Modified: pypy/branch/jitffi/pypy/rlib/test/test_clibffi.py
==============================================================================
--- pypy/branch/jitffi/pypy/rlib/test/test_clibffi.py	(original)
+++ pypy/branch/jitffi/pypy/rlib/test/test_clibffi.py	Tue Oct  5 11:21:39 2010
@@ -20,7 +20,10 @@
         return 'libm.so'
 
 class BaseFfiTest(object):
-    
+
+    CDLL = None # overridden by subclasses
+
+    @classmethod
     def setup_class(cls):
         for name in type_names:
             # XXX force this to be seen by ll2ctypes
@@ -31,14 +34,17 @@
     def setup_method(self, meth):
         ALLOCATED.clear()
     
-
-class TestCLibffi(BaseFfiTest):
-
     def get_libc(self):
-        return CDLL(get_libc_name())
+        return self.CDLL(get_libc_name())
     
     def get_libm(self):
-        return CDLL(get_libm_name(sys.platform))
+        return self.CDLL(get_libm_name(sys.platform))
+
+
+
+class TestCLibffi(BaseFfiTest):
+
+    CDLL = CDLL
 
     def test_library_open(self):
         lib = self.get_libc()

Modified: pypy/branch/jitffi/pypy/rlib/test/test_libffi.py
==============================================================================
--- pypy/branch/jitffi/pypy/rlib/test/test_libffi.py	(original)
+++ pypy/branch/jitffi/pypy/rlib/test/test_libffi.py	Tue Oct  5 11:21:39 2010
@@ -5,17 +5,9 @@
 from pypy.rlib.test.test_clibffi import BaseFfiTest, get_libm_name
 from pypy.rlib.libffi import CDLL, Func, get_libc_name, ArgChain, types
 
+class TestLibffiMisc(BaseFfiTest):
 
-class TestLibffi(BaseFfiTest):
-    """
-    Test the new JIT-friendly interface to libffi
-    """
-
-    def get_libc(self):
-        return CDLL(get_libc_name())
-    
-    def get_libm(self):
-        return CDLL(get_libm_name(sys.platform))
+    CDLL = CDLL
 
     def test_argchain(self):
         chain = ArgChain()
@@ -46,11 +38,100 @@
         del lib
         assert not ALLOCATED
 
-    def test_call_argchain(self):
+
+class TestLibffiCall(BaseFfiTest):
+    """
+    Test various kind of calls through libffi.
+
+    The peculiarity of these tests is that they are run both directly (going
+    really through libffi) and by jit/metainterp/test/test_fficall.py, which
+    tests the call when JITted.
+
+    If you need to test a behaviour than it's not affected by JITing (e.g.,
+    typechecking), you should put your test in TestLibffiMisc.
+    """
+
+    CDLL = CDLL
+
+    @classmethod
+    def setup_class(cls):
+        from pypy.tool.udir import udir
+        from pypy.translator.tool.cbuild import ExternalCompilationInfo
+        from pypy.translator.platform import platform
+
+        BaseFfiTest.setup_class()
+        # prepare C code as an example, so we can load it and call
+        # it via rlib.libffi
+        c_file = udir.ensure("test_libffi", dir=1).join("foolib.c")
+        c_file.write(py.code.Source('''
+        int sum_xy(int x, double y)
+        {
+            return (x + (int)y);
+        }
+
+        unsigned char cast_to_uchar_and_ovf(int x)
+        {
+            return 200+(unsigned char)x;
+        }
+        '''))
+        eci = ExternalCompilationInfo(export_symbols=[])
+        cls.libfoo_name = str(platform.compile([c_file], eci, 'x',
+                                               standalone=False))
+
+    def get_libfoo(self):
+        return self.CDLL(self.libfoo_name)
+
+    def call(self, funcspec, args, RESULT, init_result=0):
+        """
+        Call the specified function after constructing and ArgChain with the
+        arguments in ``args``.
+
+        The function is specified with ``funcspec``, which is a tuple of the
+        form (lib, name, argtypes, restype).
+
+        This method is overridden by metainterp/test/test_fficall.py in
+        order to do the call in a loop and JIT it. The optional arguments are
+        used only by that overridden method.
+        
+        """
+        lib, name, argtypes, restype = funcspec
+        func = lib.getpointer(name, argtypes, restype)
+        chain = ArgChain()
+        for arg in args:
+            chain.arg(arg)
+        return func.call(chain, RESULT)
+
+    def check_loops(self, *args, **kwds):
+        """
+        Ignored here, but does something in the JIT tests
+        """
+        pass
+
+    # ------------------------------------------------------------------------
+
+    def test_simple(self):
+        libfoo = self.get_libfoo() 
+        func = (libfoo, 'sum_xy', [types.sint, types.double], types.sint)
+        res = self.call(func, [38, 4.2], rffi.LONG)
+        assert res == 42
+        self.check_loops({
+                'call': 1,
+                'guard_no_exception': 1,
+                'int_add': 1,
+                'int_lt': 1,
+                'guard_true': 1,
+                'jump': 1})
+
+    def test_float_result(self):
         libm = self.get_libm()
-        pow = libm.getpointer('pow', [types.double, types.double],
-                              types.double)
-        argchain = ArgChain()
-        argchain.arg(2.0).arg(3.0)
-        res = pow.call(argchain, rffi.DOUBLE)
+        func = (libm, 'pow', [types.double, types.double], types.double)
+        res = self.call(func, [2.0, 3.0], rffi.DOUBLE, init_result=0.0)
         assert res == 8.0
+        self.check_loops(call=1)
+
+    def test_cast_result(self):
+        libfoo = self.get_libfoo()
+        func = (libfoo, 'cast_to_uchar_and_ovf', [types.sint], types.uchar)
+        res = self.call(func, [0], rffi.UCHAR)
+        assert res == 200
+        self.check_loops(call=1)



More information about the Pypy-commit mailing list