[pypy-commit] pypy ffi-backend: In-progress: JIT support for ffi_call

arigo noreply at buildbot.pypy.org
Thu Aug 2 22:42:04 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: ffi-backend
Changeset: r56546:bc098624b3c9
Date: 2012-08-02 14:25 +0200
http://bitbucket.org/pypy/pypy/changeset/bc098624b3c9/

Log:	In-progress: JIT support for ffi_call

diff --git a/pypy/jit/backend/llsupport/ffisupport.py b/pypy/jit/backend/llsupport/ffisupport.py
--- a/pypy/jit/backend/llsupport/ffisupport.py
+++ b/pypy/jit/backend/llsupport/ffisupport.py
@@ -1,43 +1,40 @@
 from pypy.rlib.rarithmetic import intmask
-from pypy.jit.metainterp import history
 from pypy.rpython.lltypesystem import rffi
 from pypy.jit.backend.llsupport.descr import CallDescr
 
 class UnsupportedKind(Exception):
     pass
 
-def get_call_descr_dynamic(cpu, ffi_args, ffi_result, extrainfo, ffi_flags):
-    """Get a call descr: the types of result and args are represented by
-    rlib.libffi.types.*"""
+def get_call_descr_dynamic(cpu, cif_description, extrainfo):
+    """Get a call descr from the given CIF_DESCRIPTION"""
+    ffi_result = cif_description.rtype
     try:
         reskind = get_ffi_type_kind(cpu, ffi_result)
-        argkinds = [get_ffi_type_kind(cpu, arg) for arg in ffi_args]
+        argkinds = [get_ffi_type_kind(cpu, atype)
+                    for atype in cif_description.atypes]
     except UnsupportedKind:
         return None
-    if reskind == history.VOID:
+    if reskind == 'v':
         result_size = 0
     else:
         result_size = intmask(ffi_result.c_size)
     argkinds = ''.join(argkinds)
     return CallDescr(argkinds, reskind, is_ffi_type_signed(ffi_result),
-                     result_size, extrainfo, ffi_flags=ffi_flags)
+                     result_size, extrainfo, ffi_flags=cif_description.abi)
 
 def get_ffi_type_kind(cpu, ffi_type):
-    from pypy.rlib.libffi import types
+    from pypy.rlib.jit_libffi import types
     kind = types.getkind(ffi_type)
-    if kind == 'i' or kind == 'u':
-        return history.INT
-    elif cpu.supports_floats and kind == 'f':
-        return history.FLOAT
-    elif kind == 'v':
-        return history.VOID
-    elif cpu.supports_longlong and (kind == 'I' or kind == 'U'):     # longlong
-        return 'L'
-    elif cpu.supports_singlefloats and kind == 's':    # singlefloat
-        return 'S'
-    raise UnsupportedKind("Unsupported kind '%s'" % kind)
+    if ((not cpu.supports_floats and kind == 'f') or
+        (not cpu.supports_longlong and kind == 'L') or
+        (not cpu.supports_singlefloats and kind == 'S') or
+        kind == '*'):
+        raise UnsupportedKind("Unsupported kind '%s'" % kind)
+    if kind == 'u':
+        kind = 'i'
+    return kind
 
 def is_ffi_type_signed(ffi_type):
-    from pypy.rlib.libffi import types
+    from pypy.rlib.jit_libffi import types
     kind = types.getkind(ffi_type)
     return kind != 'u'
diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py
--- a/pypy/jit/backend/llsupport/llmodel.py
+++ b/pypy/jit/backend/llsupport/llmodel.py
@@ -280,10 +280,10 @@
     def calldescrof(self, FUNC, ARGS, RESULT, extrainfo):
         return get_call_descr(self.gc_ll_descr, ARGS, RESULT, extrainfo)
 
-    def calldescrof_dynamic(self, ffi_args, ffi_result, extrainfo, ffi_flags):
+    def calldescrof_dynamic(self, cif_description, extrainfo):
         from pypy.jit.backend.llsupport import ffisupport
-        return ffisupport.get_call_descr_dynamic(self, ffi_args, ffi_result,
-                                                 extrainfo, ffi_flags)
+        return ffisupport.get_call_descr_dynamic(self, cif_description,
+                                                 extrainfo)
 
     def get_overflow_error(self):
         ovf_vtable = self.cast_adr_to_int(self._ovf_error_vtable)
diff --git a/pypy/jit/backend/llsupport/test/test_ffisupport.py b/pypy/jit/backend/llsupport/test/test_ffisupport.py
--- a/pypy/jit/backend/llsupport/test/test_ffisupport.py
+++ b/pypy/jit/backend/llsupport/test/test_ffisupport.py
@@ -1,4 +1,5 @@
-from pypy.rlib.libffi import types
+from pypy.rlib.jit_libffi import types, CIF_DESCRIPTION, FFI_TYPE_PP
+from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.jit.codewriter.longlong import is_64_bit
 from pypy.jit.backend.llsupport.descr import *
 from pypy.jit.backend.llsupport.ffisupport import *
@@ -12,11 +13,21 @@
         self.supports_longlong = supports_longlong
         self.supports_singlefloats = supports_singlefloats
 
+def grab(cpu, atypes, rtype):
+    p = lltype.malloc(CIF_DESCRIPTION, len(atypes),
+                      flavor='raw', immortal=True)
+    rffi.setintfield(p, 'abi', 42)
+    p.nargs = len(atypes)
+    p.rtype = rtype
+    p.atypes = lltype.malloc(FFI_TYPE_PP.TO, len(atypes),
+                             flavor='raw', immortal=True)
+    for i in range(len(atypes)):
+        p.atypes[i] = atypes[i]
+    return get_call_descr_dynamic(cpu, p, None)
 
 def test_call_descr_dynamic():
     args = [types.sint, types.pointer]
-    descr = get_call_descr_dynamic(FakeCPU(), args, types.sint, None,
-                                   ffi_flags=42)
+    descr = grab(FakeCPU(), args, types.sint)
     assert isinstance(descr, CallDescr)
     assert descr.result_type == 'i'
     assert descr.result_flag == FLAG_SIGNED
@@ -24,43 +35,39 @@
     assert descr.get_ffi_flags() == 42
 
     args = [types.sint, types.double, types.pointer]
-    descr = get_call_descr_dynamic(FakeCPU(), args, types.void, None, 42)
+    descr = grab(FakeCPU(), args, types.void)
     assert descr is None    # missing floats
-    descr = get_call_descr_dynamic(FakeCPU(supports_floats=True),
-                                   args, types.void, None, ffi_flags=43)
+    descr = grab(FakeCPU(supports_floats=True), args, types.void)
     assert descr.result_type == 'v'
     assert descr.result_flag == FLAG_VOID
     assert descr.arg_classes == 'ifi'
-    assert descr.get_ffi_flags() == 43
+    assert descr.get_ffi_flags() == 42
 
-    descr = get_call_descr_dynamic(FakeCPU(), [], types.sint8, None, 42)
+    descr = grab(FakeCPU(), [], types.sint8)
     assert descr.get_result_size() == 1
     assert descr.result_flag == FLAG_SIGNED
     assert descr.is_result_signed() == True
 
-    descr = get_call_descr_dynamic(FakeCPU(), [], types.uint8, None, 42)
+    descr = grab(FakeCPU(), [], types.uint8)
     assert isinstance(descr, CallDescr)
     assert descr.get_result_size() == 1
     assert descr.result_flag == FLAG_UNSIGNED
     assert descr.is_result_signed() == False
 
     if not is_64_bit or is_emulated_long:
-        descr = get_call_descr_dynamic(FakeCPU(), [], types.slonglong,
-                                       None, 42)
+        descr = grab(FakeCPU(), [], types.slonglong)
         assert descr is None   # missing longlongs
-        descr = get_call_descr_dynamic(FakeCPU(supports_longlong=True),
-                                       [], types.slonglong, None, ffi_flags=43)
+        descr = grab(FakeCPU(supports_longlong=True), [], types.slonglong)
         assert isinstance(descr, CallDescr)
         assert descr.result_flag == FLAG_FLOAT
         assert descr.result_type == 'L'
-        assert descr.get_ffi_flags() == 43
+        assert descr.get_ffi_flags() == 42
     else:
         assert types.slonglong is types.slong
 
-    descr = get_call_descr_dynamic(FakeCPU(), [], types.float, None, 42)
+    descr = grab(FakeCPU(), [], types.float)
     assert descr is None   # missing singlefloats
-    descr = get_call_descr_dynamic(FakeCPU(supports_singlefloats=True),
-                                   [], types.float, None, ffi_flags=44)
+    descr = grab(FakeCPU(supports_singlefloats=True), [], types.float)
     assert descr.result_flag == FLAG_UNSIGNED
     assert descr.result_type == 'S'
-    assert descr.get_ffi_flags() == 44
+    assert descr.get_ffi_flags() == 42
diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py
--- a/pypy/jit/codewriter/effectinfo.py
+++ b/pypy/jit/codewriter/effectinfo.py
@@ -45,13 +45,7 @@
     OS_UNIEQ_LENGTHOK           = 51   #
     _OS_offset_uni              = OS_UNI_CONCAT - OS_STR_CONCAT
     #
-    OS_LIBFFI_PREPARE           = 60
-    OS_LIBFFI_PUSH_ARG          = 61
     OS_LIBFFI_CALL              = 62
-    OS_LIBFFI_STRUCT_GETFIELD   = 63
-    OS_LIBFFI_STRUCT_SETFIELD   = 64
-    OS_LIBFFI_GETARRAYITEM      = 65
-    OS_LIBFFI_SETARRAYITEM      = 66
     #
     OS_LLONG_INVERT             = 69
     OS_LLONG_ADD                = 70
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -1728,27 +1728,9 @@
     # rlib.libffi
 
     def _handle_libffi_call(self, op, oopspec_name, args):
-        if oopspec_name == 'libffi_prepare_call':
-            oopspecindex = EffectInfo.OS_LIBFFI_PREPARE
-            extraeffect = EffectInfo.EF_CANNOT_RAISE
-        elif oopspec_name.startswith('libffi_push_'):
-            oopspecindex = EffectInfo.OS_LIBFFI_PUSH_ARG
-            extraeffect = EffectInfo.EF_CANNOT_RAISE
-        elif oopspec_name.startswith('libffi_call_'):
+        if oopspec_name == 'libffi_call':
             oopspecindex = EffectInfo.OS_LIBFFI_CALL
             extraeffect = EffectInfo.EF_RANDOM_EFFECTS
-        elif oopspec_name == 'libffi_struct_getfield':
-            oopspecindex = EffectInfo.OS_LIBFFI_STRUCT_GETFIELD
-            extraeffect = EffectInfo.EF_CANNOT_RAISE
-        elif oopspec_name == 'libffi_struct_setfield':
-            oopspecindex = EffectInfo.OS_LIBFFI_STRUCT_SETFIELD
-            extraeffect = EffectInfo.EF_CANNOT_RAISE
-        elif oopspec_name == 'libffi_array_getitem':
-            oopspecindex = EffectInfo.OS_LIBFFI_GETARRAYITEM
-            extraeffect = EffectInfo.EF_CANNOT_RAISE
-        elif oopspec_name == 'libffi_array_setitem':
-            oopspecindex = EffectInfo.OS_LIBFFI_SETARRAYITEM
-            extraeffect = EffectInfo.EF_CANNOT_RAISE
         else:
             assert False, 'unsupported oopspec: %s' % oopspec_name
         return self._handle_oopspec_call(op, args, oopspecindex, extraeffect)
diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -431,31 +431,6 @@
     return llop.uint_mod(lltype.Unsigned, xll, yll)
 
 
-# libffi support
-# --------------
-
-def func(llfunc):
-    from pypy.rlib.libffi import Func
-    return cast_base_ptr_to_instance(Func, llfunc)
-
-def _ll_1_libffi_prepare_call(llfunc):
-    return func(llfunc)._prepare()
-
-def _ll_4_libffi_push_int(llfunc, value, ll_args, i):
-    return func(llfunc)._push_int(value, ll_args, i)
-
-def _ll_4_libffi_push_float(llfunc, value, ll_args, i):
-    return func(llfunc)._push_float(value, ll_args, i)
-
-def _ll_3_libffi_call_int(llfunc, funcsym, ll_args):
-    return func(llfunc)._do_call(funcsym, ll_args, rffi.LONG)
-
-def _ll_3_libffi_call_float(llfunc, funcsym, ll_args):
-    return func(llfunc)._do_call(funcsym, ll_args, rffi.DOUBLE)
-
-def _ll_3_libffi_call_void(llfunc, funcsym, ll_args):
-    return func(llfunc)._do_call(funcsym, ll_args, lltype.Void)
-
 # in the following calls to builtins, the JIT is allowed to look inside:
 inline_calls_to = [
     ('int_floordiv_ovf_zer', [lltype.Signed, lltype.Signed], lltype.Signed),
diff --git a/pypy/rlib/clibffi.py b/pypy/rlib/clibffi.py
--- a/pypy/rlib/clibffi.py
+++ b/pypy/rlib/clibffi.py
@@ -202,7 +202,7 @@
 
 FFI_TYPE_P.TO.become(cConfig.ffi_type)
 size_t = cConfig.size_t
-ffi_abi = cConfig.ffi_abi
+FFI_ABI = cConfig.ffi_abi
 ffi_arg = cConfig.ffi_arg
 
 for name in type_names:
@@ -333,7 +333,7 @@
 
 VOIDPP = rffi.CArrayPtr(rffi.VOIDP)
 
-c_ffi_prep_cif = external('ffi_prep_cif', [FFI_CIFP, ffi_abi, rffi.UINT,
+c_ffi_prep_cif = external('ffi_prep_cif', [FFI_CIFP, FFI_ABI, rffi.UINT,
                                            FFI_TYPE_P, FFI_TYPE_PP], rffi.INT)
 if _MSVC:
     c_ffi_call_return_type = rffi.INT
diff --git a/pypy/rlib/jit_libffi.py b/pypy/rlib/jit_libffi.py
--- a/pypy/rlib/jit_libffi.py
+++ b/pypy/rlib/jit_libffi.py
@@ -1,12 +1,13 @@
 import sys
 from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.rlib import clibffi
+from pypy.rlib import clibffi, jit
 
 
 FFI_CIF = clibffi.FFI_CIFP.TO
 FFI_TYPE = clibffi.FFI_TYPE_P.TO
 FFI_TYPE_P = clibffi.FFI_TYPE_P
 FFI_TYPE_PP = clibffi.FFI_TYPE_PP
+FFI_ABI = clibffi.FFI_ABI
 SIZE_OF_FFI_ARG = rffi.sizeof(clibffi.ffi_arg)
 
 # "cif_description" is a block of raw memory describing how to do the call.
@@ -29,10 +30,13 @@
 CIF_DESCRIPTION = lltype.Struct(
     'CIF_DESCRIPTION',
     ('cif', FFI_CIF),
+    ('abi', FFI_ABI),
+    ('nargs', lltype.Signed),
+    ('rtype', FFI_TYPE_P),
+    ('atypes', FFI_TYPE_PP),
     ('exchange_size', lltype.Signed),
     ('exchange_result', lltype.Signed),
     ('exchange_result_libffi', lltype.Signed),
-    ('exchange_nb_args', lltype.Signed),
     ('exchange_args', lltype.Array(lltype.Signed,
                           hints={'nolength': True, 'immutable': True})),
     hints={'immutable': True})
@@ -40,12 +44,13 @@
 CIF_DESCRIPTION_P = lltype.Ptr(CIF_DESCRIPTION)
 
 
+ at jit.oopspec("libffi_call(cif_description, func_addr, exchange_buffer)")
 def jit_ffi_call(cif_description, func_addr, exchange_buffer):
     """Wrapper around ffi_call().  Must receive a CIF_DESCRIPTION_P that
-    describes the layout of the 'exchange_buffer' of size 'exchange_size'.
+    describes the layout of the 'exchange_buffer'.
     """
     buffer_array = rffi.cast(rffi.VOIDPP, exchange_buffer)
-    for i in range(cif_description.exchange_nb_args):
+    for i in range(cif_description.nargs):
         data = rffi.ptradd(exchange_buffer, cif_description.exchange_args[i])
         buffer_array[i] = data
     resultdata = rffi.ptradd(exchange_buffer,
@@ -53,3 +58,68 @@
     clibffi.c_ffi_call(cif_description.cif, func_addr,
                        rffi.cast(rffi.VOIDP, resultdata),
                        buffer_array)
+
+# ____________________________________________________________
+
+class types(object):
+    """
+    This namespace contains the mapping the JIT needs from ffi types to
+    a less strict "kind" character.
+    """
+
+    @classmethod
+    def _import(cls):
+        prefix = 'ffi_type_'
+        for key, value in clibffi.__dict__.iteritems():
+            if key.startswith(prefix):
+                name = key[len(prefix):]
+                setattr(cls, name, value)
+        cls.slong = clibffi.cast_type_to_ffitype(rffi.LONG)
+        cls.ulong = clibffi.cast_type_to_ffitype(rffi.ULONG)
+        cls.slonglong = clibffi.cast_type_to_ffitype(rffi.LONGLONG)
+        cls.ulonglong = clibffi.cast_type_to_ffitype(rffi.ULONGLONG)
+        cls.signed = clibffi.cast_type_to_ffitype(rffi.SIGNED)
+        cls.wchar_t = clibffi.cast_type_to_ffitype(lltype.UniChar)
+        del cls._import
+
+    @staticmethod
+    @jit.elidable
+    def getkind(ffi_type):
+        """Returns 'v' for void, 'f' for float, 'i' for signed integer,
+        'u' for unsigned integer, 'S' for singlefloat, 'L' for long long
+        integer (signed or unsigned), or '*' for struct.
+        """
+        if   ffi_type is types.void:    return 'v'
+        elif ffi_type is types.double:  return 'f'
+        elif ffi_type is types.float:   return 'S'
+        elif ffi_type is types.pointer: return 'i'
+        #
+        elif ffi_type is types.schar:   return 'i'
+        elif ffi_type is types.uchar:   return 'u'
+        elif ffi_type is types.sshort:  return 'i'
+        elif ffi_type is types.ushort:  return 'u'
+        elif ffi_type is types.sint:    return 'i'
+        elif ffi_type is types.uint:    return 'u'
+        elif ffi_type is types.slong:   return 'i'
+        elif ffi_type is types.ulong:   return 'u'
+        #
+        elif ffi_type is types.sint8:   return 'i'
+        elif ffi_type is types.uint8:   return 'u'
+        elif ffi_type is types.sint16:  return 'i'
+        elif ffi_type is types.uint16:  return 'u'
+        elif ffi_type is types.sint32:  return 'i'
+        elif ffi_type is types.uint32:  return 'u'
+        ## (note that on 64-bit platforms, types.sint64 is types.slong and the
+        ## case is caught above)
+        elif ffi_type is types.sint64:  return 'L'
+        elif ffi_type is types.uint64:  return 'L'
+        #
+        elif types.is_struct(ffi_type): return '*'
+        raise KeyError
+
+    @staticmethod
+    @jit.elidable
+    def is_struct(ffi_type):
+        return intmask(ffi_type.c_type) == FFI_TYPE_STRUCT
+
+types._import()


More information about the pypy-commit mailing list