[pypy-commit] pypy cffi-1.0: in-progress
arigo
noreply at buildbot.pypy.org
Sun May 17 19:30:59 CEST 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r77355:95596772fe0c
Date: 2015-05-17 19:31 +0200
http://bitbucket.org/pypy/pypy/changeset/95596772fe0c/
Log: in-progress
diff --git a/pypy/module/_cffi_backend/cdlopen.py b/pypy/module/_cffi_backend/cdlopen.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/cdlopen.py
@@ -0,0 +1,93 @@
+from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
+from rpython.rlib.objectmodel import specialize
+
+from pypy.module._cffi_backend.parse_c_type import (
+ _CFFI_OPCODE_T, GLOBAL_S, CDL_INTCONST_S,
+ ll_set_cdl_realize_global_int)
+from pypy.module._cffi_backend.realize_c_type import getop
+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
+
+ at specialize.arg(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)
+
+ # ...
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
@@ -4,13 +4,14 @@
from pypy.interpreter.typedef import TypeDef, GetSetProperty, ClassAttr
from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
from rpython.rlib import jit, rgc
-from rpython.rtyper.lltypesystem import rffi
+from rpython.rtyper.lltypesystem import lltype, rffi
from pypy.module._cffi_backend import get_dict_rtld_constants
from pypy.module._cffi_backend import parse_c_type, realize_c_type
from pypy.module._cffi_backend import newtype, cerrno, ccallback, ctypearray
from pypy.module._cffi_backend import ctypestruct, ctypeptr, handle
from pypy.module._cffi_backend import cbuffer, func, cgc, structwrapper
+from pypy.module._cffi_backend import cffi_opcode
from pypy.module._cffi_backend.ctypeobj import W_CType
from pypy.module._cffi_backend.cdataobj import W_CData
@@ -30,9 +31,12 @@
class FreeCtxObj(object):
def __init__(self, ctxobj):
self.ctxobj = ctxobj
+ 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')
class W_FFIObject(W_Root):
@@ -43,14 +47,36 @@
self.space = space
self.types_dict = {}
self.ctxobj = parse_c_type.allocate_ctxobj(src_ctx)
+ self.is_static = bool(src_ctx)
+ self.is_nonempty = bool(src_ctx)
self._finalizer = FreeCtxObj(self.ctxobj)
if src_ctx:
self.cached_types = [None] * parse_c_type.get_num_types(src_ctx)
else:
self.cached_types = None
self.w_FFIError = get_ffi_error(space)
+ self.included_ffis = [] # list of W_FFIObject's included here
self.included_libs = [] # list of W_LibObject's included here
+ def fetch_int_constant(self, name):
+ index = parse_c_type.search_in_globals(self.ctxobj.ctx, name)
+ if index >= 0:
+ g = self.ctxobj.ctx.c_globals[index]
+ op = realize_c_type.getop(g.c_type_op)
+ if (op == cffi_opcode.OP_CONSTANT_INT or
+ op == cffi_opcode.OP_ENUM):
+ return realize_c_type.realize_global_int(self, g, index)
+ raise oefmt(self.w_FFIError,
+ "function, global variable or non-integer constant "
+ "'%s' must be fetched from its original 'lib' "
+ "object", name)
+
+ for ffi1 in self.included_ffis:
+ w_result = ffi1.ffi_fetch_int_constant(name)
+ if w_result is not None:
+ return w_result
+ return None
+
@jit.elidable_promote()
def get_string_to_type(self, string, consider_fn_as_fnptr):
x = self.types_dict[string] # KeyError if not found
@@ -123,8 +149,21 @@
m1, s12, m2, s23, m3, w_x)
- def descr_init(self):
- pass # if any argument is passed, gets a TypeError
+ @unwrap_spec(module_name=str, _version=int, _types=str)
+ def descr_init(self, module_name=None, _version=-1, _types=None,
+ w__globals=None, w__struct_unions=None, w__enums=None,
+ w__typenames=None, w__includes=None):
+ from pypy.module._cffi_backend import cdlopen
+ #
+ space = self.space
+ if self.is_nonempty:
+ raise oefmt(space.w_ValueError,
+ "cannot call FFI.__init__() more than once")
+ self.is_nonempty = True
+ #
+ cdlopen.ffiobj_init(self, module_name, _version, _types,
+ w__globals, w__struct_unions, w__enums,
+ w__typenames, w__includes)
doc_errno = "the value of 'errno' from/to the C calls"
@@ -316,6 +355,7 @@
if add_paren:
result += ')'
result += w_ctype.name[w_ctype.name_position:]
+ # Python 3: bytes -> unicode string
return self.space.wrap(result)
@@ -437,6 +477,22 @@
return self.ffi_type(w_arg, ACCEPT_STRING | ACCEPT_CDATA)
+ @unwrap_spec(name=str)
+ def descr_integer_const(self, name):
+ """\
+Get the value of an integer constant.
+
+'ffi.integer_const(\"xxx\")' is equivalent to 'lib.xxx' if xxx names an
+integer constant. The point of this function is limited to use cases
+where you have an 'ffi' object but not any associated 'lib' object."""
+ #
+ w_result = self.fetch_int_constant(name)
+ if w_result is None:
+ raise oefmt(self.space.w_AttributeError,
+ "integer constant '%s' not found", name)
+ return w_result
+
+
@jit.dont_look_inside
def W_FFIObject___new__(space, w_subtype, __args__):
r = space.allocate_instance(W_FFIObject, w_subtype)
@@ -487,6 +543,7 @@
from_handle = interp2app(W_FFIObject.descr_from_handle),
gc = interp2app(W_FFIObject.descr_gc),
getctype = interp2app(W_FFIObject.descr_getctype),
+ integer_const = interp2app(W_FFIObject.descr_integer_const),
new = interp2app(W_FFIObject.descr_new),
new_handle = interp2app(W_FFIObject.descr_new_handle),
offsetof = interp2app(W_FFIObject.descr_offsetof),
diff --git a/pypy/module/_cffi_backend/lib_obj.py b/pypy/module/_cffi_backend/lib_obj.py
--- a/pypy/module/_cffi_backend/lib_obj.py
+++ b/pypy/module/_cffi_backend/lib_obj.py
@@ -120,6 +120,7 @@
fetch_funcptr = rffi.cast(
realize_c_type.FUNCPTR_FETCH_CHARP,
g.c_address)
+ xxxxxxxxxxxxxxxxxxxx
assert w_ct.size > 0
with lltype.scoped_alloc(rffi.CCHARP.TO, w_ct.size) as ptr:
fetch_funcptr(ptr)
diff --git a/pypy/module/_cffi_backend/parse_c_type.py b/pypy/module/_cffi_backend/parse_c_type.py
--- a/pypy/module/_cffi_backend/parse_c_type.py
+++ b/pypy/module/_cffi_backend/parse_c_type.py
@@ -24,6 +24,9 @@
('address', rffi.VOIDP),
('type_op', _CFFI_OPCODE_T),
('size', rffi.SIZE_T))
+CDL_INTCONST_S = lltype.Struct('cdl_intconst_s',
+ ('value', rffi.ULONGLONG),
+ ('neg', rffi.INT))
STRUCT_UNION_S = rffi.CStruct('_cffi_struct_union_s',
('name', rffi.CCHARP),
('type_index', rffi.INT),
@@ -68,6 +71,11 @@
('error_location', rffi.SIZE_T),
('error_message', rffi.CCHARP))
+GETCONST_S = rffi.CStruct('_cffi_getconst_s',
+ ('value', rffi.ULONGLONG),
+ ('ctx', PCTX),
+ ('gindex', rffi.INT))
+
ll_parse_c_type = llexternal('pypy_parse_c_type', [PINFO, rffi.CCHARP],
rffi.INT)
ll_search_in_globals = llexternal('pypy_search_in_globals',
@@ -76,6 +84,9 @@
ll_search_in_struct_unions = llexternal('pypy_search_in_struct_unions',
[PCTX, rffi.CCHARP, rffi.SIZE_T],
rffi.INT)
+ll_set_cdl_realize_global_int = llexternal('pypy_set_cdl_realize_global_int',
+ [lltype.Ptr(GLOBAL_S)],
+ lltype.Void)
def parse_c_type(info, input):
p_input = rffi.str2charp(input)
diff --git a/pypy/module/_cffi_backend/realize_c_type.py b/pypy/module/_cffi_backend/realize_c_type.py
--- a/pypy/module/_cffi_backend/realize_c_type.py
+++ b/pypy/module/_cffi_backend/realize_c_type.py
@@ -92,13 +92,16 @@
FUNCPTR_FETCH_CHARP = lltype.Ptr(lltype.FuncType([rffi.CCHARP], lltype.Void))
-FUNCPTR_FETCH_LONGLONG = lltype.Ptr(lltype.FuncType([rffi.ULONGLONGP],
- rffi.INT))
-def realize_global_int(ffi, g):
+FUNCPTR_FETCH_LONGLONG = lltype.Ptr(lltype.FuncType(
+ [lltype.Ptr(parse_c_type.GETCONST_S)], rffi.INT))
+
+def realize_global_int(ffi, g, gindex):
fetch_fnptr = rffi.cast(FUNCPTR_FETCH_LONGLONG, g.c_address)
- with lltype.scoped_alloc(rffi.ULONGLONGP.TO, 1) as p_value:
+ with lltype.scoped_alloc(parse_c_type.GETCONST_S) as p_value:
+ p_value.c_ctx = ffi.ctxobj.ctx
+ rffi.setintfield(p_value, 'c_gindex', gindex)
neg = fetch_fnptr(p_value)
- value = p_value[0]
+ value = p_value.c_value
neg = rffi.cast(lltype.Signed, neg)
if neg == 0: # positive
@@ -312,7 +315,7 @@
assert getop(g.c_type_op) == cffi_opcode.OP_ENUM
assert getarg(g.c_type_op) == -1
- w_integer_value = realize_global_int(ffi, g)
+ w_integer_value = realize_global_int(ffi, g, gindex)
enumvalues_w.append(w_integer_value)
p = rffi.ptradd(p, j)
diff --git a/pypy/module/_cffi_backend/src/parse_c_type.c b/pypy/module/_cffi_backend/src/parse_c_type.c
--- a/pypy/module/_cffi_backend/src/parse_c_type.c
+++ b/pypy/module/_cffi_backend/src/parse_c_type.c
@@ -381,16 +381,22 @@
g = &tok->info->ctx->globals[gindex];
if (_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT_INT ||
_CFFI_GETOP(g->type_op) == _CFFI_OP_ENUM) {
- unsigned long long value;
- int neg = ((int(*)(unsigned long long*))g->address)
- (&value);
- if (!neg && value > MAX_SSIZE_T)
+ int neg;
+ struct _cffi_getconst_s gc;
+ gc.ctx = tok->info->ctx;
+ gc.gindex = gindex;
+ neg = ((int(*)(struct _cffi_getconst_s*))g->address)
+ (&gc);
+ if (neg == 0 && gc.value > MAX_SSIZE_T)
return parse_error(tok,
"integer constant too large");
- if (!neg || value == 0) {
- length = (size_t)value;
+ if (neg == 0 || gc.value == 0) {
+ length = (size_t)gc.value;
break;
}
+ if (neg != 1)
+ return parse_error(tok, "disagreement about"
+ " this constant's value");
}
}
/* fall-through to the default case */
@@ -763,3 +769,34 @@
return parse_error(&token, "unexpected symbol");
return result;
}
+
+
+/************************************************************/
+/* extra from cdlopen.c */
+
+typedef struct {
+ unsigned long long value;
+ int neg;
+} cdl_intconst_t;
+
+static int _cdl_realize_global_int(struct _cffi_getconst_s *gc)
+{
+ /* The 'address' field of 'struct _cffi_global_s' is set to point
+ to this function in case ffiobj_init() sees constant integers.
+ This fishes around after the 'ctx->globals' array, which is
+ initialized to contain another array, this time of
+ 'cdl_intconst_t' structures. We get the nth one and it tells
+ us what to return.
+ */
+ cdl_intconst_t *ic;
+ ic = (cdl_intconst_t *)(gc->ctx->globals + gc->ctx->num_globals);
+ ic += gc->gindex;
+ gc->value = ic->value;
+ return ic->neg;
+}
+
+RPY_EXTERN
+void pypy_set_cdl_realize_global_int(struct _cffi_global_s *target)
+{
+ target->address = (void *)_cdl_realize_global_int;
+}
diff --git a/pypy/module/_cffi_backend/src/parse_c_type.h b/pypy/module/_cffi_backend/src/parse_c_type.h
--- a/pypy/module/_cffi_backend/src/parse_c_type.h
+++ b/pypy/module/_cffi_backend/src/parse_c_type.h
@@ -161,4 +161,6 @@
RPY_EXTERN int
pypy_search_in_struct_unions(const struct _cffi_type_context_s *ctx,
const char *search, size_t search_len);
+RPY_EXTERN
+void pypy_set_cdl_realize_global_int(struct _cffi_global_s *target);
#endif
More information about the pypy-commit
mailing list