Commits

Armin Rigo committed 1300a89 Draft

Tweak tweak tweaks to add the correct immutable hints.

  • Participants
  • Parent commits efb8662
  • Branches ffi-backend

Comments (0)

Files changed (12)

File pypy/module/_cffi_backend/cbuffer.py

 
 
 class LLBuffer(RWBuffer):
+    _immutable_ = True
 
     def __init__(self, raw_cdata, size):
         self.raw_cdata = raw_cdata

File pypy/module/_cffi_backend/ccallback.py

 
 from pypy.module._cffi_backend.cdataobj import W_CData, W_CDataApplevelOwning
 from pypy.module._cffi_backend.ctypefunc import SIZE_OF_FFI_ARG, BIG_ENDIAN
+from pypy.module._cffi_backend.ctypefunc import W_CTypeFunc
 from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveSigned
 from pypy.module._cffi_backend.ctypevoid import W_CTypeVoid
 from pypy.module._cffi_backend import cerrno, misc
         self.w_callable = w_callable
         self.w_error = w_error
         #
-        fresult = self.ctype.ctitem
+        fresult = self.getfunctype().ctitem
         size = fresult.size
         if size > 0:
             if fresult.is_primitive_integer and size < SIZE_OF_FFI_ARG:
         self.unique_id = compute_unique_id(self)
         global_callback_mapping.set(self.unique_id, self)
         #
-        cif_descr = ctype.cif_descr
+        cif_descr = self.getfunctype().cif_descr
         if not cif_descr:
             raise OperationError(space.w_NotImplementedError,
                                  space.wrap("callbacks with '...'"))
         space = self.space
         return 'calling ' + space.str_w(space.repr(self.w_callable))
 
+    def getfunctype(self):
+        ctype = self.ctype
+        if not isinstance(ctype, W_CTypeFunc):
+            space = self.space
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("expected a function ctype"))
+        return ctype
+
     def invoke(self, ll_args, ll_res):
         space = self.space
-        ctype = self.ctype
+        ctype = self.getfunctype()
         args_w = []
         for i, farg in enumerate(ctype.fargs):
             ll_arg = rffi.cast(rffi.CCHARP, ll_args[i])
         operr.write_unraisable(space, "in cffi callback", self.w_callable)
 
     def write_error_return_value(self, ll_res):
-        fresult = self.ctype.ctitem
+        fresult = self.getfunctype().ctitem
         if fresult.size > 0:
             # push push push at the llmemory interface (with hacks that
             # are all removed after translation)

File pypy/module/_cffi_backend/ctypearray.py

 
 
 class W_CTypeArray(W_CTypePtrOrArray):
+    _immutable_ = True
 
     def __init__(self, space, ctptr, length, arraysize, extra):
         W_CTypePtrOrArray.__init__(self, space, arraysize, extra, 0,
 
 
 class W_CDataIter(Wrappable):
+    _immutable_fields_ = ['ctitem', 'cdata', '_stop']    # but not '_next'
 
     def __init__(self, space, ctitem, cdata):
         self.space = space

File pypy/module/_cffi_backend/ctypeenum.py

 
 
 class W_CTypeEnum(W_CTypePrimitiveSigned):
+    _immutable_ = True
 
     def __init__(self, space, name, enumerators, enumvalues):
         from pypy.module._cffi_backend.newtype import alignment

File pypy/module/_cffi_backend/ctypefunc.py

 from pypy.module._cffi_backend.ctypeobj import W_CType
 from pypy.module._cffi_backend.ctypeptr import W_CTypePtrBase
 from pypy.module._cffi_backend.ctypevoid import W_CTypeVoid
+from pypy.module._cffi_backend.ctypestruct import W_CTypeStruct
 from pypy.module._cffi_backend.ctypestruct import W_CTypeStructOrUnion
-from pypy.module._cffi_backend import ctypeprim, ctypestruct, ctypearray
-from pypy.module._cffi_backend import cdataobj, cerrno
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveSigned
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveUnsigned
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveCharOrUniChar
+from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveFloat
+from pypy.module._cffi_backend import ctypearray, cdataobj, cerrno
 
 
 class W_CTypeFunc(W_CTypePtrBase):
+    _immutable_ = True
 
     def __init__(self, space, fargs, fresult, ellipsis):
-        self.cif_descr = lltype.nullptr(CIF_DESCRIPTION)
         extra = self._compute_extra_text(fargs, fresult, ellipsis)
         size = rffi.sizeof(rffi.VOIDP)
         W_CTypePtrBase.__init__(self, space, size, extra, 2, fresult,
                 argtype = self.fargs[i]
                 #
                 # special-case for strings.  xxx should avoid copying
-                if argtype.is_char_ptr_or_array:
+                if argtype.is_char_ptr_or_array():
                     try:
                         s = space.str_w(w_obj)
                     except OperationError, e:
                     # set the "must free" flag to 0
                     set_mustfree_flag(data, 0)
                 #
-                if argtype.is_unichar_ptr_or_array:
+                if argtype.is_unichar_ptr_or_array():
                     try:
                         space.unicode_w(w_obj)
                     except OperationError, e:
         finally:
             for i in range(mustfree_max_plus_1):
                 argtype = self.fargs[i]
-                if argtype.is_char_ptr_or_array:
+                if argtype.is_char_ptr_or_array():
                     data = rffi.ptradd(buffer, cif_descr.exchange_args[i])
                     if get_mustfree_flag(data):
                         raw_string = rffi.cast(rffi.CCHARPP, data)[0]
     ('exchange_args', rffi.CArray(lltype.Signed)))
 
 CIF_DESCRIPTION_P = lltype.Ptr(CIF_DESCRIPTION)
+W_CTypeFunc.cif_descr = lltype.nullptr(CIF_DESCRIPTION)     # default value
 
-# We attach (lazily or not) to the classes or instances a 'ffi_type' attribute
-W_CType.ffi_type = lltype.nullptr(FFI_TYPE_P.TO)
-W_CTypePtrBase.ffi_type = clibffi.ffi_type_pointer
-W_CTypeVoid.ffi_type = clibffi.ffi_type_void
 
-def _settype(ctype, ffi_type):
-    ctype.ffi_type = ffi_type
-    return ffi_type
+# ----------
+# We attach to the classes small methods that return a 'ffi_type'
+def _missing_ffi_type(self, cifbuilder):
+    space = self.space
+    if self.size < 0:
+        raise operationerrfmt(space.w_TypeError,
+                              "ctype '%s' has incomplete type",
+                              self.name)
+    raise operationerrfmt(space.w_NotImplementedError,
+                          "ctype '%s' (size %d) not supported as argument"
+                          " or return value",
+                          self.name, self.size)
+
+def _struct_ffi_type(self, cifbuilder):
+    if self.size >= 0:
+        return cifbuilder.fb_struct_ffi_type(self)
+    return _missing_ffi_type(self, cifbuilder)
+
+def _primsigned_ffi_type(self, cifbuilder):
+    size = self.size
+    if   size == 1: return clibffi.ffi_type_sint8
+    elif size == 2: return clibffi.ffi_type_sint16
+    elif size == 4: return clibffi.ffi_type_sint32
+    elif size == 8: return clibffi.ffi_type_sint64
+    return _missing_ffi_type(self, cifbuilder)
+
+def _primunsigned_ffi_type(self, cifbuilder):
+    size = self.size
+    if   size == 1: return clibffi.ffi_type_uint8
+    elif size == 2: return clibffi.ffi_type_uint16
+    elif size == 4: return clibffi.ffi_type_uint32
+    elif size == 8: return clibffi.ffi_type_uint64
+    return _missing_ffi_type(self, cifbuilder)
+
+def _primfloat_ffi_type(self, cifbuilder):
+    size = self.size
+    if   size == 4: return clibffi.ffi_type_float
+    elif size == 8: return clibffi.ffi_type_double
+    return _missing_ffi_type(self, cifbuilder)
+
+def _ptr_ffi_type(self, cifbuilder):
+    return clibffi.ffi_type_pointer
+
+def _void_ffi_type(self, cifbuilder):
+    return clibffi.ffi_type_void
+
+W_CType._get_ffi_type                       = _missing_ffi_type
+W_CTypeStruct._get_ffi_type                 = _struct_ffi_type
+W_CTypePrimitiveSigned._get_ffi_type        = _primsigned_ffi_type
+W_CTypePrimitiveCharOrUniChar._get_ffi_type = _primunsigned_ffi_type
+W_CTypePrimitiveUnsigned._get_ffi_type      = _primunsigned_ffi_type
+W_CTypePrimitiveFloat._get_ffi_type         = _primfloat_ffi_type
+W_CTypePtrBase._get_ffi_type                = _ptr_ffi_type
+W_CTypeVoid._get_ffi_type                   = _void_ffi_type
+# ----------
 
 
 class CifDescrBuilder(object):
 
 
     def fb_fill_type(self, ctype):
-        if ctype.ffi_type:   # common case: the ffi_type was already computed
-            return ctype.ffi_type
+        return ctype._get_ffi_type(self)
 
+    def fb_struct_ffi_type(self, ctype):
+        # We can't pass a struct that was completed by verify().
+        # Issue: assume verify() is given "struct { long b; ...; }".
+        # Then it will complete it in the same way whether it is actually
+        # "struct { long a, b; }" or "struct { double a; long b; }".
+        # But on 64-bit UNIX, these two structs are passed by value
+        # differently: e.g. on x86-64, "b" ends up in register "rsi" in
+        # the first case and "rdi" in the second case.
         space = self.space
-        size = ctype.size
-        if size < 0:
-            raise operationerrfmt(space.w_TypeError,
-                                  "ctype '%s' has incomplete type",
-                                  ctype.name)
+        if ctype.custom_field_pos:
+            raise OperationError(space.w_TypeError,
+                                 space.wrap(
+               "cannot pass as an argument a struct that was completed "
+               "with verify() (see pypy/module/_cffi_backend/ctypefunc.py "
+               "for details)"))
 
-        if isinstance(ctype, ctypestruct.W_CTypeStruct):
+        # allocate an array of (n + 1) ffi_types
+        n = len(ctype.fields_list)
+        elements = self.fb_alloc(rffi.sizeof(FFI_TYPE_P) * (n + 1))
+        elements = rffi.cast(FFI_TYPE_PP, elements)
 
-            # We can't pass a struct that was completed by verify().
-            # Issue: assume verify() is given "struct { long b; ...; }".
-            # Then it will complete it in the same way whether it is actually
-            # "struct { long a, b; }" or "struct { double a; long b; }".
-            # But on 64-bit UNIX, these two structs are passed by value
-            # differently: e.g. on x86-64, "b" ends up in register "rsi" in
-            # the first case and "rdi" in the second case.
-            if ctype.custom_field_pos:
-                raise OperationError(space.w_TypeError,
-                                     space.wrap(
-                   "cannot pass as an argument a struct that was completed "
-                   "with verify() (see pypy/module/_cffi_backend/ctypefunc.py "
-                   "for details)"))
+        # fill it with the ffi types of the fields
+        for i, cf in enumerate(ctype.fields_list):
+            if cf.is_bitfield():
+                raise OperationError(space.w_NotImplementedError,
+                    space.wrap("cannot pass as argument a struct "
+                               "with bit fields"))
+            ffi_subtype = self.fb_fill_type(cf.ctype)
+            if elements:
+                elements[i] = ffi_subtype
 
-            # allocate an array of (n + 1) ffi_types
-            n = len(ctype.fields_list)
-            elements = self.fb_alloc(rffi.sizeof(FFI_TYPE_P) * (n + 1))
-            elements = rffi.cast(FFI_TYPE_PP, elements)
+        # zero-terminate the array
+        if elements:
+            elements[n] = lltype.nullptr(FFI_TYPE_P.TO)
 
-            # fill it with the ffi types of the fields
-            for i, cf in enumerate(ctype.fields_list):
-                if cf.is_bitfield():
-                    raise OperationError(space.w_NotImplementedError,
-                        space.wrap("cannot pass as argument a struct "
-                                   "with bit fields"))
-                ffi_subtype = self.fb_fill_type(cf.ctype)
-                if elements:
-                    elements[i] = ffi_subtype
+        # allocate and fill an ffi_type for the struct itself
+        ffistruct = self.fb_alloc(rffi.sizeof(FFI_TYPE))
+        ffistruct = rffi.cast(FFI_TYPE_P, ffistruct)
+        if ffistruct:
+            rffi.setintfield(ffistruct, 'c_size', ctype.size)
+            rffi.setintfield(ffistruct, 'c_alignment', ctype.alignof())
+            rffi.setintfield(ffistruct, 'c_type', clibffi.FFI_TYPE_STRUCT)
+            ffistruct.c_elements = elements
 
-            # zero-terminate the array
-            if elements:
-                elements[n] = lltype.nullptr(FFI_TYPE_P.TO)
-
-            # allocate and fill an ffi_type for the struct itself
-            ffistruct = self.fb_alloc(rffi.sizeof(FFI_TYPE))
-            ffistruct = rffi.cast(FFI_TYPE_P, ffistruct)
-            if ffistruct:
-                rffi.setintfield(ffistruct, 'c_size', size)
-                rffi.setintfield(ffistruct, 'c_alignment', ctype.alignof())
-                rffi.setintfield(ffistruct, 'c_type', clibffi.FFI_TYPE_STRUCT)
-                ffistruct.c_elements = elements
-
-            return ffistruct
-
-        elif isinstance(ctype, ctypeprim.W_CTypePrimitiveSigned):
-            # compute lazily once the ffi_type
-            if   size == 1: return _settype(ctype, clibffi.ffi_type_sint8)
-            elif size == 2: return _settype(ctype, clibffi.ffi_type_sint16)
-            elif size == 4: return _settype(ctype, clibffi.ffi_type_sint32)
-            elif size == 8: return _settype(ctype, clibffi.ffi_type_sint64)
-
-        elif (isinstance(ctype, ctypeprim.W_CTypePrimitiveCharOrUniChar) or
-              isinstance(ctype, ctypeprim.W_CTypePrimitiveUnsigned)):
-            if   size == 1: return _settype(ctype, clibffi.ffi_type_uint8)
-            elif size == 2: return _settype(ctype, clibffi.ffi_type_uint16)
-            elif size == 4: return _settype(ctype, clibffi.ffi_type_uint32)
-            elif size == 8: return _settype(ctype, clibffi.ffi_type_uint64)
-
-        elif isinstance(ctype, ctypeprim.W_CTypePrimitiveFloat):
-            if   size == 4: return _settype(ctype, clibffi.ffi_type_float)
-            elif size == 8: return _settype(ctype, clibffi.ffi_type_double)
-
-        raise operationerrfmt(space.w_NotImplementedError,
-                              "ctype '%s' (size %d) not supported as argument"
-                              " or return value",
-                              ctype.name, size)
+        return ffistruct
 
 
     def fb_build(self):
 
         # loop over args
         for i, farg in enumerate(self.fargs):
-            if farg.is_char_ptr_or_array:
+            if farg.is_char_ptr_or_array():
                 exchange_offset += 1   # for the "must free" flag
             exchange_offset = self.align_arg(exchange_offset)
             cif_descr.exchange_args[i] = exchange_offset

File pypy/module/_cffi_backend/ctypeobj.py

 
 
 class W_CType(Wrappable):
-    #_immutable_ = True    XXX newtype.complete_struct_or_union()?
+    _attrs_ = ['space', 'size', 'name', 'name_position']
+    _immutable_fields_ = _attrs_
+
     cast_anything = False
-    is_char_ptr_or_array = False
-    is_unichar_ptr_or_array = False
     is_primitive_integer = False
 
     def __init__(self, space, size, name, name_position):
         else:
             return 'NULL'
 
+    def is_char_ptr_or_array(self):
+        return False
+
+    def is_unichar_ptr_or_array(self):
+        return False
+
     def newp(self, w_init):
         space = self.space
         raise operationerrfmt(space.w_TypeError,

File pypy/module/_cffi_backend/ctypeprim.py

 
 
 class W_CTypePrimitive(W_CType):
+    _immutable_ = True
 
     def __init__(self, space, size, name, name_position, align):
         W_CType.__init__(self, space, size, name, name_position)
 
 
 class W_CTypePrimitiveCharOrUniChar(W_CTypePrimitive):
+    _immutable_ = True
     is_primitive_integer = True
 
 
 class W_CTypePrimitiveChar(W_CTypePrimitiveCharOrUniChar):
+    _immutable_ = True
     cast_anything = True
 
     def int(self, cdata):
 
 
 class W_CTypePrimitiveUniChar(W_CTypePrimitiveCharOrUniChar):
+    _immutable_ = True
 
     def int(self, cdata):
         unichardata = rffi.cast(rffi.CWCHARP, cdata)
 
 
 class W_CTypePrimitiveSigned(W_CTypePrimitive):
+    _immutable_ = True
     is_primitive_integer = True
 
     def __init__(self, *args):
 
 
 class W_CTypePrimitiveUnsigned(W_CTypePrimitive):
+    _immutable_ = True
     is_primitive_integer = True
 
     def __init__(self, *args):
 
 
 class W_CTypePrimitiveFloat(W_CTypePrimitive):
+    _immutable_ = True
 
     def cast(self, w_ob):
         space = self.space

File pypy/module/_cffi_backend/ctypeptr.py

 
 
 class W_CTypePtrOrArray(W_CType):
+    _immutable_ = True
 
     def __init__(self, space, size, extra, extra_position, ctitem,
                  could_cast_anything=True):
-        from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveChar
-        from pypy.module._cffi_backend.ctypeprim import W_CTypePrimitiveUniChar
         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)
         #  - for functions, it is the return type
         self.ctitem = ctitem
         self.can_cast_anything = could_cast_anything and ctitem.cast_anything
-        self.is_char_ptr_or_array = isinstance(ctitem, W_CTypePrimitiveChar)
-        self.is_unichar_ptr_or_array=isinstance(ctitem,W_CTypePrimitiveUniChar)
         self.is_struct_ptr = isinstance(ctitem, W_CTypeStructOrUnion)
 
+    def is_char_ptr_or_array(self):
+        from pypy.module._cffi_backend import ctypeprim
+        return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveChar)
+
+    def is_unichar_ptr_or_array(self):
+        from pypy.module._cffi_backend import ctypeprim
+        return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveUniChar)
+
+    def is_char_or_unichar_ptr_or_array(self):
+        from pypy.module._cffi_backend import ctypeprim
+        return isinstance(self.ctitem, ctypeprim.W_CTypePrimitiveCharOrUniChar)
+
     def cast(self, w_ob):
         # cast to a pointer, to a funcptr, or to an array.
         # Note that casting to an array is an extension to the C language,
 
 class W_CTypePtrBase(W_CTypePtrOrArray):
     # base class for both pointers and pointers-to-functions
+    _immutable_ = True
 
     def convert_to_object(self, cdata):
         ptrdata = rffi.cast(rffi.CCHARPP, cdata)[0]
 
 
 class W_CTypePointer(W_CTypePtrBase):
+    _immutable_ = True
 
     def __init__(self, space, ctitem):
         from pypy.module._cffi_backend import ctypearray
         W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem)
 
     def str(self, cdataobj):
-        if self.is_char_ptr_or_array:
+        if self.is_char_ptr_or_array():
             if not cdataobj._cdata:
                 space = self.space
                 raise operationerrfmt(space.w_RuntimeError,
         return W_CTypePtrOrArray.str(self, cdataobj)
 
     def unicode(self, cdataobj):
-        if self.is_unichar_ptr_or_array:
+        if self.is_unichar_ptr_or_array():
             if not cdataobj._cdata:
                 space = self.space
                 raise operationerrfmt(space.w_RuntimeError,
                                                        cdatastruct._cdata,
                                                        self, cdatastruct)
         else:
-            if self.is_char_ptr_or_array or self.is_unichar_ptr_or_array:
+            if self.is_char_or_unichar_ptr_or_array():
                 datasize *= 2       # forcefully add a null character
             cdata = cdataobj.W_CDataNewOwning(space, datasize, self)
         #

File pypy/module/_cffi_backend/ctypestruct.py

 
 
 class W_CTypeStructOrUnion(W_CType):
+    # not an _immutable_ class!
     # fields added by complete_struct_or_union():
     alignment = -1
     fields_list = None

File pypy/module/_cffi_backend/ctypevoid.py

 
 
 class W_CTypeVoid(W_CType):
+    _immutable_ = True
     cast_anything = True
 
     def __init__(self, space):

File pypy/module/_cffi_backend/func.py

 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.rpython.lltypesystem import lltype, rffi
 
-from pypy.module._cffi_backend import ctypeobj, cdataobj, ctypefunc
+from pypy.module._cffi_backend import ctypeobj, cdataobj
 
 
 # ____________________________________________________________
 
 # ____________________________________________________________
 
-@unwrap_spec(ctype=ctypefunc.W_CTypeFunc)
+@unwrap_spec(ctype=ctypeobj.W_CType)
 def callback(space, ctype, w_callable, w_error=None):
     from pypy.module._cffi_backend.ccallback import W_CDataCallback
     return W_CDataCallback(space, ctype, w_callable, w_error)

File pypy/module/_cffi_backend/libraryobj.py

 
 
 class W_Library(Wrappable):
+    _immutable_ = True
     handle = rffi.cast(DLLHANDLE, 0)
 
     def __init__(self, space, filename, is_global):