Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r67889:73de8b43bff0 Date: 2013-11-09 10:33 +0100 http://bitbucket.org/pypy/pypy/changeset/73de8b43bff0/
Log: Port cffi's c99-array branch. diff --git a/pypy/module/_cffi_backend/ctypearray.py b/pypy/module/_cffi_backend/ctypearray.py --- a/pypy/module/_cffi_backend/ctypearray.py +++ b/pypy/module/_cffi_backend/ctypearray.py @@ -34,19 +34,8 @@ datasize = self.size # if datasize < 0: - if (space.isinstance_w(w_init, space.w_list) or - space.isinstance_w(w_init, space.w_tuple)): - length = space.int_w(space.len(w_init)) - elif space.isinstance_w(w_init, space.w_basestring): - # from a string, we add the null terminator - length = space.int_w(space.len(w_init)) + 1 - else: - length = space.getindex_w(w_init, space.w_OverflowError) - if length < 0: - raise OperationError(space.w_ValueError, - space.wrap("negative array length")) - w_init = space.w_None - # + from pypy.module._cffi_backend import misc + w_init, length = misc.get_new_array_length(space, w_init) try: datasize = ovfcheck(length * self.ctitem.size) except OverflowError: diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py --- a/pypy/module/_cffi_backend/ctypeptr.py +++ b/pypy/module/_cffi_backend/ctypeptr.py @@ -15,15 +15,12 @@ class W_CTypePtrOrArray(W_CType): - _attrs_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr', - 'length'] - _immutable_fields_ = ['ctitem', 'can_cast_anything', 'is_struct_ptr', - 'length'] + _attrs_ = ['ctitem', 'can_cast_anything', 'length'] + _immutable_fields_ = ['ctitem', 'can_cast_anything', 'length'] length = -1 def __init__(self, space, size, extra, extra_position, ctitem, could_cast_anything=True): - from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion name, name_position = ctitem.insert_name(extra, extra_position) W_CType.__init__(self, space, size, name, name_position) # this is the "underlying type": @@ -32,7 +29,6 @@ # - for functions, it is the return type self.ctitem = ctitem self.can_cast_anything = could_cast_anything and ctitem.cast_anything - self.is_struct_ptr = isinstance(ctitem, W_CTypeStructOrUnion) def is_char_ptr_or_array(self): return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar) @@ -195,6 +191,7 @@ W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem) def newp(self, w_init): + from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion space = self.space ctitem = self.ctitem datasize = ctitem.size @@ -202,10 +199,15 @@ raise operationerrfmt(space.w_TypeError, "cannot instantiate ctype '%s' of unknown size", self.name) - if self.is_struct_ptr: + if isinstance(ctitem, W_CTypeStructOrUnion): # 'newp' on a struct-or-union pointer: in this case, we return # a W_CDataPtrToStruct object which has a strong reference # to a W_CDataNewOwning that really contains the structure. + # + if ctitem.with_var_array and not space.is_w(w_init, space.w_None): + datasize = ctitem.convert_struct_from_object( + lltype.nullptr(rffi.CCHARP.TO), w_init, datasize) + # cdatastruct = cdataobj.W_CDataNewOwning(space, datasize, ctitem) cdata = cdataobj.W_CDataPtrToStructOrUnion(space, cdatastruct._cdata, @@ -321,7 +323,8 @@ space = self.space ctype2 = cdata.ctype if (isinstance(ctype2, W_CTypeStructOrUnion) or - (isinstance(ctype2, W_CTypePtrOrArray) and ctype2.is_struct_ptr)): + (isinstance(ctype2, W_CTypePtrOrArray) and + isinstance(ctype2.ctitem, W_CTypeStructOrUnion))): ptrdata = rffi.ptradd(cdata._cdata, offset) return cdataobj.W_CData(space, ptrdata, self) else: diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py --- a/pypy/module/_cffi_backend/ctypestruct.py +++ b/pypy/module/_cffi_backend/ctypestruct.py @@ -9,7 +9,8 @@ from rpython.rlib import jit from rpython.rlib.objectmodel import keepalive_until_here from rpython.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong, intmask -from rpython.rtyper.lltypesystem import rffi +from rpython.rlib.rarithmetic import ovfcheck +from rpython.rtyper.lltypesystem import lltype, rffi from pypy.module._cffi_backend import cdataobj, ctypeprim, misc from pypy.module._cffi_backend.ctypeobj import W_CType @@ -17,12 +18,13 @@ class W_CTypeStructOrUnion(W_CType): _immutable_fields_ = ['alignment?', 'fields_list?', 'fields_dict?', - 'custom_field_pos?'] + 'custom_field_pos?', 'with_var_array?'] # fields added by complete_struct_or_union(): alignment = -1 fields_list = None fields_dict = None custom_field_pos = False + with_var_array = False def __init__(self, space, name): W_CType.__init__(self, space, -1, name, len(name)) @@ -90,12 +92,13 @@ pass def convert_from_object(self, cdata, w_ob): - space = self.space - if self._copy_from_same(cdata, w_ob): - return + if not self._copy_from_same(cdata, w_ob): + self.convert_struct_from_object(cdata, w_ob) + def convert_struct_from_object(self, cdata, w_ob, optvarsize=-1): self._check_only_one_argument_for_union(w_ob) + space = self.space if (space.isinstance_w(w_ob, space.w_list) or space.isinstance_w(w_ob, space.w_tuple)): lst_w = space.listview(w_ob) @@ -104,7 +107,9 @@ "too many initializers for '%s' (got %d)", self.name, len(lst_w)) for i in range(len(lst_w)): - self.fields_list[i].write(cdata, lst_w[i]) + optvarsize = self.fields_list[i].write_v(cdata, lst_w[i], + optvarsize) + return optvarsize elif space.isinstance_w(w_ob, space.w_dict): lst_w = space.fixedview(w_ob) @@ -116,11 +121,16 @@ except KeyError: space.raise_key_error(w_key) assert 0 - cf.write(cdata, space.getitem(w_ob, w_key)) + optvarsize = cf.write_v(cdata, space.getitem(w_ob, w_key), + optvarsize) + return optvarsize else: - raise self._convert_error("list or tuple or dict or struct-cdata", - w_ob) + if optvarsize == -1: + msg = "list or tuple or dict or struct-cdata" + else: + msg = "list or tuple or dict" + raise self._convert_error(msg, w_ob) @jit.elidable def _getcfield_const(self, attr): @@ -192,6 +202,37 @@ else: self.ctype.convert_from_object(cdata, w_ob) + def write_v(self, cdata, w_ob, optvarsize): + # a special case for var-sized C99 arrays + from pypy.module._cffi_backend import ctypearray + ct = self.ctype + if isinstance(ct, ctypearray.W_CTypeArray) and ct.length < 0: + space = ct.space + w_ob, varsizelength = misc.get_new_array_length(space, w_ob) + if optvarsize != -1: + # in this mode, the only purpose of this function is to compute + # the real size of the structure from a var-sized C99 array + assert cdata == lltype.nullptr(rffi.CCHARP.TO) + itemsize = ct.ctitem.size + try: + varsize = ovfcheck(itemsize * varsizelength) + size = ovfcheck(self.offset + varsize) + except OverflowError: + raise OperationError(space.w_OverflowError, + space.wrap("array size would overflow a ssize_t")) + assert size >= 0 + return max(size, optvarsize) + # if 'value' was only an integer, get_new_array_length() returns + # w_ob = space.w_None. Detect if this was the case, + # and if so, stop here, leaving the content uninitialized + # (it should be zero-initialized from somewhere else). + if space.is_w(w_ob, space.w_None): + return optvarsize + # + if optvarsize == -1: + self.write(cdata, w_ob) + return optvarsize + def convert_bitfield_to_object(self, cdata): ctype = self.ctype space = ctype.space diff --git a/pypy/module/_cffi_backend/misc.py b/pypy/module/_cffi_backend/misc.py --- a/pypy/module/_cffi_backend/misc.py +++ b/pypy/module/_cffi_backend/misc.py @@ -278,6 +278,22 @@ # ____________________________________________________________ +def get_new_array_length(space, w_value): + if (space.isinstance_w(w_value, space.w_list) or + space.isinstance_w(w_value, space.w_tuple)): + return (w_value, space.int_w(space.len(w_value))) + elif space.isinstance_w(w_value, space.w_basestring): + # from a string, we add the null terminator + return (w_value, space.int_w(space.len(w_value)) + 1) + else: + explicitlength = space.getindex_w(w_value, space.w_OverflowError) + if explicitlength < 0: + raise OperationError(space.w_ValueError, + space.wrap("negative array length")) + return (space.w_None, explicitlength) + +# ____________________________________________________________ + @specialize.arg(0) def _raw_memcopy_tp(TPP, source, dest): # in its own function: LONGLONG may make the whole function jit-opaque diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py --- a/pypy/module/_cffi_backend/newtype.py +++ b/pypy/module/_cffi_backend/newtype.py @@ -158,8 +158,10 @@ fields_list = [] fields_dict = {} custom_field_pos = False + with_var_array = False - for w_field in fields_w: + for i in range(len(fields_w)): + w_field = fields_w[i] field_w = space.fixedview(w_field) if not (2 <= len(field_w) <= 4): raise OperationError(space.w_TypeError, @@ -176,7 +178,11 @@ "duplicate field name '%s'", fname) # if ftype.size < 0: - raise operationerrfmt(space.w_TypeError, + if (isinstance(ftype, ctypearray.W_CTypeArray) and fbitsize < 0 + and (i == len(fields_w) - 1 or foffset != -1)): + with_var_array = True + else: + raise operationerrfmt(space.w_TypeError, "field '%s.%s' has ctype '%s' of unknown size", w_ctype.name, fname, ftype.name) # @@ -235,7 +241,8 @@ fields_list.append(fld) fields_dict[fname] = fld - boffset += ftype.size * 8 + if ftype.size >= 0: + boffset += ftype.size * 8 prev_bitfield_size = 0 else: @@ -359,6 +366,7 @@ w_ctype.fields_list = fields_list w_ctype.fields_dict = fields_dict w_ctype.custom_field_pos = custom_field_pos + w_ctype.with_var_array = with_var_array # ____________________________________________________________ _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit