[pypy-commit] pypy ffistruct: introduce the dispatcher, whose goal is to convert applevel objtects into low-level values based on the given ffitype. Move there the logic that we used in W_FunctPtr to build the argchain

antocuni noreply at buildbot.pypy.org
Fri Nov 11 16:32:36 CET 2011


Author: Antonio Cuni <anto.cuni at gmail.com>
Branch: ffistruct
Changeset: r49313:1e475fc1fe0e
Date: 2011-11-10 18:39 +0100
http://bitbucket.org/pypy/pypy/changeset/1e475fc1fe0e/

Log:	introduce the dispatcher, whose goal is to convert applevel objtects
	into low-level values based on the given ffitype. Move there the
	logic that we used in W_FunctPtr to build the argchain

diff --git a/pypy/module/_ffi/dispatcher.py b/pypy/module/_ffi/dispatcher.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_ffi/dispatcher.py
@@ -0,0 +1,172 @@
+from pypy.rlib import libffi
+from pypy.rlib import jit
+from pypy.rlib.rarithmetic import intmask
+from pypy.rpython.lltypesystem import rffi
+from pypy.module._rawffi.structure import W_StructureInstance
+
+
+def unwrap_truncate_int(TP, space, w_arg):
+    if space.is_true(space.isinstance(w_arg, space.w_int)):
+        return rffi.cast(TP, space.int_w(w_arg))
+    else:
+        return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask())
+unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)'
+
+
+class AbstractDispatcher(object):
+
+    def __init__(self, space):
+        self.space = space
+
+    def unwrap_and_do(self, w_ffitype, w_obj):
+        space = self.space
+        if w_ffitype.is_longlong():
+            # note that we must check for longlong first, because either
+            # is_signed or is_unsigned returns true anyway
+            assert libffi.IS_32_BIT
+            self._longlong(w_ffitype, w_obj)
+        elif w_ffitype.is_signed():
+            intval = unwrap_truncate_int(rffi.LONG, space, w_obj)
+            self.handle_signed(w_ffitype, w_obj, intval)
+        elif self.maybe_handle_char_or_unichar_p(w_ffitype, w_obj):
+            # the object was already handled from within
+            # maybe_handle_char_or_unichar_p
+            pass
+        elif w_ffitype.is_pointer():
+            w_obj = self.convert_pointer_arg_maybe(w_obj, w_ffitype)
+            intval = intmask(space.uint_w(w_obj))
+            self.handle_pointer(w_ffitype, w_obj, intval)
+        elif w_ffitype.is_unsigned():
+            uintval = unwrap_truncate_int(rffi.ULONG, space, w_obj)
+            self.handle_unsigned(w_ffitype, w_obj, uintval)
+        elif w_ffitype.is_char():
+            intval = space.int_w(space.ord(w_obj))
+            self.handle_char(w_ffitype, w_obj, intval)
+        elif w_ffitype.is_unichar():
+            intval = space.int_w(space.ord(w_obj))
+            self.handle_unichar(w_ffitype, w_obj, intval)
+        elif w_ffitype.is_double():
+            self._float(w_ffitype, w_obj)
+        elif w_ffitype.is_singlefloat():
+            self._singlefloat(w_ffitype, w_obj)
+        elif w_ffitype.is_struct():
+            # arg_raw directly takes value to put inside ll_args
+            w_obj = space.interp_w(W_StructureInstance, w_obj)
+            self.handle_struct(w_ffitype, w_obj)
+        else:
+            self.error(w_ffitype, w_obj)
+
+    def _longlong(self, w_ffitype, w_obj):
+        # a separate function, which can be seen by the jit or not,
+        # depending on whether longlongs are supported
+        bigval = self.space.bigint_w(w_obj)
+        ullval = bigval.ulonglongmask()
+        llval = rffi.cast(rffi.LONGLONG, ullval)
+        self.handle_longlong(w_ffitype, w_obj, llval)
+
+    def _float(self, w_ffitype, w_obj):
+        # a separate function, which can be seen by the jit or not,
+        # depending on whether floats are supported
+        floatval = self.space.float_w(w_obj)
+        self.handle_float(w_ffitype, w_obj, floatval)
+
+    def _singlefloat(self, w_ffitype, w_obj):
+        # a separate function, which can be seen by the jit or not,
+        # depending on whether singlefloats are supported
+        from pypy.rlib.rarithmetic import r_singlefloat
+        floatval = self.space.float_w(w_obj)
+        singlefloatval = r_singlefloat(floatval)
+        self.handle_singlefloat(w_ffitype, w_obj, singlefloatval)
+
+    def maybe_handle_char_or_unichar_p(self, w_ffitype, w_obj):
+        w_type = jit.promote(self.space.type(w_obj))
+        if w_ffitype.is_char_p() and w_type is self.space.w_str:
+            strval = self.space.str_w(w_obj)
+            self.handle_char_p(w_ffitype, w_obj, strval)
+            return True
+        elif w_ffitype.is_unichar_p() and (w_type is self.space.w_str or
+                                           w_type is self.space.w_unicode):
+            unicodeval = self.space.unicode_w(w_obj)
+            self.handle_unichar_p(w_ffitype, w_obj, unicodeval)
+            return True
+
+    def convert_pointer_arg_maybe(self, w_arg, w_argtype):
+        """
+        Try to convert the argument by calling _as_ffi_pointer_()
+        """
+        space = self.space
+        meth = space.lookup(w_arg, '_as_ffi_pointer_') # this also promotes the type
+        if meth:
+            return space.call_function(meth, w_arg, w_argtype)
+        else:
+            return w_arg
+
+    def error(self, w_ffitype, w_obj):
+        assert False # XXX raise a proper app-level exception
+
+    def handle_signed(self, w_ffitype, w_obj, intval):
+        """
+        intval: lltype.Signed
+        """
+        self.error(w_ffitype, w_obj)
+
+    def handle_unsigned(self, w_ffitype, w_obj, uintval):
+        """
+        uintval: lltype.Unsigned
+        """
+        self.error(w_ffitype, w_obj)
+
+    def handle_pointer(self, w_ffitype, w_obj, intval):
+        """
+        intval: lltype.Signed
+        """
+        self.error(w_ffitype, w_obj)
+
+    def handle_char(self, w_ffitype, w_obj, intval):
+        """
+        intval: lltype.Signed
+        """
+        self.error(w_ffitype, w_obj)
+        
+    def handle_unichar(self, w_ffitype, w_obj, intval):
+        """
+        intval: lltype.Signed
+        """
+        self.error(w_ffitype, w_obj)
+
+    def handle_longlong(self, w_ffitype, w_obj, longlongval):
+        """
+        longlongval: lltype.SignedLongLong
+        """
+        self.error(w_ffitype, w_obj)
+
+    def handle_char_p(self, w_ffitype, w_obj, strval):
+        """
+        strval: interp-level str
+        """
+        self.error(w_ffitype, w_obj)
+
+    def handle_unichar_p(self, w_ffitype, w_obj, unicodeval):
+        """
+        unicodeval: interp-level unicode
+        """
+        self.error(w_ffitype, w_obj)
+
+    def handle_float(self, w_ffitype, w_obj, floatval):
+        """
+        floatval: lltype.Float
+        """
+        self.error(w_ffitype, w_obj)
+
+    def handle_singlefloat(self, w_ffitype, w_obj, singlefloatval):
+        """
+        singlefloatval: lltype.SingleFloat
+        """
+        self.error(w_ffitype, w_obj)
+
+    def handle_struct(self, w_ffitype, w_structinstance):
+        """
+        w_structinstance: W_StructureInstance
+        """
+        self.error(w_ffitype, w_structinstance)
+
diff --git a/pypy/module/_ffi/interp_funcptr.py b/pypy/module/_ffi/interp_funcptr.py
--- a/pypy/module/_ffi/interp_funcptr.py
+++ b/pypy/module/_ffi/interp_funcptr.py
@@ -13,6 +13,7 @@
 from pypy.rlib.rdynload import DLOpenError
 from pypy.rlib.rarithmetic import intmask, r_uint
 from pypy.rlib.objectmodel import we_are_translated
+from pypy.module._ffi.dispatcher import AbstractDispatcher
 
 
 def unwrap_ffitype(space, w_argtype, allow_void=False):
@@ -22,12 +23,6 @@
         raise OperationError(space.w_TypeError, space.wrap(msg))
     return res
 
-def unwrap_truncate_int(TP, space, w_arg):
-    if space.is_true(space.isinstance(w_arg, space.w_int)):
-        return rffi.cast(TP, space.int_w(w_arg))
-    else:
-        return rffi.cast(TP, space.bigint_w(w_arg).ulonglongmask())
-unwrap_truncate_int._annspecialcase_ = 'specialize:arg(0)'
 
 # ========================================================================
 
@@ -54,97 +49,13 @@
                                   self.func.name, expected, arg, given)
         #
         argchain = libffi.ArgChain()
+        argpusher = ArgumentPusherDispatcher(space, argchain, self.to_free)
         for i in range(expected):
             w_argtype = self.argtypes_w[i]
             w_arg = args_w[i]
-            if w_argtype.is_longlong():
-                # note that we must check for longlong first, because either
-                # is_signed or is_unsigned returns true anyway
-                assert libffi.IS_32_BIT
-                self.arg_longlong(space, argchain, w_arg)
-            elif w_argtype.is_signed():
-                argchain.arg(unwrap_truncate_int(rffi.LONG, space, w_arg))
-            elif self.add_char_p_maybe(space, argchain, w_arg, w_argtype):
-                # the argument is added to the argchain direcly by the method above
-                pass
-            elif w_argtype.is_pointer():
-                w_arg = self.convert_pointer_arg_maybe(space, w_arg, w_argtype)
-                argchain.arg(intmask(space.uint_w(w_arg)))
-            elif w_argtype.is_unsigned():
-                argchain.arg(unwrap_truncate_int(rffi.ULONG, space, w_arg))
-            elif w_argtype.is_char():
-                w_arg = space.ord(w_arg)
-                argchain.arg(space.int_w(w_arg))
-            elif w_argtype.is_unichar():
-                w_arg = space.ord(w_arg)
-                argchain.arg(space.int_w(w_arg))
-            elif w_argtype.is_double():
-                self.arg_float(space, argchain, w_arg)
-            elif w_argtype.is_singlefloat():
-                self.arg_singlefloat(space, argchain, w_arg)
-            elif w_argtype.is_struct():
-                # arg_raw directly takes value to put inside ll_args
-                w_arg = space.interp_w(W_StructureInstance, w_arg)
-                ptrval = w_arg.ll_buffer
-                argchain.arg_raw(ptrval)
-            else:
-                assert False, "Argument shape '%s' not supported" % w_argtype
+            argpusher.unwrap_and_do(w_argtype, w_arg)
         return argchain
 
-    def add_char_p_maybe(self, space, argchain, w_arg, w_argtype):
-        """
-        Automatic conversion from string to char_p. The allocated buffer will
-        be automatically freed after the call.
-        """
-        w_type = jit.promote(space.type(w_arg))
-        if w_argtype.is_char_p() and w_type is space.w_str:
-            strval = space.str_w(w_arg)
-            buf = rffi.str2charp(strval)
-            self.to_free.append(rffi.cast(rffi.VOIDP, buf))
-            addr = rffi.cast(rffi.ULONG, buf)
-            argchain.arg(addr)
-            return True
-        elif w_argtype.is_unichar_p() and (w_type is space.w_str or
-                                           w_type is space.w_unicode):
-            unicodeval = space.unicode_w(w_arg)
-            buf = rffi.unicode2wcharp(unicodeval)
-            self.to_free.append(rffi.cast(rffi.VOIDP, buf))
-            addr = rffi.cast(rffi.ULONG, buf)
-            argchain.arg(addr)
-            return True
-        return False
-
-    def convert_pointer_arg_maybe(self, space, w_arg, w_argtype):
-        """
-        Try to convert the argument by calling _as_ffi_pointer_()
-        """
-        meth = space.lookup(w_arg, '_as_ffi_pointer_') # this also promotes the type
-        if meth:
-            return space.call_function(meth, w_arg, w_argtype)
-        else:
-            return w_arg
-
-    def arg_float(self, space, argchain, w_arg):
-        # a separate function, which can be seen by the jit or not,
-        # depending on whether floats are supported
-        argchain.arg(space.float_w(w_arg))
-
-    def arg_longlong(self, space, argchain, w_arg):
-        # a separate function, which can be seen by the jit or not,
-        # depending on whether longlongs are supported
-        bigarg = space.bigint_w(w_arg)
-        ullval = bigarg.ulonglongmask()
-        llval = rffi.cast(rffi.LONGLONG, ullval)
-        argchain.arg(llval)
-
-    def arg_singlefloat(self, space, argchain, w_arg):
-        # a separate function, which can be seen by the jit or not,
-        # depending on whether singlefloats are supported
-        from pypy.rlib.rarithmetic import r_singlefloat
-        fval = space.float_w(w_arg)
-        sfval = r_singlefloat(fval)
-        argchain.arg(sfval)
-
     def call(self, space, args_w):
         self = jit.promote(self)
         argchain = self.build_argchain(space, args_w)
@@ -281,6 +192,58 @@
         return space.wrap(rffi.cast(rffi.LONG, self.func.funcsym))
 
 
+class ArgumentPusherDispatcher(AbstractDispatcher):
+    """
+    A dispatcher used by W_FuncPtr to unwrap the app-level objects into
+    low-level types and push them to the argchain.
+    """
+
+    def __init__(self, space, argchain, to_free):
+        AbstractDispatcher.__init__(self, space)
+        self.argchain = argchain
+        self.to_free = to_free
+
+    def handle_signed(self, w_ffitype, w_obj, intval):
+        self.argchain.arg(intval)
+
+    def handle_unsigned(self, w_ffitype, w_obj, uintval):
+        self.argchain.arg(uintval)
+
+    def handle_pointer(self, w_ffitype, w_obj, intval):
+        self.argchain.arg(intval)
+
+    def handle_char(self, w_ffitype, w_obj, intval):
+        self.argchain.arg(intval)
+
+    def handle_unichar(self, w_ffitype, w_obj, intval):
+        self.argchain.arg(intval)
+
+    def handle_longlong(self, w_ffitype, w_obj, longlongval):
+        self.argchain.arg(longlongval)
+
+    def handle_char_p(self, w_ffitype, w_obj, strval):
+        buf = rffi.str2charp(strval)
+        self.to_free.append(rffi.cast(rffi.VOIDP, buf))
+        addr = rffi.cast(rffi.ULONG, buf)
+        self.argchain.arg(addr)
+
+    def handle_unichar_p(self, w_ffitype, w_obj, unicodeval):
+        buf = rffi.unicode2wcharp(unicodeval)
+        self.to_free.append(rffi.cast(rffi.VOIDP, buf))
+        addr = rffi.cast(rffi.ULONG, buf)
+        self.argchain.arg(addr)
+
+    def handle_float(self, w_ffitype, w_obj, floatval):
+        self.argchain.arg(floatval)
+
+    def handle_singlefloat(self, w_ffitype, w_obj, singlefloatval):
+        self.argchain.arg(singlefloatval)
+
+    def handle_struct(self, w_ffitype, w_structinstance):
+        ptrval = w_structinstance.ll_buffer
+        self.argchain.arg_raw(ptrval)
+
+
 
 def unpack_argtypes(space, w_argtypes, w_restype):
     argtypes_w = [space.interp_w(W_FFIType, w_argtype)
@@ -369,3 +332,4 @@
         return space.wrap(W_CDLL(space, get_libc_name()))
     except OSError, e:
         raise wrap_oserror(space, e)
+


More information about the pypy-commit mailing list