[pypy-commit] cffi cffi-1.0: enums, integer constants

arigo noreply at buildbot.pypy.org
Mon May 11 19:29:52 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1977:f3745cfa00a0
Date: 2015-05-11 19:30 +0200
http://bitbucket.org/cffi/cffi/changeset/f3745cfa00a0/

Log:	enums, integer constants

diff --git a/_cffi1/cdlopen.c b/_cffi1/cdlopen.c
--- a/_cffi1/cdlopen.c
+++ b/_cffi1/cdlopen.c
@@ -95,15 +95,38 @@
 }
 
 
-static int cdl_int(char *src)
+static Py_ssize_t cdl_4bytes(char *src)
 {
+    /* read 4 bytes in little-endian order; return it as a signed integer */
+    signed char *ssrc = (signed char *)src;
     unsigned char *usrc = (unsigned char *)src;
-    return (usrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3];
+    return (ssrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3];
 }
 
 static _cffi_opcode_t cdl_opcode(char *src)
 {
-    return (_cffi_opcode_t)(Py_ssize_t)cdl_int(src);
+    return (_cffi_opcode_t)cdl_4bytes(src);
+}
+
+typedef struct {
+    unsigned long long value;
+    int neg;
+} cdl_intconst_t;
+
+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;
 }
 
 static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds)
@@ -111,18 +134,19 @@
     FFIObject *ffi;
     static char *keywords[] = {"module_name", "_version", "_types",
                                "_globals", "_struct_unions", "_enums",
-                               "_typenames", "_consts", NULL};
+                               "_typenames", NULL};
     char *ffiname = NULL, *types = NULL, *building = NULL;
     Py_ssize_t version = -1;
     Py_ssize_t types_len = 0;
     PyObject *globals = NULL, *struct_unions = NULL, *enums = NULL;
-    PyObject *typenames = NULL, *consts = NULL;
+    PyObject *typenames = NULL;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sns#O!OOOO:FFI", keywords,
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sns#O!O!O!O!:FFI", keywords,
                                      &ffiname, &version, &types, &types_len,
                                      &PyTuple_Type, &globals,
-                                     &struct_unions, &enums,
-                                     &typenames, &consts))
+                                     &PyTuple_Type, &struct_unions,
+                                     &PyTuple_Type, &enums,
+                                     &PyTuple_Type, &typenames))
         return -1;
 
     ffi = (FFIObject *)self;
@@ -153,22 +177,41 @@
     }
 
     if (globals != NULL) {
-        /* unpack a tuple of strings, each of which describes one global_s
-           entry with no specified address or size */
+        /* 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. */
         struct _cffi_global_s *nglobs;
-        Py_ssize_t i, n = PyTuple_GET_SIZE(globals);
+        cdl_intconst_t *nintconsts;
+        Py_ssize_t i, n = PyTuple_GET_SIZE(globals) / 2;
 
-        i = n * sizeof(struct _cffi_global_s);
+        i = n * (sizeof(struct _cffi_global_s) + sizeof(cdl_intconst_t));
         building = PyMem_Malloc(i);
         if (building == NULL)
             goto error;
         memset(building, 0, i);
         nglobs = (struct _cffi_global_s *)building;
+        nintconsts = (cdl_intconst_t *)(nglobs + n);
 
         for (i = 0; i < n; i++) {
-            char *g = PyString_AS_STRING(PyTuple_GET_ITEM(globals, i));
-            nglobs[i].type_op = cdl_opcode(g);
-            nglobs[i].name = g + 4;
+            char *g = PyString_AS_STRING(PyTuple_GET_ITEM(globals, i * 2));
+            nglobs[i].type_op = cdl_opcode(g); g += 4;
+            nglobs[i].name = g;
+            if (_CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_CONSTANT_INT ||
+                _CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_ENUM) {
+                PyObject *o = PyTuple_GET_ITEM(globals, i * 2 + 1);
+                nglobs[i].address = &_cdl_realize_global_int;
+                if (PyInt_Check(o)) {
+                    nintconsts[i].neg = PyInt_AS_LONG(o) <= 0;
+                    nintconsts[i].value = (long long)PyInt_AS_LONG(o);
+                }
+                else {
+                    nintconsts[i].neg = PyObject_RichCompareBool(o, Py_False,
+                                                                 Py_LE);
+                    nintconsts[i].value = PyLong_AsUnsignedLongLongMask(o);
+                    if (PyErr_Occurred())
+                        goto error;
+                }
+            }
         }
         ffi->types_builder.ctx.globals = nglobs;
         ffi->types_builder.ctx.num_globals = n;
@@ -203,9 +246,9 @@
             Py_ssize_t j, nf1 = PyTuple_GET_SIZE(desc) - 1;
             char *s = PyString_AS_STRING(PyTuple_GET_ITEM(desc, 0));
             /* 's' is the first string, describing the struct/union */
-            nstructs[i].type_index = cdl_int(s);
-            nstructs[i].flags = cdl_int(s + 4);
-            nstructs[i].name = s + 8;
+            nstructs[i].type_index = cdl_4bytes(s); s += 4;
+            nstructs[i].flags = cdl_4bytes(s); s += 4;
+            nstructs[i].name = s;
             if (nstructs[i].flags & _CFFI_F_OPAQUE) {
                 nstructs[i].size = (size_t)-1;
                 nstructs[i].alignment = -1;
@@ -223,11 +266,10 @@
                 char *f = PyString_AS_STRING(PyTuple_GET_ITEM(desc, j + 1));
                 /* 'f' is one of the other strings beyond the first one,
                    describing one field each */
-                nfields[nf].field_type_op = cdl_opcode(f);
-                nfields[nf].name = f + 4;
+                nfields[nf].field_type_op = cdl_opcode(f); f += 4;
                 nfields[nf].field_offset = (size_t)-1;
-                nfields[nf].field_size = (size_t)-1;
-                /* XXXXXXXXXXX BITFIELD MISSING XXXXXXXXXXXXXXXX */
+                nfields[nf].field_size = cdl_4bytes(f); f += 4;
+                nfields[nf].name = f;
                 nf++;
             }
         }
@@ -237,9 +279,30 @@
         building = NULL;
     }
 
-    if (consts != NULL) {
-        Py_INCREF(consts);
-        ffi->types_builder.known_constants = consts;
+    if (enums != NULL) {
+        /* unpack a tuple of strings, each of which describes one enum_s
+           entry */
+        struct _cffi_enum_s *nenums;
+        Py_ssize_t i, n = PyTuple_GET_SIZE(enums);
+
+        i = n * sizeof(struct _cffi_enum_s);
+        building = PyMem_Malloc(i);
+        if (building == NULL)
+            goto error;
+        memset(building, 0, i);
+        nenums = (struct _cffi_enum_s *)building;
+
+        for (i = 0; i < n; i++) {
+            char *e = PyString_AS_STRING(PyTuple_GET_ITEM(enums, i));
+            /* 'e' is a string describing the enum */
+            nenums[i].type_index = cdl_4bytes(e); e += 4;
+            nenums[i].type_prim = cdl_4bytes(e); e += 4;
+            nenums[i].name = e; e += strlen(e) + 1;
+            nenums[i].enumerators = e;
+        }
+        ffi->types_builder.ctx.enums = nenums;
+        ffi->types_builder.ctx.num_enums = n;
+        building = NULL;
     }
 
     /* Above, we took directly some "char *" strings out of the strings,
diff --git a/_cffi1/lib_obj.c b/_cffi1/lib_obj.c
--- a/_cffi1/lib_obj.c
+++ b/_cffi1/lib_obj.c
@@ -166,14 +166,6 @@
     index = search_in_globals(&lib->l_types_builder->ctx, s, strlen(s));
     if (index < 0) {
 
-        if (lib->l_types_builder->known_constants != NULL) {
-            x = PyDict_GetItem(lib->l_types_builder->known_constants, name);
-            if (x != NULL) {
-                Py_INCREF(x);
-                goto found;
-            }
-        }
-
         if (lib->l_includes != NULL) {
             Py_ssize_t i;
 
@@ -232,7 +224,7 @@
     {
         /* a constant integer whose value, in an "unsigned long long",
            is obtained by calling the function at g->address */
-        x = realize_global_int(g);
+        x = realize_global_int(lib->l_types_builder, index);
         break;
     }
 
diff --git a/_cffi1/manual2.py b/_cffi1/manual2.py
--- a/_cffi1/manual2.py
+++ b/_cffi1/manual2.py
@@ -3,11 +3,10 @@
 ffi = _cffi_backend.FFI(b"manual2",
     _version = 0x2600,
     _types = b'\x00\x00\x01\x0D\x00\x00\x07\x01\x00\x00\x00\x0F\x00\x00\x00\x09\x00\x00\x00\x0B\x00\x00\x01\x03',
-    _globals = (b'\x00\x00\x00#close',b'\x00\x00\x05#stdout'),
-    _struct_unions = ((b'\x00\x00\x00\x03\x00\x00\x00\x00point_s',b'\x00\x00\x01\x11x',b'\x00\x00\x01\x11y'),),
-    _enums = (b'\x00\x00\x00\x04\x00\x00\x00\x01myenum_e\x00AA,BB,CC',),
+    _globals = (b'\xff\xff\xff\x0bAA',0,b'\xff\xff\xff\x0bBB',1,b'\xff\xff\xff\x0bCC',2,b'\x00\x00\x00\x1fFOO',-42,b'\x00\x00\x00#close',0,b'\x00\x00\x05#stdout',0),
+    _struct_unions = ((b'\x00\x00\x00\x03\x00\x00\x00\x00point_s',b'\x00\x00\x01\x11\xff\xff\xff\xffx',b'\x00\x00\x01\x11\xff\xff\xff\xffy'),),
+    _enums = (b'\x00\x00\x00\x04\x00\x00\x00\x07myenum_e\x00AA,BB,CC',),
     _typenames = (b'\x00\x00\x00\x01myint_t',),
-    _consts = {'AA':0,'BB':1,'CC':2},
 )
 
 
@@ -15,6 +14,7 @@
 # trying it out
 lib = ffi.dlopen(None)
 assert lib.BB == 1
+assert lib.FOO == -42
 x = lib.close(-42)
 assert x == -1
 
@@ -24,4 +24,6 @@
 print ffi.offsetof("struct point_s", "x")
 print ffi.offsetof("struct point_s", "y")
 
-del ffi
+print ffi.cast("enum myenum_e", 2)
+
+del ffi, lib
diff --git a/_cffi1/parse_c_type.c b/_cffi1/parse_c_type.c
--- a/_cffi1/parse_c_type.c
+++ b/_cffi1/parse_c_type.c
@@ -370,16 +370,21 @@
                     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)
+                        struct _cffi_getconst_s gc;
+                        gc.ctx = tok->info->ctx;
+                        gc.gindex = gindex;
+                        int 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 */
diff --git a/_cffi1/parse_c_type.h b/_cffi1/parse_c_type.h
--- a/_cffi1/parse_c_type.h
+++ b/_cffi1/parse_c_type.h
@@ -84,6 +84,12 @@
     size_t size;             // 0 if unknown
 };
 
+struct _cffi_getconst_s {
+    unsigned long long value;
+    const struct _cffi_type_context_s *ctx;
+    int gindex;
+};
+
 struct _cffi_struct_union_s {
     const char *name;
     int type_index;          // -> _cffi_types, on a OP_STRUCT_UNION
diff --git a/_cffi1/realize_c_type.c b/_cffi1/realize_c_type.c
--- a/_cffi1/realize_c_type.c
+++ b/_cffi1/realize_c_type.c
@@ -3,7 +3,6 @@
     struct _cffi_type_context_s ctx;   /* inlined substructure */
     PyObject *types_dict;
     PyObject *included_ffis;
-    PyObject *known_constants;
     PyObject *_keepalive1;
     PyObject *_keepalive2;
 } builder_c_t;
@@ -73,7 +72,6 @@
     }
     Py_XDECREF(builder->included_ffis);
     Py_XDECREF(builder->types_dict);
-    Py_XDECREF(builder->known_constants);
     Py_XDECREF(builder->_keepalive1);
     Py_XDECREF(builder->_keepalive2);
 }
@@ -92,7 +90,6 @@
 
     builder->types_dict = ldict;
     builder->included_ffis = NULL;
-    builder->known_constants = NULL;
     builder->_keepalive1 = NULL;
     builder->_keepalive2 = NULL;
     return 0;
@@ -170,13 +167,22 @@
     return x;
 }
 
-static PyObject *realize_global_int(const struct _cffi_global_s *g)
+static PyObject *realize_global_int(builder_c_t *builder, int gindex)
 {
+    int neg;
     char got[64];
     unsigned long long value;
+    struct _cffi_getconst_s gc;
+    const struct _cffi_global_s *g = &builder->ctx.globals[gindex];
+    gc.ctx = &builder->ctx;
+    gc.gindex = gindex;
     /* note: we cast g->address to this function type; we do the same
-       in parse_c_type:parse_sequel() too */
-    int neg = ((int(*)(unsigned long long*))g->address)(&value);
+       in parse_c_type:parse_sequel() too.  Note that the called function
+       may be declared simply with "unsigned long long *" as argument,
+       which is fine as it is the first field in _cffi_getconst_s. */
+    assert(&gc.value == (unsigned long long *)&gc);
+    neg = ((int(*)(struct _cffi_getconst_s *))g->address)(&gc);
+    value = gc.value;
 
     switch (neg) {
 
@@ -440,7 +446,6 @@
             PyObject *enumerators = NULL, *enumvalues = NULL, *tmp;
             Py_ssize_t i, j, n = 0;
             const char *p;
-            const struct _cffi_global_s *g;
             int gindex;
             PyObject *args;
             PyObject *basetd = get_primitive_type(e->type_prim);
@@ -474,10 +479,10 @@
 
                 gindex = search_in_globals(&builder->ctx, p, j);
                 assert(gindex >= 0);
-                g = &builder->ctx.globals[gindex];
-                assert(g->type_op == _CFFI_OP(_CFFI_OP_ENUM, -1));
+                assert(builder->ctx.globals[gindex].type_op ==
+                       _CFFI_OP(_CFFI_OP_ENUM, -1));
 
-                tmp = realize_global_int(g);
+                tmp = realize_global_int(builder, gindex);
                 if (tmp == NULL)
                     break;
                 PyTuple_SET_ITEM(enumvalues, i, tmp);


More information about the pypy-commit mailing list