[pypy-svn] pypy fast-forward: Start support of bit fields in the _rawffi module.
amauryfa
commits-noreply at bitbucket.org
Wed Dec 29 21:31:28 CET 2010
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: fast-forward
Changeset: r40266:7ca80c668e44
Date: 2010-12-29 21:09 +0100
http://bitbucket.org/pypy/pypy/changeset/7ca80c668e44/
Log: Start support of bit fields in the _rawffi module. the special
"bitsizes" array encodes in a single number the size (in bits) and
the shift of the member. If this number is smaller than 0xFFFF, it's
a normal field...
diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py
--- a/pypy/module/_rawffi/test/test__rawffi.py
+++ b/pypy/module/_rawffi/test/test__rawffi.py
@@ -891,6 +891,7 @@
assert "Procedure called with too many arguments" in e.message
else:
assert 0, "Did not raise"
+ arg.free()
def test_struct_byvalue(self):
import _rawffi, sys
diff --git a/pypy/module/_rawffi/test/test_struct.py b/pypy/module/_rawffi/test/test_struct.py
--- a/pypy/module/_rawffi/test/test_struct.py
+++ b/pypy/module/_rawffi/test/test_struct.py
@@ -5,7 +5,7 @@
sizeof = lambda x : size_alignment_pos(x)[0]
def unpack(desc):
- return [('x', letter2tp('space', i)) for i in desc]
+ return [('x', letter2tp('space', i), 0) for i in desc]
def test_sizeof():
s_c = sizeof(unpack('c'))
@@ -22,3 +22,33 @@
assert sizeof(unpack('qcc')) == s_q + alignment_of_q
assert sizeof(unpack('qccc')) == s_q + alignment_of_q
assert sizeof(unpack('qcccc')) == s_q + alignment_of_q
+
+def test_bitsizes():
+ c_int = letter2tp('space', 'i')
+ c_short = letter2tp('space', 'h')
+ fields = [("A", c_int, 1),
+ ("B", c_int, 2),
+ ("C", c_int, 3),
+ ("D", c_int, 4),
+ ("E", c_int, 5),
+ ("F", c_int, 6),
+ ("G", c_int, 7),
+ ("H", c_int, 8),
+ ("I", c_int, 9),
+
+ ("M", c_short, 1),
+ ("N", c_short, 2),
+ ("O", c_short, 3),
+ ("P", c_short, 4),
+ ("Q", c_short, 5),
+ ("R", c_short, 6),
+ ("S", c_short, 7)]
+ size, alignment, pos, bitsizes = size_alignment_pos(fields)
+ assert size == 12
+ assert pos == [0, 0, 0, 0, 0, 0, 0, 4, 4, 8, 8, 8, 8, 8, 10, 10]
+ assert bitsizes == [
+ 0x10000, 0x20001, 0x30003, 0x40006, 0x5000a, 0x6000f, 0x70015, 0x80000, 0x90008,
+ 0x10000, 0x20001, 0x30003, 0x40006, 0x5000a, 0x60000, 0x70006]
+
+ # TODO: test a normal struct containing a big array > 0x10000.
+ # Make sure we don't take this for a bitsize...
diff --git a/pypy/module/_rawffi/structure.py b/pypy/module/_rawffi/structure.py
--- a/pypy/module/_rawffi/structure.py
+++ b/pypy/module/_rawffi/structure.py
@@ -10,7 +10,7 @@
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.module._rawffi.interp_rawffi import segfault_exception
+from pypy.module._rawffi.interp_rawffi import segfault_exception, _MS_WINDOWS
from pypy.module._rawffi.interp_rawffi import W_DataShape, W_DataInstance
from pypy.module._rawffi.interp_rawffi import wrap_value, unwrap_value
from pypy.module._rawffi.interp_rawffi import unpack_shape_with_length
@@ -23,35 +23,93 @@
fields = []
for w_tup in fields_w:
l_w = space.unpackiterable(w_tup)
- if not len(l_w) == 2:
+ len_l = len(l_w)
+
+ if len_l == 2:
+ bitsize = 0
+ elif len_l == 3:
+ bitsize = l_w[2]
+ else:
raise OperationError(space.w_ValueError, space.wrap(
- "Expected list of 2-size tuples"))
+ "Expected list of 2- or 3-size tuples"))
name = space.str_w(l_w[0])
tp = unpack_shape_with_length(space, l_w[1])
- fields.append((name, tp))
+ fields.append((name, tp, bitsize))
return fields
def round_up(size, alignment):
return (size + alignment - 1) & -alignment
-def size_alignment_pos(fields, is_union=False):
+NO_BITFIELD, NEW_BITFIELD, CONT_BITFIELD, EXPAND_BITFIELD = range(4)
+
+def size_alignment_pos(fields, is_union=False, pack=0):
size = 0
alignment = 1
pos = []
- for fieldname, fieldtype in fields:
+ bitsizes = []
+ bitoffset = 0
+ last_size = 0
+ for fieldname, fieldtype, bitsize in fields:
# fieldtype is a W_Array
fieldsize = fieldtype.size
fieldalignment = fieldtype.alignment
+ if pack:
+ fieldalignment = min(fieldalignment, pack)
alignment = max(alignment, fieldalignment)
+
+ if not bitsize:
+ # not a bit field
+ field_type = NO_BITFIELD
+ last_size = 0
+ bitoffset = 0
+ elif (last_size and # we have a bitfield open
+ (not _MS_WINDOWS or fieldsize * 8 == last_size) and
+ fieldsize * 8 <= last_size and
+ bitoffset + bitsize <= last_size):
+ # continue bit field
+ field_type = CONT_BITFIELD
+ elif (not _MS_WINDOWS and
+ last_size and # we have a bitfield open
+ fieldsize * 8 >= last_size and
+ bitoffset + bitsize <= fieldsize * 8):
+ # expand bit field
+ field_type = EXPAND_BITFIELD
+ else:
+ # start new bitfield
+ field_type = NEW_BITFIELD
+ bitoffset = 0
+ last_size = fieldsize * 8
+
if is_union:
pos.append(0)
size = max(size, fieldsize)
else:
- size = round_up(size, fieldalignment)
- pos.append(size)
- size += intmask(fieldsize)
+ if field_type == NO_BITFIELD:
+ # the usual case
+ size = round_up(size, fieldalignment)
+ pos.append(size)
+ size += intmask(fieldsize)
+ bitsizes.append(fieldsize)
+ elif field_type == NEW_BITFIELD:
+ bitsizes.append((bitsize << 16) + bitoffset)
+ bitoffset = bitsize
+ size = round_up(size, fieldalignment)
+ pos.append(size)
+ size += fieldsize
+ elif field_type == CONT_BITFIELD:
+ bitsizes.append((bitsize << 16) + bitoffset)
+ bitoffset += bitsize
+ # offset is already updated for the NEXT field
+ pos.append(size - fieldsize)
+ elif field_type == EXPAND_BITFIELD:
+ size += fieldsize - last_size / 8
+ last_size = fieldsize * 8
+ bitsizes.append((bitsize << 16) + bitoffset)
+ bitoffset += bitsize
+ # offset is already updated for the NEXT field
+ pos.append(size - fieldsize)
size = round_up(size, alignment)
- return size, alignment, pos
+ return size, alignment, pos, bitsizes
class W_Structure(W_DataShape):
@@ -59,19 +117,21 @@
name_to_index = {}
if fields is not None:
for i in range(len(fields)):
- name, tp = fields[i]
+ name, tp, bitsize = fields[i]
if name in name_to_index:
raise operationerrfmt(space.w_ValueError,
"duplicate field name %s", name)
name_to_index[name] = i
- size, alignment, pos = size_alignment_pos(fields, is_union)
+ size, alignment, pos, bitfields = size_alignment_pos(fields, is_union)
else: # opaque case
fields = []
pos = []
+ bitfields = []
self.fields = fields
self.size = size
self.alignment = alignment
self.ll_positions = pos
+ self.ll_bitfields = bitfields
self.name_to_index = name_to_index
def allocate(self, space, length, autofree=False):
@@ -92,7 +152,7 @@
descr_call.unwrap_spec = ['self', ObjSpace, int]
def descr_repr(self, space):
- fieldnames = ' '.join(["'%s'" % name for name, _ in self.fields])
+ fieldnames = ' '.join(["'%s'" % name for name, _, _ in self.fields])
return space.wrap("<_rawffi.Structure %s (%d, %d)>" % (fieldnames,
self.size,
self.alignment))
@@ -118,7 +178,7 @@
# Seeing no corresponding doc in clibffi, let's just repeat
# the field 5 times...
fieldtypes = []
- for name, tp in self.fields:
+ for name, tp, bitsize in self.fields:
basic_ffi_type = tp.get_basic_ffi_type()
basic_size, _ = size_alignment(basic_ffi_type)
total_size = tp.size
@@ -189,7 +249,7 @@
if not self.ll_buffer:
raise segfault_exception(space, "accessing NULL pointer")
i = self.shape.getindex(space, attr)
- _, tp = self.shape.fields[i]
+ _, tp, _ = self.shape.fields[i]
return wrap_value(space, cast_pos, self, i, tp.itemcode)
getattr.unwrap_spec = ['self', ObjSpace, str]
@@ -197,7 +257,7 @@
if not self.ll_buffer:
raise segfault_exception(space, "accessing NULL pointer")
i = self.shape.getindex(space, attr)
- _, tp = self.shape.fields[i]
+ _, tp, _ = self.shape.fields[i]
unwrap_value(space, push_field, self, i, tp.itemcode, w_value)
setattr.unwrap_spec = ['self', ObjSpace, str, W_Root]
More information about the Pypy-commit
mailing list