Author: Armin Rigo <ar...@tunes.org> Branch: ffi-backend Changeset: r55780:e73d843759a7 Date: 2012-06-23 15:46 +0200 http://bitbucket.org/pypy/pypy/changeset/e73d843759a7/
Log: Pom pom pom diff --git a/pypy/module/_ffi_backend/__init__.py b/pypy/module/_ffi_backend/__init__.py --- a/pypy/module/_ffi_backend/__init__.py +++ b/pypy/module/_ffi_backend/__init__.py @@ -12,9 +12,12 @@ 'new_primitive_type': 'newtype.new_primitive_type', 'new_pointer_type': 'newtype.new_pointer_type', 'new_array_type': 'newtype.new_array_type', + 'new_struct_type': 'newtype.new_struct_type', + 'complete_struct_or_union': 'newtype.complete_struct_or_union', 'newp': 'func.newp', 'cast': 'func.cast', 'sizeof': 'func.sizeof', 'alignof': 'func.alignof', + '_getfields': 'func._getfields', } diff --git a/pypy/module/_ffi_backend/ctypeobj.py b/pypy/module/_ffi_backend/ctypeobj.py --- a/pypy/module/_ffi_backend/ctypeobj.py +++ b/pypy/module/_ffi_backend/ctypeobj.py @@ -1,16 +1,16 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.interpreter.typedef import TypeDef +from pypy.interpreter.typedef import TypeDef, interp_attrproperty from pypy.rpython.lltypesystem import lltype, rffi from pypy.rlib.rarithmetic import intmask, ovfcheck -from pypy.rlib.objectmodel import keepalive_until_here +from pypy.rlib.objectmodel import keepalive_until_here, we_are_translated from pypy.module._ffi_backend import cdataobj, misc class W_CType(Wrappable): - _immutable_ = True + #_immutable_ = True XXX newtype.complete_struct_or_union()? def __init__(self, space, size, name, name_position): self.space = space @@ -72,8 +72,20 @@ return name, name_position def alignof(self): + align = self._alignof() + if not we_are_translated(): + # obscure hack when untranslated, maybe, approximate, don't use + from pypy.rpython.lltypesystem import llmemory + if isinstance(align, llmemory.FieldOffset): + align = rffi.sizeof(align.TYPE.y) + return align + + def _alignof(self): xxx + def _getfields(self): + return None + class W_CTypePtrOrArray(W_CType): @@ -135,7 +147,7 @@ p = rffi.ptradd(cdata, i * self.ctitem.size) return cdataobj.W_CData(self.space, p, self) - def alignof(self): + def _alignof(self): from pypy.module._ffi_backend import newtype return newtype.alignment_of_pointer @@ -148,7 +160,7 @@ self.length = length self.ctptr = ctptr - def alignof(self): + def _alignof(self): return self.ctitem.alignof() def newp(self, w_init): @@ -223,7 +235,7 @@ W_CType.__init__(self, space, size, name, name_position) self.align = align - def alignof(self): + def _alignof(self): return self.align def cast_single_char(self, w_ob): @@ -370,8 +382,61 @@ misc.write_raw_float_data(cdata, value, self.size) +class W_CTypeStructOrUnion(W_CType): + # fields added by complete_struct_or_union(): + alignment = -1 + fields_list = None + fields_dict = None + + def __init__(self, space, name): + name = '%s %s' % (self.kind, name) + W_CType.__init__(self, space, -1, name, len(name)) + + def _alignof(self): + space = self.space + if self.size < 0: + raise operationerrfmt(space.w_TypeError, + "'%s' is not completed yet", self.name) + return self.alignment + + def _getfields(self): + if self.size < 0: + return None + space = self.space + result = [None] * len(self.fields_list) + for fname, field in self.fields_dict.iteritems(): + i = self.fields_list.index(field) + result[i] = space.newtuple([space.wrap(fname), + space.wrap(field)]) + return space.newlist(result) + + +class W_CTypeStruct(W_CTypeStructOrUnion): + kind = "struct" + +class W_CTypeUnion(W_CTypeStructOrUnion): + kind = "union" + +class W_CField(Wrappable): + _immutable_ = True + def __init__(self, ctype, offset, bitshift, bitsize): + self.ctype = ctype + self.offset = offset + self.bitshift = bitshift + self.bitsize = bitsize + + W_CType.typedef = TypeDef( '_ffi_backend.CTypeDescr', __repr__ = interp2app(W_CType.repr), ) W_CType.typedef.acceptable_as_base_class = False + +W_CField.typedef = TypeDef( + '_ffi_backend.CField', + type = interp_attrproperty('ctype', W_CField), + offset = interp_attrproperty('offset', W_CField), + bitshift = interp_attrproperty('bitshift', W_CField), + bitsize = interp_attrproperty('bitsize', W_CField), + ) +W_CField.typedef.acceptable_as_base_class = False diff --git a/pypy/module/_ffi_backend/func.py b/pypy/module/_ffi_backend/func.py --- a/pypy/module/_ffi_backend/func.py +++ b/pypy/module/_ffi_backend/func.py @@ -1,8 +1,7 @@ from pypy.interpreter.error import OperationError, operationerrfmt from pypy.interpreter.baseobjspace import Wrappable from pypy.interpreter.gateway import interp2app, unwrap_spec -from pypy.rpython.lltypesystem import lltype, llmemory, rffi -from pypy.rlib.objectmodel import we_are_translated +from pypy.rpython.lltypesystem import lltype, rffi from pypy.module._ffi_backend import ctypeobj, cdataobj @@ -40,8 +39,8 @@ @unwrap_spec(ctype=ctypeobj.W_CType) def alignof(space, ctype): align = ctype.alignof() - if not we_are_translated(): - # obscure hack when untranslated, maybe, approximate, don't use - assert isinstance(align, llmemory.FieldOffset) - align = rffi.sizeof(align.TYPE.y) return space.wrap(align) + +@unwrap_spec(ctype=ctypeobj.W_CType) +def _getfields(space, ctype): + return ctype._getfields() diff --git a/pypy/module/_ffi_backend/newtype.py b/pypy/module/_ffi_backend/newtype.py --- a/pypy/module/_ffi_backend/newtype.py +++ b/pypy/module/_ffi_backend/newtype.py @@ -80,3 +80,98 @@ # ctypeptr = ctypeobj.W_CTypeArray(space, ctptr, length, arraysize, extra) return ctypeptr + +# ____________________________________________________________ + +@unwrap_spec(name=str) +def new_struct_type(space, name): + return ctypeobj.W_CTypeStruct(space, name) + +@unwrap_spec(ctype=ctypeobj.W_CType, totalsize=int, totalalignment=int) +def complete_struct_or_union(space, ctype, w_fields, w_ignored=None, + totalsize=-1, totalalignment=-1): + if (not isinstance(ctype, ctypeobj.W_CTypeStructOrUnion) + or ctype.size >= 0): + raise OperationError(space.w_TypeError, + space.wrap("first arg must be a non-initialized" + " struct or union ctype")) + + is_union = isinstance(ctype, ctypeobj.W_CTypeUnion) + maxsize = 1 + alignment = 1 + offset = 0 + fields_w = space.listview(w_fields) + fields_list = [] + fields_dict = {} + prev_bit_position = 0 + prev_field = None + + for w_field in fields_w: + field_w = space.fixedview(w_field) + if not (2 <= len(field_w) <= 4): + raise OperationError(space.w_TypeError, + space.wrap("bad field descr")) + fname = space.str_w(field_w[0]) + ftype = space.interp_w(ctypeobj.W_CType, field_w[1]) + fbitsize = -1 + foffset = -1 + if len(field_w) > 2: fbitsize = space.int_w(field_w[2]) + if len(field_w) > 3: foffset = space.int_w(field_w[3]) + # + if fname in fields_dict: + raise operationerrfmt(space.w_KeyError, + "duplicate field name '%s'", fname) + # + if ftype.size < 0: + raise operationerrfmt(space.w_TypeError, + "field '%s.%s' has ctype '%s' of unknown size", + ctype.name, fname, ftype.name) + # + falign = ftype.alignof() + if alignment < falign: + alignment = falign + # + if foffset < 0: + # align this field to its own 'falign' by inserting padding + offset = (offset + falign - 1) & ~(falign-1) + else: + offset = foffset + # + if fbitsize < 0 or (fbitsize == 8 * ftype.size and + not isinstance(ftype, W_CTypePrimitiveChar)): + fbitsize = -1 + bitshift = -1 + prev_bit_position = 0 + else: + xxx + # + fld = ctypeobj.W_CField(ftype, offset, bitshift, fbitsize) + fields_list.append(fld) + fields_dict[fname] = fld + # + if maxsize < ftype.size: + maxsize = ftype.size + if not is_union: + offset += ftype.size + + if is_union: + assert offset == 0 + offset = maxsize + else: + if offset == 0: + offset = 1 + offset = (offset + alignment - 1) & ~(alignment-1) + + if totalsize < 0: + totalsize = offset + elif totalsize < offset: + raise operationerrfmt(space.w_TypeError, + "%s cannot be of size %d: there are fields at least " + "up to %d", ctype.name, totalsize, offset) + if totalalignment < 0: + totalalignment = alignment + + ctype.size = totalsize + ctype.alignment = totalalignment + ctype.fields_list = fields_list + ctype.fields_dict = fields_dict diff --git a/pypy/module/_ffi_backend/test/_backend_test_c.py b/pypy/module/_ffi_backend/test/_backend_test_c.py --- a/pypy/module/_ffi_backend/test/_backend_test_c.py +++ b/pypy/module/_ffi_backend/test/_backend_test_c.py @@ -440,6 +440,7 @@ assert repr(BStruct) == "<ctype 'struct foo'>" BPtr = new_pointer_type(BStruct) assert repr(BPtr) == "<ctype 'struct foo *'>" + py.test.raises(TypeError, alignof, BStruct) def test_new_union_type(): BUnion = new_union_type("foo") _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit