[pypy-commit] cffi cffi-1.0: Reimplement verify() as a hack that updates the old ffi object with

arigo noreply at buildbot.pypy.org
Thu Apr 16 09:36:46 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r1722:3758e99173fd
Date: 2015-04-16 09:17 +0200
http://bitbucket.org/cffi/cffi/changeset/3758e99173fd/

Log:	Reimplement verify() as a hack that updates the old ffi object with
	the ffi object from the extension module.

diff --git a/new/cffi1_module.c b/new/cffi1_module.c
--- a/new/cffi1_module.c
+++ b/new/cffi1_module.c
@@ -49,7 +49,7 @@
     if (m == NULL)
         return -1;
 
-    FFIObject *ffi = ffi_internal_new(NULL, ctx);
+    FFIObject *ffi = ffi_internal_new(&FFI_Type, ctx, 1);
     Py_XINCREF(ffi);    /* make the ffi object really immortal */
     if (ffi == NULL || PyModule_AddObject(m, "ffi", (PyObject *)ffi) < 0)
         return -1;
diff --git a/new/ffi_obj.c b/new/ffi_obj.c
--- a/new/ffi_obj.c
+++ b/new/ffi_obj.c
@@ -23,19 +23,21 @@
     PyObject *types_dict;
     PyObject *gc_wrefs;
     struct _cffi_parse_info_s info;
+    int ctx_is_static;
     _cffi_opcode_t internal_output[FFI_COMPLEXITY_OUTPUT];
 };
 
 static FFIObject *ffi_internal_new(PyTypeObject *ffitype,
-                                   const struct _cffi_type_context_s *ctx)
+                                   const struct _cffi_type_context_s *ctx,
+                                   int ctx_is_static)
 {
     PyObject *dict = PyDict_New();
     if (dict == NULL)
         return NULL;
 
     FFIObject *ffi;
-    if (ffitype == NULL) {
-        ffi = (FFIObject *)PyObject_New(FFIObject, &FFI_Type);
+    if (ctx_is_static) {
+        ffi = (FFIObject *)PyObject_New(FFIObject, ffitype);
         /* we don't call PyObject_GC_Track() here: from _cffi_init_module()
            it is not needed, because in this case the ffi object is immortal */
     }
@@ -51,6 +53,7 @@
     ffi->info.ctx = ctx;
     ffi->info.output = ffi->internal_output;
     ffi->info.output_size = FFI_COMPLEXITY_OUTPUT;
+    ffi->ctx_is_static = ctx_is_static;
     return ffi;
 }
 
@@ -60,7 +63,7 @@
     Py_DECREF(ffi->types_dict);
     Py_XDECREF(ffi->gc_wrefs);
 
-    {
+    if (!ffi->ctx_is_static) {
         const void *mem[] = {ffi->info.ctx->types,
                              ffi->info.ctx->globals,
                              ffi->info.ctx->constants,
@@ -98,7 +101,7 @@
     }
     memset(ctx, 0, sizeof(struct _cffi_type_context_s));
 
-    result = (PyObject *)ffi_internal_new(type, ctx);
+    result = (PyObject *)ffi_internal_new(type, ctx, 0);
     if (result == NULL) {
         PyMem_Free(ctx);
         return NULL;
@@ -516,7 +519,40 @@
 }
 #endif
 
+static PyObject *ffi__verified(FFIObject *self, PyObject *args)
+{
+    FFIObject *srcffi;
+
+    if (!PyArg_ParseTuple(args, "O!:_verified", &FFI_Type, &srcffi))
+        return NULL;
+
+    if (!srcffi->ctx_is_static)
+        goto invalid;
+
+    if (self->ctx_is_static)
+        goto invalid;
+
+    size_t i;
+    const char *p = (const char *)self->info.ctx;
+    for (i = 0; i < sizeof(struct _cffi_type_context_s); i++) {
+        if (*p++ != '\0')
+            goto invalid;
+    }
+
+    PyMem_Free((void *)self->info.ctx);
+    self->ctx_is_static = 1;
+    self->info.ctx = srcffi->info.ctx;
+
+    Py_INCREF(Py_None);
+    return Py_None;
+
+ invalid:
+    PyErr_SetString(PyExc_ValueError, "XXX invalid source or destination");
+    return NULL;
+}
+
 static PyMethodDef ffi_methods[] = {
+    {"_verified",     (PyCFunction)ffi__verified, METH_VARARGS},
 #if 0
     {"addressof",     (PyCFunction)ffi_addressof, METH_VARARGS},
     {"cast",          (PyCFunction)ffi_cast,      METH_VARARGS},
diff --git a/new/recompiler.py b/new/recompiler.py
--- a/new/recompiler.py
+++ b/new/recompiler.py
@@ -125,7 +125,7 @@
             nums[step_name] = len(lst)
             if nums[step_name] > 0:
                 lst.sort()  # sort by name, which is at the start of each line
-                prnt('static const struct _cffi_%s_s _cffi_%s[] = {' % (
+                prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % (
                     step_name, step_name))
                 for line in lst:
                     prnt(line)
@@ -408,10 +408,32 @@
             self.cffi_types[index] = CffiOp(OP_ARRAY, item_index)
             self.cffi_types[index + 1] = CffiOp(None, '%d' % (tp.length,))
 
-def make_c_source(ffi, target_c_file, preamble):
-    module_name, ext = os.path.splitext(os.path.basename(target_c_file))
-    assert ext, "no extension!"
+def make_c_source(ffi, module_name, preamble, target_c_file):
     recompiler = Recompiler(ffi, module_name)
     recompiler.collect_type_table()
     with open(target_c_file, 'w') as f:
         recompiler.write_source_to_f(f, preamble)
+
+def _get_extension(module_name, c_file, kwds):
+    source_name = ffiplatform.maybe_relative_path(c_file)
+    include_dirs = kwds.setdefault('include_dirs', [])
+    include_dirs.insert(0, '.')   # XXX
+    return ffiplatform.get_extension(source_name, module_name, **kwds)
+
+def recompile(ffi, module_name, preamble, tmpdir=None, **kwds):
+    if tmpdir is None:
+        tmpdir = 'build'
+        if not os.path.isdir(tmpdir):
+            os.mkdir(tmpdir)
+    c_file = os.path.join(tmpdir, module_name + '.c')
+    ext = _get_extension(module_name, c_file, kwds)
+    make_c_source(ffi, module_name, preamble, c_file)
+    outputfilename = ffiplatform.compile(tmpdir, ext)
+    return outputfilename
+
+def verify(ffi, module_name, preamble, *args, **kwds):
+    import imp
+    outputfilename = recompile(ffi, module_name, preamble, *args, **kwds)
+    module = imp.load_dynamic(module_name, outputfilename)
+    ffi._verified(module.ffi)
+    return module.lib
diff --git a/new/test_recompiler.py b/new/test_recompiler.py
--- a/new/test_recompiler.py
+++ b/new/test_recompiler.py
@@ -1,6 +1,5 @@
-from recompiler import Recompiler, make_c_source
+from recompiler import Recompiler, verify
 from cffi1 import FFI
-from udir import udir
 
 
 def check_type_table(input, expected_output):
@@ -62,16 +61,21 @@
 
 
 def test_math_sin():
+    import math
     ffi = FFI()
     ffi.cdef("float sin(double); double cos(double);")
-    make_c_source(ffi, str(udir.join('math_sin.c')), '#include <math.h>')
+    lib = verify(ffi, 'test_math_sin', '#include <math.h>')
+    assert lib.cos(1.43) == math.cos(1.43)
 
 def test_global_var_array():
     ffi = FFI()
     ffi.cdef("int a[100];")
-    make_c_source(ffi, str(udir.join('global_var_array.c')), 'int a[100];')
+    lib = verify(ffi, 'test_global_var_array', 'int a[100] = { 9999 };')
+    #lib.a[42] = 123456
+    #assert lib.a[42] == 123456
+    #assert lib.a[0] == 9999
 
 def test_typedef():
     ffi = FFI()
     ffi.cdef("typedef int **foo_t;")
-    make_c_source(ffi, str(udir.join('typedef.c')), 'typedef int **foo_t;')
+    lib = verify(ffi, 'test_typedef', 'typedef int **foo_t;')


More information about the pypy-commit mailing list