Author: Armin Rigo <ar...@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); _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit