[pypy-commit] creflect default: move some code around and translate gc_weakrefs.py into C.
arigo
noreply at buildbot.pypy.org
Fri Dec 5 22:37:25 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r185:771ed4577187
Date: 2014-12-05 22:37 +0100
http://bitbucket.org/cffi/creflect/changeset/771ed4577187/
Log: move some code around and translate gc_weakrefs.py into C.
diff --git a/zeffir/cdata.c b/zeffir/cdata.c
--- a/zeffir/cdata.c
+++ b/zeffir/cdata.c
@@ -1708,3 +1708,197 @@
cd->c_weakreflist = NULL;
return cd;
}
+
+static int _my_PyObject_AsBool(PyObject *ob)
+{
+ /* convert and cast a Python object to a boolean. Accept an integer
+ or a float object, up to a CData 'long double'. */
+ PyObject *io;
+ PyNumberMethods *nb;
+ int res;
+
+#if PY_MAJOR_VERSION < 3
+ if (PyInt_Check(ob)) {
+ return PyInt_AS_LONG(ob) != 0;
+ }
+ else
+#endif
+ if (PyLong_Check(ob)) {
+ return _PyLong_Sign(ob) != 0;
+ }
+ else if (PyFloat_Check(ob)) {
+ return PyFloat_AS_DOUBLE(ob) != 0.0;
+ }
+ else if (CData_Check(ob)) {
+ CDataObject *cd = (CDataObject *)ob;
+ if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) {
+ /*READ(cd->c_data, cd->c_type->ct_size)*/
+ if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) {
+ /* 'long double' objects: return the answer directly */
+ return read_raw_longdouble_data(cd->c_data) != 0.0;
+ }
+ else {
+ /* 'float'/'double' objects: return the answer directly */
+ return read_raw_float_data(cd->c_data,
+ cd->c_type->ct_size) != 0.0;
+ }
+ }
+ }
+ nb = ob->ob_type->tp_as_number;
+ if (nb == NULL || (nb->nb_float == NULL && nb->nb_int == NULL)) {
+ PyErr_SetString(PyExc_TypeError, "integer/float expected");
+ return -1;
+ }
+ if (nb->nb_float && !CData_Check(ob))
+ io = (*nb->nb_float) (ob);
+ else
+ io = (*nb->nb_int) (ob);
+ if (io == NULL)
+ return -1;
+
+ if (PyIntOrLong_Check(io) || PyFloat_Check(io)) {
+ res = _my_PyObject_AsBool(io);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "integer/float conversion failed");
+ res = -1;
+ }
+ Py_DECREF(io);
+ return res;
+}
+
+static CDataObject *cast_to_integer_or_char(CTypeDescrObject *ct, PyObject *ob)
+{
+ unsigned PY_LONG_LONG value;
+ CDataObject *cd;
+
+ if (CData_Check(ob) &&
+ ((CDataObject *)ob)->c_type->ct_flags & (CT_POINTER | CT_ARRAY)) {
+ value = (Py_intptr_t)((CDataObject *)ob)->c_data;
+ }
+ else if (PyString_Check(ob)) {
+ if (PyString_GET_SIZE(ob) != 1) {
+ PyErr_Format(PyExc_TypeError,
+ "cannot cast string of length %zd to ctype '%s'",
+ PyString_GET_SIZE(ob), ct->ct_name);
+ return NULL;
+ }
+ value = (unsigned char)PyString_AS_STRING(ob)[0];
+ }
+ else if (ct->ct_flags & CT_IS_BOOL) {
+ int res = _my_PyObject_AsBool(ob);
+ if (res < 0)
+ return NULL;
+ value = res;
+ }
+ else {
+ value = _my_PyLong_AsUnsignedLongLong(ob, 0);
+ if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
+ return NULL;
+ }
+ if (ct->ct_flags & CT_IS_BOOL)
+ value = !!value;
+ cd = _new_casted_primitive(ct);
+ if (cd != NULL)
+ write_raw_integer_data(cd->c_data, value, ct->ct_size);
+ return cd;
+}
+
+static PyObject *do_cast(CTypeDescrObject *ct, PyObject *ob)
+{
+ CDataObject *cd;
+
+ if (ct->ct_flags & (CT_POINTER | CT_ARRAY) &&
+ ct->ct_size >= 0) {
+ /* cast to a pointer or to an array.
+ Note that casting to an array is an extension to the C language,
+ which seems to be necessary in order to sanely get a
+ <cdata 'int[3]'> at some address. */
+ unsigned PY_LONG_LONG value;
+
+ if (CData_Check(ob)) {
+ CDataObject *cdsrc = (CDataObject *)ob;
+ if (cdsrc->c_type->ct_flags & (CT_POINTER | CT_ARRAY)) {
+ return new_simple_cdata(cdsrc->c_data, ct);
+ }
+ }
+ value = _my_PyLong_AsUnsignedLongLong(ob, 0);
+ if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
+ return NULL;
+ return new_simple_cdata((char *)(Py_intptr_t)value, ct);
+ }
+ else if (ct->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED
+ |CT_PRIMITIVE_CHAR)) {
+ /* cast to an integer type or a char */
+ return (PyObject *)cast_to_integer_or_char(ct, ob);
+ }
+ else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) {
+ /* cast to a float */
+ double value;
+ PyObject *io;
+
+ if (CData_Check(ob)) {
+ CDataObject *cdsrc = (CDataObject *)ob;
+
+ if (!(cdsrc->c_type->ct_flags & CT_PRIMITIVE_ANY))
+ goto cannot_cast;
+ io = convert_to_object(cdsrc->c_data, cdsrc->c_type);
+ if (io == NULL)
+ return NULL;
+ }
+ else {
+ io = ob;
+ Py_INCREF(io);
+ }
+
+ if (PyBytes_Check(io)) {
+ if (PyBytes_GET_SIZE(io) != 1) {
+ Py_DECREF(io);
+ goto cannot_cast;
+ }
+ value = (unsigned char)PyBytes_AS_STRING(io)[0];
+ }
+ else if ((ct->ct_flags & CT_IS_LONGDOUBLE) &&
+ CData_Check(io) &&
+ (((CDataObject *)io)->c_type->ct_flags & CT_IS_LONGDOUBLE)) {
+ long double lvalue;
+ char *data = ((CDataObject *)io)->c_data;
+ /*READ(data, sizeof(long double)*/
+ lvalue = read_raw_longdouble_data(data);
+ cd = _new_casted_primitive(ct);
+ if (cd != NULL)
+ write_raw_longdouble_data(cd->c_data, lvalue);
+ return (PyObject *)cd;
+ }
+ else {
+ value = PyFloat_AsDouble(io);
+ }
+ Py_DECREF(io);
+ if (value == -1.0 && PyErr_Occurred())
+ return NULL;
+
+ cd = _new_casted_primitive(ct);
+ if (cd != NULL) {
+ if (!(ct->ct_flags & CT_IS_LONGDOUBLE))
+ write_raw_float_data(cd->c_data, value, ct->ct_size);
+ else
+ write_raw_longdouble_data(cd->c_data, (long double)value);
+ }
+ return (PyObject *)cd;
+ }
+ else {
+ PyErr_Format(PyExc_TypeError, "cannot cast to ctype '%s'",
+ ct->ct_name);
+ return NULL;
+ }
+
+ cannot_cast:
+ if (CData_Check(ob))
+ PyErr_Format(PyExc_TypeError, "cannot cast ctype '%s' to ctype '%s'",
+ ((CDataObject *)ob)->c_type->ct_name, ct->ct_name);
+ else
+ PyErr_Format(PyExc_TypeError,
+ "cannot cast %.200s object to ctype '%s'",
+ Py_TYPE(ob)->tp_name, ct->ct_name);
+ return NULL;
+}
diff --git a/zeffir/cgc.c b/zeffir/cgc.c
new file mode 100644
--- /dev/null
+++ b/zeffir/cgc.c
@@ -0,0 +1,86 @@
+
+/* translated to C from cffi/gc_weakref.py */
+
+
+#define GCWREF_DATA(ffi) ((ffi)->gc_wrefs[0])
+#define GCWREF_CALLBACK(ffi) ((ffi)->gc_wrefs[1])
+
+
+static PyObject *zef_name_pop;
+
+static PyObject *gc_wref_remove(ZefFFIObject *ffi, PyObject *arg)
+{
+ PyObject *destructor, *cdata, *x;
+ PyObject *res = PyObject_CallMethodObjArgs(GCWREF_DATA(ffi),
+ zef_name_pop, arg, NULL);
+ if (res == NULL)
+ return NULL;
+
+ assert(PyTuple_Check(res));
+ destructor = PyTuple_GET_ITEM(res, 0);
+ cdata = PyTuple_GET_ITEM(res, 1);
+ x = PyObject_CallFunctionObjArgs(destructor, cdata, NULL);
+ Py_DECREF(res);
+ if (x == NULL)
+ return NULL;
+ Py_DECREF(x);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMethodDef remove_callback = {
+ "remove", (PyCFunction)gc_wref_remove, METH_O
+};
+
+static PyObject *gc_weakrefs_build(ZefFFIObject *ffi, CDataObject *cd,
+ PyObject *destructor)
+{
+ PyObject *new_cdata, *ref = NULL, *tup = NULL;
+
+ if (GCWREF_DATA(ffi) == NULL) {
+ /* initialize */
+ PyObject *remove, *data;
+
+ if (zef_name_pop == NULL) {
+ zef_name_pop = PyString_InternFromString("pop");
+ if (zef_name_pop == NULL)
+ return NULL;
+ }
+ remove = PyCFunction_New(&remove_callback, (PyObject *)ffi);
+ if (remove == NULL)
+ return NULL;
+ data = PyDict_New();
+ if (data == NULL) {
+ Py_DECREF(remove);
+ return NULL;
+ }
+ GCWREF_DATA(ffi) = data;
+ GCWREF_CALLBACK(ffi) = remove;
+ }
+
+ new_cdata = do_cast(cd->c_type, (PyObject *)cd);
+ if (new_cdata == NULL)
+ goto error;
+
+ ref = PyWeakref_NewRef(new_cdata, GCWREF_CALLBACK(ffi));
+ if (ref == NULL)
+ goto error;
+
+ tup = PyTuple_Pack(2, destructor, cd);
+ if (tup == NULL)
+ goto error;
+
+ if (PyDict_SetItem(GCWREF_DATA(ffi), ref, tup) < 0)
+ goto error;
+
+ Py_DECREF(tup);
+ Py_DECREF(ref);
+ return new_cdata;
+
+ error:
+ Py_XDECREF(new_cdata);
+ Py_XDECREF(ref);
+ Py_XDECREF(tup);
+ return NULL;
+}
diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c
--- a/zeffir/ffi_obj.c
+++ b/zeffir/ffi_obj.c
@@ -17,18 +17,23 @@
struct ZefFFIObject_s {
PyObject_HEAD
PyObject *types_dict;
+ PyObject *gc_wrefs[2];
};
static void ffi_dealloc(ZefFFIObject *ffi)
{
PyObject_GC_UnTrack(ffi);
Py_DECREF(ffi->types_dict);
+ Py_XDECREF(ffi->gc_wrefs[0]);
+ Py_XDECREF(ffi->gc_wrefs[1]);
PyObject_GC_Del(ffi);
}
static int ffi_traverse(ZefFFIObject *ffi, visitproc visit, void *arg)
{
Py_VISIT(ffi->types_dict);
+ Py_VISIT(ffi->gc_wrefs[0]);
+ Py_VISIT(ffi->gc_wrefs[1]);
return 0;
}
@@ -48,6 +53,8 @@
return NULL;
}
ffi->types_dict = dict;
+ ffi->gc_wrefs[0] = NULL;
+ ffi->gc_wrefs[1] = NULL;
PyObject_GC_Track(ffi);
return (PyObject *)ffi;
@@ -255,105 +262,9 @@
return (PyObject *)cd;
}
-static int _my_PyObject_AsBool(PyObject *ob)
-{
- /* convert and cast a Python object to a boolean. Accept an integer
- or a float object, up to a CData 'long double'. */
- PyObject *io;
- PyNumberMethods *nb;
- int res;
-
-#if PY_MAJOR_VERSION < 3
- if (PyInt_Check(ob)) {
- return PyInt_AS_LONG(ob) != 0;
- }
- else
-#endif
- if (PyLong_Check(ob)) {
- return _PyLong_Sign(ob) != 0;
- }
- else if (PyFloat_Check(ob)) {
- return PyFloat_AS_DOUBLE(ob) != 0.0;
- }
- else if (CData_Check(ob)) {
- CDataObject *cd = (CDataObject *)ob;
- if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) {
- /*READ(cd->c_data, cd->c_type->ct_size)*/
- if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) {
- /* 'long double' objects: return the answer directly */
- return read_raw_longdouble_data(cd->c_data) != 0.0;
- }
- else {
- /* 'float'/'double' objects: return the answer directly */
- return read_raw_float_data(cd->c_data,
- cd->c_type->ct_size) != 0.0;
- }
- }
- }
- nb = ob->ob_type->tp_as_number;
- if (nb == NULL || (nb->nb_float == NULL && nb->nb_int == NULL)) {
- PyErr_SetString(PyExc_TypeError, "integer/float expected");
- return -1;
- }
- if (nb->nb_float && !CData_Check(ob))
- io = (*nb->nb_float) (ob);
- else
- io = (*nb->nb_int) (ob);
- if (io == NULL)
- return -1;
-
- if (PyIntOrLong_Check(io) || PyFloat_Check(io)) {
- res = _my_PyObject_AsBool(io);
- }
- else {
- PyErr_SetString(PyExc_TypeError, "integer/float conversion failed");
- res = -1;
- }
- Py_DECREF(io);
- return res;
-}
-
-static CDataObject *cast_to_integer_or_char(CTypeDescrObject *ct, PyObject *ob)
-{
- unsigned PY_LONG_LONG value;
- CDataObject *cd;
-
- if (CData_Check(ob) &&
- ((CDataObject *)ob)->c_type->ct_flags & (CT_POINTER | CT_ARRAY)) {
- value = (Py_intptr_t)((CDataObject *)ob)->c_data;
- }
- else if (PyString_Check(ob)) {
- if (PyString_GET_SIZE(ob) != 1) {
- PyErr_Format(PyExc_TypeError,
- "cannot cast string of length %zd to ctype '%s'",
- PyString_GET_SIZE(ob), ct->ct_name);
- return NULL;
- }
- value = (unsigned char)PyString_AS_STRING(ob)[0];
- }
- else if (ct->ct_flags & CT_IS_BOOL) {
- int res = _my_PyObject_AsBool(ob);
- if (res < 0)
- return NULL;
- value = res;
- }
- else {
- value = _my_PyLong_AsUnsignedLongLong(ob, 0);
- if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
- return NULL;
- }
- if (ct->ct_flags & CT_IS_BOOL)
- value = !!value;
- cd = _new_casted_primitive(ct);
- if (cd != NULL)
- write_raw_integer_data(cd->c_data, value, ct->ct_size);
- return cd;
-}
-
static PyObject *ffi_cast(ZefFFIObject *self, PyObject *args)
{
CTypeDescrObject *ct;
- CDataObject *cd;
PyObject *ob, *arg;
if (!PyArg_ParseTuple(args, "OO:cast", &arg, &ob))
return NULL;
@@ -362,99 +273,7 @@
if (ct == NULL)
return NULL;
- if (ct->ct_flags & (CT_POINTER | CT_ARRAY) &&
- ct->ct_size >= 0) {
- /* cast to a pointer or to an array.
- Note that casting to an array is an extension to the C language,
- which seems to be necessary in order to sanely get a
- <cdata 'int[3]'> at some address. */
- unsigned PY_LONG_LONG value;
-
- if (CData_Check(ob)) {
- CDataObject *cdsrc = (CDataObject *)ob;
- if (cdsrc->c_type->ct_flags & (CT_POINTER | CT_ARRAY)) {
- return new_simple_cdata(cdsrc->c_data, ct);
- }
- }
- value = _my_PyLong_AsUnsignedLongLong(ob, 0);
- if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
- return NULL;
- return new_simple_cdata((char *)(Py_intptr_t)value, ct);
- }
- else if (ct->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED
- |CT_PRIMITIVE_CHAR)) {
- /* cast to an integer type or a char */
- return (PyObject *)cast_to_integer_or_char(ct, ob);
- }
- else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) {
- /* cast to a float */
- double value;
- PyObject *io;
-
- if (CData_Check(ob)) {
- CDataObject *cdsrc = (CDataObject *)ob;
-
- if (!(cdsrc->c_type->ct_flags & CT_PRIMITIVE_ANY))
- goto cannot_cast;
- io = convert_to_object(cdsrc->c_data, cdsrc->c_type);
- if (io == NULL)
- return NULL;
- }
- else {
- io = ob;
- Py_INCREF(io);
- }
-
- if (PyBytes_Check(io)) {
- if (PyBytes_GET_SIZE(io) != 1) {
- Py_DECREF(io);
- goto cannot_cast;
- }
- value = (unsigned char)PyBytes_AS_STRING(io)[0];
- }
- else if ((ct->ct_flags & CT_IS_LONGDOUBLE) &&
- CData_Check(io) &&
- (((CDataObject *)io)->c_type->ct_flags & CT_IS_LONGDOUBLE)) {
- long double lvalue;
- char *data = ((CDataObject *)io)->c_data;
- /*READ(data, sizeof(long double)*/
- lvalue = read_raw_longdouble_data(data);
- cd = _new_casted_primitive(ct);
- if (cd != NULL)
- write_raw_longdouble_data(cd->c_data, lvalue);
- return (PyObject *)cd;
- }
- else {
- value = PyFloat_AsDouble(io);
- }
- Py_DECREF(io);
- if (value == -1.0 && PyErr_Occurred())
- return NULL;
-
- cd = _new_casted_primitive(ct);
- if (cd != NULL) {
- if (!(ct->ct_flags & CT_IS_LONGDOUBLE))
- write_raw_float_data(cd->c_data, value, ct->ct_size);
- else
- write_raw_longdouble_data(cd->c_data, (long double)value);
- }
- return (PyObject *)cd;
- }
- else {
- PyErr_Format(PyExc_TypeError, "cannot cast to ctype '%s'",
- ct->ct_name);
- return NULL;
- }
-
- cannot_cast:
- if (CData_Check(ob))
- PyErr_Format(PyExc_TypeError, "cannot cast ctype '%s' to ctype '%s'",
- ((CDataObject *)ob)->c_type->ct_name, ct->ct_name);
- else
- PyErr_Format(PyExc_TypeError,
- "cannot cast %.200s object to ctype '%s'",
- Py_TYPE(ob)->tp_name, ct->ct_name);
- return NULL;
+ return do_cast(ct, ob);
}
static PyObject *ffi_string(ZefFFIObject *self, PyObject *args)
@@ -728,12 +547,24 @@
return x;
}
+static PyObject *ffi_gc(ZefFFIObject *self, PyObject *args)
+{
+ CDataObject *cd;
+ PyObject *destructor;
+
+ if (!PyArg_ParseTuple(args, "O!O:gc", &CData_Type, &cd, &destructor))
+ return NULL;
+
+ return gc_weakrefs_build(self, cd, destructor);
+}
+
static PyMethodDef ffi_methods[] = {
{"addressof", (PyCFunction)ffi_addressof, METH_VARARGS},
{"cast", (PyCFunction)ffi_cast, METH_VARARGS},
{"close_library", ffi_close_library, METH_VARARGS | METH_STATIC},
{"from_handle", (PyCFunction)ffi_from_handle,METH_O},
+ {"gc", (PyCFunction)ffi_gc, METH_VARARGS},
{"getctype", (PyCFunction)ffi_getctype, METH_VARARGS},
{"load_library", (PyCFunction)ffi_load_library,METH_VARARGS|METH_KEYWORDS},
{"offsetof", (PyCFunction)ffi_offsetof, METH_VARARGS},
diff --git a/zeffir/test/test_cgc.py b/zeffir/test/test_cgc.py
new file mode 100644
--- /dev/null
+++ b/zeffir/test/test_cgc.py
@@ -0,0 +1,18 @@
+import gc
+import support
+
+
+def test_simple_gc():
+ ffi = support.new_ffi()
+ p1 = ffi.cast("int *", 0x12345)
+ #
+ seen = []
+ q1 = ffi.gc(p1, seen.append)
+ del p1
+ for i in range(3):
+ gc.collect()
+ assert seen == []
+ del q1
+ for i in range(3):
+ gc.collect()
+ assert seen == [ffi.cast("int *", 0x12345)]
diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c
--- a/zeffir/zeffir.c
+++ b/zeffir/zeffir.c
@@ -18,6 +18,7 @@
#include "lib_obj.c"
#include "cfunc.c"
#include "ffi_obj.c"
+#include "cgc.c"
#include "builder.c"
#include "../creflect/creflect_cdecl.c"
diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h
--- a/zeffir/zeffir.h
+++ b/zeffir/zeffir.h
@@ -27,3 +27,5 @@
CTypeDescrObject *totype);
static PyObject *combine_type_name_l(CTypeDescrObject *ct,
size_t extra_text_len);
+static PyObject *gc_weakrefs_build(ZefFFIObject *ffi, CDataObject *cd,
+ PyObject *destructor);
More information about the pypy-commit
mailing list