Author: Armin Rigo <[email protected]>
Branch: cffi-1.0
Changeset: r77363:d63d6a4219f7
Date: 2015-05-17 21:09 +0200
http://bitbucket.org/pypy/pypy/changeset/d63d6a4219f7/

Log:    Structs and unions

diff --git a/pypy/module/_cffi_backend/cdlopen.py 
b/pypy/module/_cffi_backend/cdlopen.py
--- a/pypy/module/_cffi_backend/cdlopen.py
+++ b/pypy/module/_cffi_backend/cdlopen.py
@@ -1,103 +1,18 @@
 from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
-from rpython.rlib.objectmodel import specialize
+from rpython.rlib.objectmodel import specialize, we_are_translated
 from rpython.rlib.rdynload import DLLHANDLE, dlopen, dlsym, dlclose, 
DLOpenError
 
 from pypy.interpreter.error import oefmt
 from pypy.module._rawffi.interp_rawffi import wrap_dlopenerror
 
 from pypy.module._cffi_backend.parse_c_type import (
-    _CFFI_OPCODE_T, GLOBAL_S, CDL_INTCONST_S,
+    _CFFI_OPCODE_T, GLOBAL_S, CDL_INTCONST_S, STRUCT_UNION_S, FIELD_S,
     ll_set_cdl_realize_global_int)
 from pypy.module._cffi_backend.realize_c_type import getop
 from pypy.module._cffi_backend.lib_obj import W_LibObject
 from pypy.module._cffi_backend import cffi_opcode
 
 
-class StringDecoder:
-    def __init__(self, ffi, string):
-        self.ffi = ffi
-        self.string = string
-        self.pos = 0
-
-    def next_4bytes(self):
-        pos = self.pos
-        src = ord(self.string[pos])
-        if src >= 0x80:
-            src -= 0x100
-        src = ((src << 24) |
-               (ord(self.string[pos + 1]) << 16) |
-               (ord(self.string[pos + 2]) << 8 ) |
-               (ord(self.string[pos + 3])      ))
-        self.pos = pos + 4
-        return src
-
-    def next_opcode(self):
-        return rffi.cast(_CFFI_OPCODE_T, self.next_4bytes())
-
-    def next_name(self):
-        frm = self.pos
-        i = self.string.find('\x00', frm)
-        if i < 0:
-            i = len(self.string)
-        pos = i + 1
-        p = rffi.str2charp(self.string[frm : i])
-        self.ffi._finalizer.free_mems.append(p)
-        return p
-
-
-def allocate(ffi, nbytes):
-    p = lltype.malloc(rffi.CCHARP.TO, nbytes, flavor='raw', zero=True)
-    ffi._finalizer.free_mems.append(p)
-    return p
-
[email protected](1)
-def allocate_array(ffi, OF, nitems):
-    p = allocate(ffi, nitems * rffi.sizeof(OF))
-    return rffi.cast(rffi.CArrayPtr(OF), p)
-
-
-def ffiobj_init(ffi, module_name, version, types, w_globals,
-                w_struct_unions, w_enums, w_typenames, w_includes):
-    space = ffi.space
-
-    if types:
-        # unpack a string of 4-byte entries into an array of _cffi_opcode_t
-        n = len(types) // 4
-        ntypes = allocate_array(ffi, _CFFI_OPCODE_T, n)
-        decoder = StringDecoder(ffi, types)
-        for i in range(n):
-            ntypes[i] = decoder.next_opcode()
-        ffi.ctxobj.ctx.c_types = ntypes
-        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_types', n)
-        ffi.cached_types = [None] * n
-
-    if w_globals is not None:
-        globals_w = space.fixedview(w_globals)
-        n = len(globals_w) // 2
-        size = n * rffi.sizeof(GLOBAL_S) + n * rffi.sizeof(CDL_INTCONST_S)
-        size = llmemory.raw_malloc_usage(size)
-        p = allocate(ffi, size)
-        nglobs = rffi.cast(rffi.CArrayPtr(GLOBAL_S), p)
-        p = rffi.ptradd(p, llmemory.raw_malloc_usage(n * 
rffi.sizeof(GLOBAL_S)))
-        nintconsts = rffi.cast(rffi.CArrayPtr(CDL_INTCONST_S), p)
-        for i in range(n):
-            decoder = StringDecoder(ffi, space.str_w(globals_w[i * 2]))
-            nglobs[i].c_type_op = decoder.next_opcode()
-            nglobs[i].c_name = decoder.next_name()
-            op = getop(nglobs[i].c_type_op)
-            if op == cffi_opcode.OP_CONSTANT_INT or op == cffi_opcode.OP_ENUM:
-                w_integer = globals_w[i * 2 + 1]
-                ll_set_cdl_realize_global_int(nglobs[i])
-                bigint = space.bigint_w(w_integer)
-                ullvalue = bigint.ulonglongmask()
-                rffi.setintfield(nintconsts[i], 'neg', int(bigint.sign <= 0))
-                rffi.setintfield(nintconsts[i], 'value', ullvalue)
-        ffi.ctxobj.ctx.c_globals = nglobs
-        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_globals', n)
-
-    # ...
-
-
 class W_DlOpenLibObject(W_LibObject):
 
     def __init__(self, ffi, filename, flags):
@@ -142,3 +57,150 @@
         if dlclose(libhandle) < 0:
             raise oefmt(self.ffi.w_FFIError, "error closing library '%s'",
                         self.libname)
+
+
+class StringDecoder:
+    def __init__(self, ffi, string):
+        self.ffi = ffi
+        self.string = string
+        self.pos = 0
+
+    def next_4bytes(self):
+        pos = self.pos
+        src = ord(self.string[pos])
+        if src >= 0x80:
+            src -= 0x100
+        src = ((src << 24) |
+               (ord(self.string[pos + 1]) << 16) |
+               (ord(self.string[pos + 2]) << 8 ) |
+               (ord(self.string[pos + 3])      ))
+        self.pos = pos + 4
+        return src
+
+    def next_opcode(self):
+        return rffi.cast(_CFFI_OPCODE_T, self.next_4bytes())
+
+    def next_name(self):
+        frm = self.pos
+        i = self.string.find('\x00', frm)
+        if i < 0:
+            i = len(self.string)
+        pos = i + 1
+        p = rffi.str2charp(self.string[frm : i])
+        self.ffi._finalizer.free_mems.append(p)
+        return p
+
+
+def allocate(ffi, nbytes):
+    nbytes = llmemory.raw_malloc_usage(nbytes)
+    p = lltype.malloc(rffi.CCHARP.TO, nbytes, flavor='raw', zero=True)
+    ffi._finalizer.free_mems.append(p)
+    return p
+
[email protected](1)
+def allocate_array(ffi, OF, nitems):
+    nbytes = llmemory.raw_malloc_usage(rffi.sizeof(OF))
+    if not we_are_translated():
+        nbytes *= 2   # hack to account for the fact that raw_malloc_usage()
+                      # returns an approximation, ignoring padding and 
alignment
+    p = allocate(ffi, nitems * nbytes)
+    return rffi.cast(rffi.CArrayPtr(OF), p)
+
+
+def ffiobj_init(ffi, module_name, version, types, w_globals,
+                w_struct_unions, w_enums, w_typenames, w_includes):
+    space = ffi.space
+
+    # xxx force ll2ctypes conversion here.  This appears to be needed,
+    # otherwise ll2ctypes explodes.  I don't want to know :-(
+    rffi.cast(lltype.Signed, ffi.ctxobj)
+
+    if types:
+        # unpack a string of 4-byte entries into an array of _cffi_opcode_t
+        n = len(types) // 4
+        ntypes = allocate_array(ffi, _CFFI_OPCODE_T, n)
+        decoder = StringDecoder(ffi, types)
+        for i in range(n):
+            ntypes[i] = decoder.next_opcode()
+        ffi.ctxobj.ctx.c_types = ntypes
+        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_types', n)
+        ffi.cached_types = [None] * n
+
+    if w_globals is not None:
+        # unpack a tuple alternating strings and ints, each two together
+        # describing one global_s entry with no specified address or size.
+        # The int is only used with integer constants.
+        globals_w = space.fixedview(w_globals)
+        n = len(globals_w) // 2
+        size = n * rffi.sizeof(GLOBAL_S) + n * rffi.sizeof(CDL_INTCONST_S)
+        p = allocate(ffi, size)
+        nglobs = rffi.cast(rffi.CArrayPtr(GLOBAL_S), p)
+        p = rffi.ptradd(p, llmemory.raw_malloc_usage(n * 
rffi.sizeof(GLOBAL_S)))
+        nintconsts = rffi.cast(rffi.CArrayPtr(CDL_INTCONST_S), p)
+        for i in range(n):
+            decoder = StringDecoder(ffi, space.str_w(globals_w[i * 2]))
+            nglobs[i].c_type_op = decoder.next_opcode()
+            nglobs[i].c_name = decoder.next_name()
+            op = getop(nglobs[i].c_type_op)
+            if op == cffi_opcode.OP_CONSTANT_INT or op == cffi_opcode.OP_ENUM:
+                w_integer = globals_w[i * 2 + 1]
+                ll_set_cdl_realize_global_int(nglobs[i])
+                bigint = space.bigint_w(w_integer)
+                ullvalue = bigint.ulonglongmask()
+                rffi.setintfield(nintconsts[i], 'neg', int(bigint.sign <= 0))
+                rffi.setintfield(nintconsts[i], 'value', ullvalue)
+        ffi.ctxobj.ctx.c_globals = nglobs
+        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_globals', n)
+
+    if w_struct_unions is not None:
+        # unpack a tuple of struct/unions, each described as a sub-tuple;
+        # the item 0 of each sub-tuple describes the struct/union, and
+        # the items 1..N-1 describe the fields, if any
+        struct_unions_w = space.fixedview(w_struct_unions)
+        n = len(struct_unions_w)
+        nftot = 0     # total number of fields
+        for i in range(n):
+            nftot += space.len_w(struct_unions_w[i]) - 1
+        nstructs = allocate_array(ffi, STRUCT_UNION_S, n)
+        nfields = allocate_array(ffi, FIELD_S, nftot)
+        nf = 0
+        for i in range(n):
+            # 'desc' is the tuple of strings (desc_struct, desc_field_1, ..)
+            desc = space.fixedview(struct_unions_w[i])
+            nf1 = len(desc) - 1
+            decoder = StringDecoder(ffi, space.str_w(desc[0]))
+            rffi.setintfield(nstructs[i], 'c_type_index', 
decoder.next_4bytes())
+            flags = decoder.next_4bytes()
+            rffi.setintfield(nstructs[i], 'c_flags', flags)
+            nstructs[i].c_name = decoder.next_name()
+            if flags & (cffi_opcode.F_OPAQUE | cffi_opcode.F_EXTERNAL):
+                rffi.setintfield(nstructs[i], 'c_size', -1)
+                rffi.setintfield(nstructs[i], 'c_alignment', -1)
+                rffi.setintfield(nstructs[i], 'c_first_field_index', -1)
+                rffi.setintfield(nstructs[i], 'c_num_fields', 0)
+                assert nf1 == 0
+            else:
+                rffi.setintfield(nstructs[i], 'c_size', -2)
+                rffi.setintfield(nstructs[i], 'c_alignment', -2)
+                rffi.setintfield(nstructs[i], 'c_first_field_index', nf)
+                rffi.setintfield(nstructs[i], 'c_num_fields', nf1)
+            for j in range(nf1):
+                decoder = StringDecoder(ffi, space.str_w(desc[j + 1]))
+                # this 'decoder' is for one of the other strings beyond
+                # the first one, describing one field each
+                type_op = decoder.next_opcode()
+                nfields[nf].c_field_type_op = type_op
+                rffi.setintfield(nfields[nf], 'c_field_offset', -1)
+                if getop(type_op) != cffi_opcode.OP_NOOP:
+                    field_size = decoder.next_4bytes()
+                else:
+                    field_size = -1
+                rffi.setintfield(nfields[nf], 'c_field_size', field_size)
+                nfields[nf].c_name = decoder.next_name()
+                nf += 1
+        assert nf == nftot
+        ffi.ctxobj.ctx.c_struct_unions = nstructs
+        ffi.ctxobj.ctx.c_fields = nfields
+        rffi.setintfield(ffi.ctxobj.ctx, 'c_num_struct_unions', n)
+
+    # ... XXXX
diff --git a/pypy/module/_cffi_backend/ffi_obj.py 
b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -34,9 +34,13 @@
         self.free_mems = []       # filled from cdlopen.py
     @rgc.must_be_light_finalizer
     def __del__(self):
-        parse_c_type.free_ctxobj(self.ctxobj)
-        for p in self.free_mems:
-            lltype.free(p, flavor='raw')
+        ctxobj = self.ctxobj
+        free_mems = self.free_mems
+        parse_c_type.free_ctxobj(ctxobj)
+        i = len(free_mems) - 1
+        while i >= 0:
+            lltype.free(free_mems[i], flavor='raw')
+            i -= 1
 
 
 class W_FFIObject(W_Root):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to