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