Commits

Armin Rigo committed b6390a3

Tentatively rewrite push_arg_as_ffiptr().

  • Participants
  • Parent commits 88daf71

Comments (0)

Files changed (1)

File pypy/rlib/clibffi.py

     return TYPE_MAP[tp]
 cast_type_to_ffitype._annspecialcase_ = 'specialize:memo'
 
-def push_arg_as_ffiptr_base(ffitp, arg, ll_buf):
-    # this is for primitive types. For structures and arrays
-    # would be something different (more dynamic)
-    # XXX is this valid in C?, for args that are larger than the size of
-    # ll_buf we write over the boundaries of the allocated char array and
-    # just keep as much bytes as we need for the target type. Maybe using
-    # memcpy would be better here. Also this
-    # only works on little endian architectures
-    TP = lltype.typeOf(arg)
-    TP_P = lltype.Ptr(rffi.CArray(TP))
-    buf = rffi.cast(TP_P, ll_buf)
-    buf[0] = arg
-push_arg_as_ffiptr_base._annspecialcase_ = 'specialize:argtype(1)'
-
-def push_arg_as_ffiptr_memcpy(ffitp, arg, ll_buf):
-    # this is for primitive types. For structures and arrays
-    # would be something different (more dynamic)
+def push_arg_as_ffiptr(ffitp, arg, ll_buf):
+    # This is for primitive types.  Note that the exact type of 'arg' may be
+    # different from the expected 'c_size'.  To cope with that, we fall back
+    # to a byte-by-byte copy.
     TP = lltype.typeOf(arg)
     TP_P = lltype.Ptr(rffi.CArray(TP))
     TP_size = rffi.sizeof(TP)
     c_size = intmask(ffitp.c_size)
-
-    # if both types have the same size, we do not can directly write the
+    # if both types have the same size, we can directly write the
     # value to the buffer
     if c_size == TP_size:
-        return push_arg_as_ffiptr_base(ffitp, arg, ll_buf)
-
-    # store arg in a small box in memory
-    # and copy the relevant bytes over to the target buffer (ll_buf)
-    with lltype.scoped_alloc(TP_P.TO, TP_size) as argbuf:
-        argbuf[0] = arg
-        cargbuf = rffi.cast(rffi.CCHARP, argbuf)
-        ptr = rffi.ptradd(cargbuf, TP_size - c_size)
-        rffi.c_memcpy(ll_buf, ptr, c_size)
-push_arg_as_ffiptr_memcpy._annspecialcase_ = 'specialize:argtype(1)'
-
-if _LITTLE_ENDIAN:
-    push_arg_as_ffiptr = push_arg_as_ffiptr_base
-else:
-    push_arg_as_ffiptr = push_arg_as_ffiptr_memcpy
+        buf = rffi.cast(TP_P, ll_buf)
+        buf[0] = arg
+    else:
+        # needs byte-by-byte copying.  Make sure 'arg' is an integer type.
+        # Note that this won't work for rffi.FLOAT/rffi.DOUBLE.
+        assert TP is not rffi.FLOAT and TP is not rffi.DOUBLE
+        if TP_size <= rffi.sizeof(lltype.Signed):
+            arg = rffi.cast(lltype.Unsigned, arg)
+        else:
+            arg = rffi.cast(lltype.UnsignedLongLong, arg)
+        if _LITTLE_ENDIAN:
+            for i in range(c_size):
+                ll_buf[i] = chr(arg & 0xFF)
+                arg >>= 8
+        elif _BIG_ENDIAN:
+            for i in range(c_size-1, -1, -1):
+                ll_buf[i] = chr(arg & 0xFF)
+                arg >>= 8
+        else:
+            raise AssertionError
+push_arg_as_ffiptr._annspecialcase_ = 'specialize:argtype(1)'
 
 # type defs for callback and closure userdata
 USERDATA_P = lltype.Ptr(lltype.ForwardReference())