From noreply at buildbot.pypy.org Mon Dec 1 07:27:08 2014 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 1 Dec 2014 07:27:08 +0100 (CET) Subject: [pypy-commit] pypy default: two more unroll safes Message-ID: <20141201062708.C3E791D2865@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r74770:e6a84d9a3a34 Date: 2014-12-01 08:26 +0200 http://bitbucket.org/pypy/pypy/changeset/e6a84d9a3a34/ Log: two more unroll safes diff --git a/pypy/module/micronumpy/iterators.py b/pypy/module/micronumpy/iterators.py --- a/pypy/module/micronumpy/iterators.py +++ b/pypy/module/micronumpy/iterators.py @@ -104,6 +104,7 @@ track_index = True + @jit.unroll_safe def __init__(self, array, size, shape, strides, backstrides, op_flags=OpFlag()): from pypy.module.micronumpy import concrete assert len(shape) == len(strides) == len(backstrides) diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py --- a/pypy/module/micronumpy/nditer.py +++ b/pypy/module/micronumpy/nditer.py @@ -455,6 +455,7 @@ def descr_len(self, space): space.wrap(len(self.iters)) + @jit.unroll_safe def descr_next(self, space): for it, st in self.iters: if not it.done(st): From noreply at buildbot.pypy.org Mon Dec 1 07:33:05 2014 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 1 Dec 2014 07:33:05 +0100 (CET) Subject: [pypy-commit] pypy default: one missing Message-ID: <20141201063305.6F5D81D2865@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r74771:d14911aabae2 Date: 2014-12-01 08:32 +0200 http://bitbucket.org/pypy/pypy/changeset/d14911aabae2/ Log: one missing diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py --- a/pypy/module/micronumpy/strides.py +++ b/pypy/module/micronumpy/strides.py @@ -270,7 +270,7 @@ shape = shape_agreement(space, shape, arr) return shape - + at jit.unroll_safe def _shape_agreement(shape1, shape2): """ Checks agreement about two shapes with respect to broadcasting. Returns the resulting shape. From noreply at buildbot.pypy.org Mon Dec 1 13:19:12 2014 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 1 Dec 2014 13:19:12 +0100 (CET) Subject: [pypy-commit] creflect default: prepare the tests for more Message-ID: <20141201121912.2634E1C04B4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r134:36bdfd223942 Date: 2014-12-01 11:39 +0100 http://bitbucket.org/cffi/creflect/changeset/36bdfd223942/ Log: prepare the tests for more diff --git a/zeffir/test/support.py b/zeffir/test/support.py new file mode 100644 --- /dev/null +++ b/zeffir/test/support.py @@ -0,0 +1,34 @@ +import sys, os +from udir import udir, include_dir + +zeffir_dir = os.path.join(os.path.dirname(__file__), '..') +zeffir_lib_path = str(udir.join('zeffir.so')) + + +def run(cmd): + print cmd + err = os.system(cmd) + if err: + raise OSError("%r\n==> error code %s" % (cmd, err)) + +def compile_and_open(modname): + if not os.path.exists(zeffir_lib_path): + run("cd '%s' && " + "gcc -g -I'%s' -Wall -Werror -fPIC -shared zeffir.c -o '%s'" % + (zeffir_dir, include_dir, zeffir_lib_path)) + assert os.path.exists(zeffir_lib_path) + + sys.path.insert(0, str(udir)) + import zeffir + del sys.path[0] + + mod_c_path = str(udir.join('%s.c' % modname)) + mod_lib_path = str(udir.join('lib%s.so' % modname)) + if not os.path.exists(mod_lib_path): + run("cd '%s'/test && " + "PYTHONPATH=../.. ../../bin/creflect %s.crx '%s' && " + "gcc -g -I../../creflect -fPIC -shared '%s' -o '%s'" % + (zeffir_dir, modname, mod_c_path, mod_c_path, mod_lib_path)) + assert os.path.exists(mod_lib_path) + + return zeffir.open(modname, relative_to=zeffir_lib_path) diff --git a/zeffir/test/test_basic.py b/zeffir/test/test_basic.py --- a/zeffir/test/test_basic.py +++ b/zeffir/test/test_basic.py @@ -1,39 +1,19 @@ -import os, sys -from udir import udir, include_dir - -def setup_module(mod): - global zeffir, zeffir_lib_path - zeffir_dir = os.path.join(os.path.dirname(__file__), '..') - zeffir_lib_path = str(udir.join('zeffir.so')) - err = os.system("cd '%s' && " - "gcc -g -I'%s' -Wall -Werror -fPIC -shared zeffir.c -o '%s'" % - (zeffir_dir, include_dir, zeffir_lib_path)) - assert not err - # - sys.path.insert(0, str(udir)) - import zeffir - # - basic_c_path = str(udir.join('basic.c')) - basic_lib_path = str(udir.join('libbasic.so')) - err = os.system("cd '%s'/test && " - "PYTHONPATH=../.. ../../bin/creflect basic.crx '%s' && " - "gcc -g -I../../creflect -fPIC -shared '%s' -o '%s'" % - (zeffir_dir, basic_c_path, basic_c_path, basic_lib_path)) - assert not err +import os +import support def test_ffi_type(): - ffi, lib = zeffir.open('basic', relative_to=zeffir_lib_path) + ffi, lib = support.compile_and_open('basic') assert type(ffi).__module__ == 'zeffir' assert type(ffi).__name__ == 'FFI' assert repr(ffi) == "" % ( - os.path.dirname(zeffir_lib_path),) + os.path.dirname(support.zeffir_lib_path),) def test_forty_two(): - ffi, lib = zeffir.open('basic', relative_to=zeffir_lib_path) + ffi, lib = support.compile_and_open('basic') assert lib.forty_two == 42 assert type(lib.forty_two) is int def test_dir(): - ffi, lib = zeffir.open('basic', relative_to=zeffir_lib_path) + ffi, lib = support.compile_and_open('basic') assert dir(lib) == ['forty_two'] From noreply at buildbot.pypy.org Mon Dec 1 13:19:13 2014 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 1 Dec 2014 13:19:13 +0100 (CET) Subject: [pypy-commit] creflect default: in-progress: simple function calls Message-ID: <20141201121913.830491C04B4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r135:083a62ba609e Date: 2014-12-01 13:19 +0100 http://bitbucket.org/cffi/creflect/changeset/083a62ba609e/ Log: in-progress: simple function calls diff --git a/zeffir/test/function.crx b/zeffir/test/function.crx new file mode 100644 --- /dev/null +++ b/zeffir/test/function.crx @@ -0,0 +1,11 @@ +// CREFLECT: start + +int simple_function(int); + +// CREFLECT: end + + +int simple_function(int x) +{ + return x + 1; +} diff --git a/zeffir/test/test_function.py b/zeffir/test/test_function.py new file mode 100644 --- /dev/null +++ b/zeffir/test/test_function.py @@ -0,0 +1,8 @@ +import support + + +def test_simple_function(): + ffi, lib = support.compile_and_open('function') + res = lib.simple_function(42) + assert type(res) is int + assert res == 43 diff --git a/zeffir/zef_builder.c b/zeffir/zef_builder.c --- a/zeffir/zef_builder.c +++ b/zeffir/zef_builder.c @@ -4,9 +4,9 @@ typedef struct { _crx_builder_t cb; - PyLibObject *lib; - PyFFIObject *ffi; - PyObject *dict; + ZefLibObject *lib; + ZefFFIObject *ffi; + PyObject *l_dict; } zeffir_builder_t; static PyObject *zef_cache_primitive_signed; @@ -157,13 +157,22 @@ _crx_type_t *ret, _crx_qual_type args[], int nargs, _crx_trampoline0_fn trampl, void *directcall) { - abort(); + PyObject *l_dict = ((zeffir_builder_t *)cb)->l_dict; + ZefFFIObject *ffi = ((zeffir_builder_t *)cb)->ffi; + + assert(trampl != NULL); + PyObject *x = make_builtin_func(ffi, name, ret, args, nargs, trampl); + if (x == NULL) + return; + + PyDict_SetItemString(l_dict, name, x); + Py_DECREF(x); } static void zef_define_num_const(_crx_builder_t *cb, const char *name, _crx_type_t *ct, _crx_num_const_t *value) { - PyObject *dict = ((zeffir_builder_t *)cb)->dict; + PyObject *l_dict = ((zeffir_builder_t *)cb)->l_dict; assert(ct->ct_flags & CT_PRIMITIVE_ANY); @@ -171,7 +180,7 @@ if (x == NULL) return; - PyDict_SetItemString(dict, name, x); + PyDict_SetItemString(l_dict, name, x); Py_DECREF(x); } @@ -180,26 +189,27 @@ abort(); } -static int load_creflect_main(PyLibObject *lib) +static int load_creflect_main(ZefLibObject *lib) { const char *creflect_main = "_creflect_main"; /* XXX fixed for now */ int (*crxmain)(_crx_builder_t *); - crxmain = (int(*)(_crx_builder_t *))dlsym(lib->ffi->dl_lib, creflect_main); + crxmain = (int(*)(_crx_builder_t *))dlsym(lib->ffi->f_dl_lib, + creflect_main); if (crxmain == NULL) { PyErr_Format(PyExc_OSError, "%s: symbol '%s' not found", - lib->ffi->libname, creflect_main); + lib->ffi->f_libname, creflect_main); return -1; } int result = crxmain(NULL); if ((result & ~0xFF) != MAGIC_CREFLECT_TAG) { PyErr_Format(PyExc_OSError, "%s: %s() is not a creflect entry point", - lib->ffi->libname, creflect_main); + lib->ffi->f_libname, creflect_main); return -1; } if ((result & 0xFF) != CREFLECT_VERSION) { PyErr_Format(PyExc_OSError, "%s was made with creflect version %d, " - "expected %d", lib->ffi->libname, result & 0xFF, + "expected %d", lib->ffi->f_libname, result & 0xFF, CREFLECT_VERSION); return -1; } @@ -230,11 +240,12 @@ zef_define_num_const, zef_error, }, - lib, /* lib */ - lib->ffi, /* ffi */ - lib->dict, /* dict */ + lib, /* lib */ + lib->ffi, /* ffi */ + lib->l_dict, /* l_dict */ }; crxmain(&builder.cb); + return PyErr_Occurred() ? -1 : 0; } diff --git a/zeffir/zef_cdata.c b/zeffir/zef_cdata.c new file mode 100644 --- /dev/null +++ b/zeffir/zef_cdata.c @@ -0,0 +1,1 @@ + diff --git a/zeffir/zef_cfunc.c b/zeffir/zef_cfunc.c new file mode 100644 --- /dev/null +++ b/zeffir/zef_cfunc.c @@ -0,0 +1,96 @@ + +typedef struct { + PyObject_HEAD + + ZefFFIObject *zfs_ffi; + int zfs_nargs; + _crx_trampoline0_fn zfs_trampl; + PyMethodDef zfs_md; + char zfs_funcname[1]; + +} ZefFuncSupportObject; + +static void zef_builtin_support_dealloc(ZefFuncSupportObject *zfs) +{ + Py_DECREF(zfs->zfs_ffi); + PyObject_Del(zfs); +} + +static PyTypeObject ZefFuncSupport_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "zeffir.BuiltinSupport", + sizeof(ZefFuncSupportObject), + 0, + (destructor)zef_builtin_support_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ +}; + +static PyObject *zfs_call(PyObject *self, PyObject *args) +{ + ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)self; + int i, nargs = zfs->zfs_nargs; + Py_ssize_t actualnargs; + void *llargs[nargs]; + int llinput[nargs], lloutput; /* temp */ + + actualnargs = PyTuple_Size(args); + if (actualnargs != nargs) { + if (!PyErr_Occurred()) + PyErr_Format(PyExc_TypeError, "'%s' expects %d arguments, got %zd", + zfs->zfs_funcname, nargs, actualnargs); + return NULL; + } + + for (i = 0; i < nargs; i++) { + llinput[i] = PyInt_AsLong(PyTuple_GET_ITEM(args, i)); + if (PyErr_Occurred()) + return NULL; + llargs[i] = &llinput[i]; + } + + zfs->zfs_trampl(llargs, &lloutput); + + return PyInt_FromLong(lloutput); +} + +static PyObject *make_builtin_func(ZefFFIObject *ffi, const char *funcname, + _crx_type_t *ret, + _crx_qual_type args[], int nargs, + _crx_trampoline0_fn trampl) +{ + size_t size = sizeof(ZefFuncSupportObject) + strlen(funcname); + ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)PyObject_Malloc(size); + if (zfs == NULL) + return PyErr_NoMemory(); + PyObject_Init((PyObject *)zfs, &ZefFuncSupport_Type); + + Py_INCREF(ffi); + zfs->zfs_ffi = ffi; + zfs->zfs_nargs = nargs; + zfs->zfs_trampl = trampl; + + memset(&zfs->zfs_md, 0, sizeof(PyMethodDef)); + zfs->zfs_md.ml_name = strcpy(zfs->zfs_funcname, funcname); + zfs->zfs_md.ml_meth = &zfs_call; + zfs->zfs_md.ml_flags = METH_VARARGS; + /*zfs->zfs_md.ml_doc = ... */ + + PyObject *res = PyCFunction_NewEx(&zfs->zfs_md, (PyObject *)zfs, + ffi->f_libname_obj); + Py_DECREF(zfs); + return res; +} diff --git a/zeffir/zef_ffi_obj.c b/zeffir/zef_ffi_obj.c --- a/zeffir/zef_ffi_obj.c +++ b/zeffir/zef_ffi_obj.c @@ -1,27 +1,28 @@ -struct PyFFIObject_s { +struct ZefFFIObject_s { PyObject_HEAD - void *dl_lib; - char *libname; + void *f_dl_lib; /* keep the library returned by 'dlopen()' */ + char *f_libname; /* the original argument to 'dlopen()' */ + PyObject *f_libname_obj; /* same, as a PyObject */ }; -static void ffi_dealloc(PyFFIObject *ffi) +static void ffi_dealloc(ZefFFIObject *ffi) { - if (ffi->dl_lib != NULL) - dlclose(ffi->dl_lib); - free(ffi->libname); + if (ffi->f_dl_lib != NULL) + dlclose(ffi->f_dl_lib); + Py_DECREF(ffi->f_libname_obj); PyObject_Del(ffi); } -static PyObject *ffi_repr(PyFFIObject *ffi) +static PyObject *ffi_repr(ZefFFIObject *ffi) { - return PyString_FromFormat("", ffi->libname); + return PyString_FromFormat("", ffi->f_libname); } -static PyTypeObject FFI_Type = { +static PyTypeObject ZefFFI_Type = { PyVarObject_HEAD_INIT(NULL, 0) "zeffir.FFI", - sizeof(PyFFIObject), + sizeof(ZefFFIObject), 0, (destructor)ffi_dealloc, /* tp_dealloc */ 0, /* tp_print */ diff --git a/zeffir/zef_funcs.c b/zeffir/zef_funcs.c deleted file mode 100644 --- a/zeffir/zef_funcs.c +++ /dev/null @@ -1,77 +0,0 @@ - -static PyObject *b_open(PyObject *self, PyObject *args, PyObject *kwds) -{ - char *keywords[] = {"libname", "relative_to", NULL}; - char *libname, *relative_to; - char *path; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", keywords, - &libname, &relative_to)) - return NULL; - - char *last_slash = strrchr(relative_to, '/'); - if (last_slash == NULL) { - relative_to = "./"; - last_slash = relative_to + 1; - } - size_t n = last_slash + 1 - relative_to; - path = malloc(n + strlen(libname) + 16); - if (path == NULL) - return PyErr_NoMemory(); - memcpy(path, relative_to, n); - strcpy(path + n, "lib"); - strcat(path + n, libname); - strcat(path + n, ".so"); - - PyFFIObject *ffi = NULL; - PyLibObject *lib = NULL; - PyObject *dict = NULL; - - dlerror(); /* clear errors */ - void *dl_lib = dlopen(path, RTLD_LAZY); - if (dl_lib == NULL) { - char *error = dlerror(); - if (error == NULL) - error = "failed to open"; - PyErr_Format(PyExc_OSError, "%s: %s", path, error); - goto error; - } - - ffi = PyObject_New(PyFFIObject, &FFI_Type); - if (ffi == NULL) - goto error; - ffi->dl_lib = dl_lib; dl_lib = NULL; - ffi->libname = path; path = NULL; - - dict = PyDict_New(); - if (dict == NULL) - goto error; - - lib = PyObject_New(PyLibObject, &Lib_Type); - if (lib == NULL) - goto error; - lib->ffi = ffi; ffi = NULL; - lib->dict = dict; dict = NULL; - - if (load_creflect_main(lib) < 0) - goto error; - - PyObject *result = Py_BuildValue("OO", lib->ffi, lib); - Py_DECREF(lib); - return result; - - error: - Py_XDECREF(dict); - Py_XDECREF(lib); - Py_XDECREF(ffi); - if (dl_lib != NULL) - dlclose(dl_lib); - free(path); - return NULL; -} - - -static PyMethodDef ZeffirMethods[] = { - {"open", (PyCFunction)b_open, METH_KEYWORDS}, - {NULL, NULL} /* Sentinel */ -}; diff --git a/zeffir/zef_lib_obj.c b/zeffir/zef_lib_obj.c --- a/zeffir/zef_lib_obj.c +++ b/zeffir/zef_lib_obj.c @@ -1,26 +1,26 @@ -struct PyLibObject_s { +struct ZefLibObject_s { PyObject_HEAD - PyObject *dict; - PyFFIObject *ffi; + PyObject *l_dict; + ZefFFIObject *ffi; }; -static void lib_dealloc(PyLibObject *lib) +static void lib_dealloc(ZefLibObject *lib) { - Py_DECREF(lib->dict); + Py_DECREF(lib->l_dict); Py_DECREF(lib->ffi); PyObject_Del(lib); } -static PyObject *lib_repr(PyLibObject *lib) +static PyObject *lib_repr(ZefLibObject *lib) { return PyString_FromFormat("", - lib->ffi->libname); + lib->ffi->f_libname); } static PyObject *lib_dir(PyObject *lib, PyObject *noarg) { - return PyDict_Keys(((PyLibObject *)lib)->dict); + return PyDict_Keys(((ZefLibObject *)lib)->l_dict); } static PyMethodDef lib_methods[] = { @@ -29,14 +29,14 @@ }; static PyMemberDef lib_members[] = { - {"__dict__", T_OBJECT, offsetof(PyLibObject, dict), READONLY}, + {"__dict__", T_OBJECT, offsetof(ZefLibObject, l_dict), READONLY}, {NULL} }; -static PyTypeObject Lib_Type = { +static PyTypeObject ZefLib_Type = { PyVarObject_HEAD_INIT(NULL, 0) "zeffir.Lib", - sizeof(PyLibObject), + sizeof(ZefLibObject), 0, (destructor)lib_dealloc, /* tp_dealloc */ 0, /* tp_print */ @@ -68,5 +68,5 @@ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ - offsetof(PyLibObject, dict), /* tp_dictoffset */ + offsetof(ZefLibObject, l_dict), /* tp_dictoffset */ }; diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c --- a/zeffir/zeffir.c +++ b/zeffir/zeffir.c @@ -6,8 +6,8 @@ typedef struct _crx_type_s CTypeDescrObject; -typedef struct PyLibObject_s PyLibObject; -typedef struct PyFFIObject_s PyFFIObject; +typedef struct ZefLibObject_s ZefLibObject; +typedef struct ZefFFIObject_s ZefFFIObject; /************************************************************/ @@ -15,13 +15,91 @@ /* Allows all function and global symbols to remain static. */ #include "zef_ctype.c" +#include "zef_cdata.c" #include "zef_ffi_obj.c" #include "zef_lib_obj.c" +#include "zef_cfunc.c" #include "zef_builder.c" -#include "zef_funcs.c" /************************************************************/ + +static PyObject *z_open(PyObject *self, PyObject *args, PyObject *kwds) +{ + char *keywords[] = {"libname", "relative_to", NULL}; + char *libname, *relative_to, *relative_dir; + PyObject *path; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", keywords, + &libname, &relative_to)) + return NULL; + + char *last_slash = strrchr(relative_to, '/'); + if (last_slash == NULL) + relative_dir = strdup("."); + else + relative_dir = strndup(relative_to, last_slash - relative_to); + if (relative_dir == NULL) + return PyErr_NoMemory(); + + path = PyString_FromFormat("%s/lib%s.so", relative_dir, libname); + free(relative_dir); + if (path == NULL) + return NULL; + + ZefFFIObject *ffi = NULL; + ZefLibObject *lib = NULL; + PyObject *dict = NULL; + + dlerror(); /* clear errors */ + void *dl_lib = dlopen(PyString_AS_STRING(path), RTLD_LAZY); + if (dl_lib == NULL) { + char *error = dlerror(); + if (error == NULL) + error = "failed to open"; + PyErr_Format(PyExc_OSError, "%s: %s", PyString_AS_STRING(path), error); + goto error; + } + + ffi = PyObject_New(ZefFFIObject, &ZefFFI_Type); + if (ffi == NULL) + goto error; + ffi->f_dl_lib = dl_lib; dl_lib = NULL; + ffi->f_libname = PyString_AS_STRING(path); + ffi->f_libname_obj = path; path = NULL; + + dict = PyDict_New(); + if (dict == NULL) + goto error; + + lib = PyObject_New(ZefLibObject, &ZefLib_Type); + if (lib == NULL) + goto error; + lib->ffi = ffi; ffi = NULL; + lib->l_dict = dict; dict = NULL; + + if (load_creflect_main(lib) < 0) + goto error; + + PyObject *result = Py_BuildValue("OO", lib->ffi, lib); + Py_DECREF(lib); + return result; + + error: + Py_XDECREF(dict); + Py_XDECREF(lib); + Py_XDECREF(ffi); + if (dl_lib != NULL) + dlclose(dl_lib); + Py_XDECREF(path); + return NULL; +} + +static PyMethodDef ZeffirMethods[] = { + {"open", (PyCFunction)z_open, METH_KEYWORDS}, + {NULL, NULL} /* Sentinel */ +}; + PyMODINIT_FUNC initzeffir(void) { @@ -34,8 +112,12 @@ if (PyErr_Occurred()) return; - if (PyType_Ready(&FFI_Type) < 0) + if (PyType_Ready(&ZefFFI_Type) < 0) return; - if (PyType_Ready(&Lib_Type) < 0) + if (PyType_Ready(&ZefLib_Type) < 0) + return; + if (PyType_Ready(&CTypeDescr_Type) < 0) + return; + if (PyType_Ready(&ZefFuncSupport_Type) < 0) return; } From noreply at buildbot.pypy.org Mon Dec 1 13:38:31 2014 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 1 Dec 2014 13:38:31 +0100 (CET) Subject: [pypy-commit] creflect default: add comment Message-ID: <20141201123831.484151D2CCC@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r136:96dd4b191e06 Date: 2014-12-01 13:38 +0100 http://bitbucket.org/cffi/creflect/changeset/96dd4b191e06/ Log: add comment diff --git a/zeffir/test/support.py b/zeffir/test/support.py --- a/zeffir/test/support.py +++ b/zeffir/test/support.py @@ -12,6 +12,8 @@ raise OSError("%r\n==> error code %s" % (cmd, err)) def compile_and_open(modname): + """Process with creflect 'modname.crx', compile the result, and load it.""" + if not os.path.exists(zeffir_lib_path): run("cd '%s' && " "gcc -g -I'%s' -Wall -Werror -fPIC -shared zeffir.c -o '%s'" % From noreply at buildbot.pypy.org Mon Dec 1 14:46:46 2014 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 1 Dec 2014 14:46:46 +0100 (CET) Subject: [pypy-commit] pypy default: kill this hack for now - makes matters worse without a deeper thought Message-ID: <20141201134646.332521C04B4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r74772:70275c5679a9 Date: 2014-12-01 15:46 +0200 http://bitbucket.org/pypy/pypy/changeset/70275c5679a9/ Log: kill this hack for now - makes matters worse without a deeper thought diff --git a/pypy/module/micronumpy/iterators.py b/pypy/module/micronumpy/iterators.py --- a/pypy/module/micronumpy/iterators.py +++ b/pypy/module/micronumpy/iterators.py @@ -155,7 +155,7 @@ index = state.index if self.track_index: index += 1 - indices = state.indices[:] + indices = state.indices offset = state.offset if self.contiguous: offset += self.array.dtype.elsize From noreply at buildbot.pypy.org Mon Dec 1 15:05:04 2014 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 1 Dec 2014 15:05:04 +0100 (CET) Subject: [pypy-commit] pypy default: this is unroll safe Message-ID: <20141201140504.58CF31C34C4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r74773:ff9f32344c01 Date: 2014-12-01 16:04 +0200 http://bitbucket.org/pypy/pypy/changeset/ff9f32344c01/ Log: this is unroll safe diff --git a/pypy/module/micronumpy/flagsobj.py b/pypy/module/micronumpy/flagsobj.py --- a/pypy/module/micronumpy/flagsobj.py +++ b/pypy/module/micronumpy/flagsobj.py @@ -1,3 +1,5 @@ +from rpython.rlib import jit + from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app @@ -13,6 +15,7 @@ arr.flags &= ~flags + at jit.unroll_safe def _update_contiguous_flags(arr): shape = arr.shape strides = arr.strides From noreply at buildbot.pypy.org Mon Dec 1 15:11:38 2014 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 1 Dec 2014 15:11:38 +0100 (CET) Subject: [pypy-commit] pypy default: try some unrolling strategy Message-ID: <20141201141138.5A4B21C34C4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r74774:bf9b7211befc Date: 2014-12-01 16:11 +0200 http://bitbucket.org/pypy/pypy/changeset/bf9b7211befc/ Log: try some unrolling strategy diff --git a/rpython/rtyper/rlist.py b/rpython/rtyper/rlist.py --- a/rpython/rtyper/rlist.py +++ b/rpython/rtyper/rlist.py @@ -983,6 +983,14 @@ # # Comparison. +def listeq_unroll_case(l1, l2, eqfn): + if jit.isvirtual(l1) and len(l1) < 10: + return True + if jit.isvirtual(l2) and len(l2) < 10: + return True + return False + + at jit.unroll_iff(listeq_unroll_case) def ll_listeq(l1, l2, eqfn): if not l1 and not l2: return True From noreply at buildbot.pypy.org Mon Dec 1 15:13:08 2014 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 1 Dec 2014 15:13:08 +0100 (CET) Subject: [pypy-commit] pypy default: I never get those right Message-ID: <20141201141308.BB35D1C34C4@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r74775:739ecaa8a1c0 Date: 2014-12-01 16:12 +0200 http://bitbucket.org/pypy/pypy/changeset/739ecaa8a1c0/ Log: I never get those right diff --git a/rpython/rtyper/rlist.py b/rpython/rtyper/rlist.py --- a/rpython/rtyper/rlist.py +++ b/rpython/rtyper/rlist.py @@ -984,13 +984,13 @@ # Comparison. def listeq_unroll_case(l1, l2, eqfn): - if jit.isvirtual(l1) and len(l1) < 10: + if jit.isvirtual(l1) and l1.ll_length() < 10: return True - if jit.isvirtual(l2) and len(l2) < 10: + if jit.isvirtual(l2) and l2.ll_length() < 10: return True return False - at jit.unroll_iff(listeq_unroll_case) + at jit.look_inside_iff(listeq_unroll_case) def ll_listeq(l1, l2, eqfn): if not l1 and not l2: return True From noreply at buildbot.pypy.org Mon Dec 1 16:59:19 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Mon, 1 Dec 2014 16:59:19 +0100 (CET) Subject: [pypy-commit] pypy framestate: move all the SETUP_XXX Message-ID: <20141201155919.35B9C1D36F5@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74776:ec616f23ec15 Date: 2014-11-26 17:18 +0100 http://bitbucket.org/pypy/pypy/changeset/ec616f23ec15/ Log: move all the SETUP_XXX diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -507,6 +507,36 @@ block = ExceptBlock(ctx.stackdepth, self.arg) ctx.blockstack.append(block) + at bc_reader.register_opcode +class SETUP_LOOP(BCInstruction): + def eval(self, ctx): + from rpython.flowspace.flowcontext import LoopBlock + block = LoopBlock(ctx.stackdepth, self.arg) + ctx.blockstack.append(block) + + at bc_reader.register_opcode +class SETUP_FINALLY(BCInstruction): + def eval(self, ctx): + from rpython.flowspace.flowcontext import FinallyBlock + block = FinallyBlock(ctx.stackdepth, self.arg) + ctx.blockstack.append(block) + + at bc_reader.register_opcode +class SETUP_WITH(BCInstruction): + def eval(self, ctx): + from rpython.flowspace.flowcontext import WithBlock + # A simpler version than the 'real' 2.7 one: + # directly call manager.__enter__(), don't use special lookup functions + # which don't make sense on the RPython type system. + w_manager = ctx.peekvalue() + w_exit = op.getattr(w_manager, const("__exit__")).eval(ctx) + ctx.settopvalue(w_exit) + w_enter = op.getattr(w_manager, const('__enter__')).eval(ctx) + w_result = op.simple_call(w_enter).eval(ctx) + block = WithBlock(ctx.stackdepth, self.arg) + ctx.blockstack.append(block) + ctx.pushvalue(w_result) + _unary_ops = [ ('UNARY_POSITIVE', op.pos), ('UNARY_NEGATIVE', op.neg), diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -702,27 +702,6 @@ w_iterator = op.iter(w_iterable).eval(self) self.pushvalue(w_iterator) - def SETUP_LOOP(self, target): - block = LoopBlock(self.stackdepth, target) - self.blockstack.append(block) - - def SETUP_FINALLY(self, target): - block = FinallyBlock(self.stackdepth, target) - self.blockstack.append(block) - - def SETUP_WITH(self, target): - # A simpler version than the 'real' 2.7 one: - # directly call manager.__enter__(), don't use special lookup functions - # which don't make sense on the RPython type system. - w_manager = self.peekvalue() - w_exit = op.getattr(w_manager, const("__exit__")).eval(self) - self.settopvalue(w_exit) - w_enter = op.getattr(w_manager, const('__enter__')).eval(self) - w_result = op.simple_call(w_enter).eval(self) - block = WithBlock(self.stackdepth, target) - self.blockstack.append(block) - self.pushvalue(w_result) - def WITH_CLEANUP(self, oparg): # Note: RPython context managers receive None in lieu of tracebacks # and cannot suppress the exception. From noreply at buildbot.pypy.org Mon Dec 1 16:59:20 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Mon, 1 Dec 2014 16:59:20 +0100 (CET) Subject: [pypy-commit] pypy framestate: create a base class for the SETUP_XXX opcodes Message-ID: <20141201155920.62DEA1D36F5@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74777:13de37f01288 Date: 2014-11-26 17:36 +0100 http://bitbucket.org/pypy/pypy/changeset/13de37f01288/ Log: create a base class for the SETUP_XXX opcodes diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -499,30 +499,36 @@ else: raise +class SetupInstruction(BCInstruction): + def bc_flow(self, reader): + reader.curr_block.operations.append(self) + self.target = reader.get_block_at(self.arg) + + def eval(self, ctx): + block = self.make_block(ctx) + ctx.blockstack.append(block) + @bc_reader.register_opcode -class SETUP_EXCEPT(BCInstruction): - def eval(self, ctx): +class SETUP_EXCEPT(SetupInstruction): + def make_block(self, ctx): from rpython.flowspace.flowcontext import ExceptBlock - block = ExceptBlock(ctx.stackdepth, self.arg) - ctx.blockstack.append(block) + return ExceptBlock(ctx.stackdepth, self.arg) @bc_reader.register_opcode -class SETUP_LOOP(BCInstruction): - def eval(self, ctx): +class SETUP_LOOP(SetupInstruction): + def make_block(self, ctx): from rpython.flowspace.flowcontext import LoopBlock - block = LoopBlock(ctx.stackdepth, self.arg) - ctx.blockstack.append(block) + return LoopBlock(ctx.stackdepth, self.arg) @bc_reader.register_opcode -class SETUP_FINALLY(BCInstruction): - def eval(self, ctx): +class SETUP_FINALLY(SetupInstruction): + def make_block(self, ctx): from rpython.flowspace.flowcontext import FinallyBlock - block = FinallyBlock(ctx.stackdepth, self.arg) - ctx.blockstack.append(block) + return FinallyBlock(ctx.stackdepth, self.arg) @bc_reader.register_opcode -class SETUP_WITH(BCInstruction): +class SETUP_WITH(SetupInstruction): def eval(self, ctx): from rpython.flowspace.flowcontext import WithBlock # A simpler version than the 'real' 2.7 one: From noreply at buildbot.pypy.org Mon Dec 1 16:59:21 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Mon, 1 Dec 2014 16:59:21 +0100 (CET) Subject: [pypy-commit] pypy framestate: move BREAK_LOOP, CONTINUE_LOOP Message-ID: <20141201155921.9F4641D36F5@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74778:8796e220baf7 Date: 2014-11-26 19:38 +0100 http://bitbucket.org/pypy/pypy/changeset/8796e220baf7/ Log: move BREAK_LOOP, CONTINUE_LOOP diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -499,6 +499,18 @@ else: raise + at bc_reader.register_opcode +class BREAK_LOOP(BCInstruction): + def eval(self, ctx): + from rpython.flowspace.flowcontext import Break + raise Break + + at bc_reader.register_opcode +class CONTINUE_LOOP(BCInstruction): + def eval(self, ctx): + from rpython.flowspace.flowcontext import Continue + raise Continue(self.arg) + class SetupInstruction(BCInstruction): def bc_flow(self, reader): reader.curr_block.operations.append(self) diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -479,12 +479,6 @@ def BAD_OPCODE(self, _): raise FlowingError("This operation is not RPython") - def BREAK_LOOP(self, oparg): - raise Break - - def CONTINUE_LOOP(self, startofloop): - raise Continue(startofloop) - def not_(self, w_obj): w_bool = op.bool(w_obj).eval(self) return const(not self.guessbool(w_bool)) From noreply at buildbot.pypy.org Mon Dec 1 16:59:22 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Mon, 1 Dec 2014 16:59:22 +0100 (CET) Subject: [pypy-commit] pypy framestate: return BC blocks from FrameBlock.handle() Message-ID: <20141201155922.DA2831D36F5@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74779:3b6c35deccbc Date: 2014-11-26 19:54 +0100 http://bitbucket.org/pypy/pypy/changeset/3b6c35deccbc/ Log: return BC blocks from FrameBlock.handle() diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -507,9 +507,13 @@ @bc_reader.register_opcode class CONTINUE_LOOP(BCInstruction): + def bc_flow(self, reader): + reader.curr_block.operations.append(self) + self.target = reader.get_block_at(self.arg) + def eval(self, ctx): from rpython.flowspace.flowcontext import Continue - raise Continue(self.arg) + raise Continue(self.target) class SetupInstruction(BCInstruction): def bc_flow(self, reader): @@ -525,19 +529,19 @@ class SETUP_EXCEPT(SetupInstruction): def make_block(self, ctx): from rpython.flowspace.flowcontext import ExceptBlock - return ExceptBlock(ctx.stackdepth, self.arg) + return ExceptBlock(ctx.stackdepth, self.target) @bc_reader.register_opcode class SETUP_LOOP(SetupInstruction): def make_block(self, ctx): from rpython.flowspace.flowcontext import LoopBlock - return LoopBlock(ctx.stackdepth, self.arg) + return LoopBlock(ctx.stackdepth, self.target) @bc_reader.register_opcode class SETUP_FINALLY(SetupInstruction): def make_block(self, ctx): from rpython.flowspace.flowcontext import FinallyBlock - return FinallyBlock(ctx.stackdepth, self.arg) + return FinallyBlock(ctx.stackdepth, self.target) @bc_reader.register_opcode class SETUP_WITH(SetupInstruction): @@ -551,7 +555,7 @@ ctx.settopvalue(w_exit) w_enter = op.getattr(w_manager, const('__enter__')).eval(ctx) w_result = op.simple_call(w_enter).eval(ctx) - block = WithBlock(ctx.stackdepth, self.arg) + block = WithBlock(ctx.stackdepth, self.target) ctx.blockstack.append(block) ctx.pushvalue(w_result) diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -16,6 +16,7 @@ rpython_print_newline) from rpython.flowspace.operation import op from rpython.flowspace.bytecode import BytecodeCorruption, bc_reader +from rpython.flowspace.bytecode import BytecodeBlock from rpython.flowspace.pygraph import PyGraph w_None = const(None) @@ -356,12 +357,11 @@ try: next_block = instr.eval(self) except FlowSignal as signal: - next_position = bc_graph.get_position(self.unroll(signal)) + next_block = self.unroll(signal) + if next_block is None: + next_position = bc_graph.next_pos() else: - if next_block is None: - next_position = bc_graph.next_pos() - else: - next_position = next_block, 0 + next_position = next_block, 0 bc_graph.curr_position = next_position self.recorder.final_state = self.getstate(next_position) @@ -1125,20 +1125,20 @@ """Abstract base class for frame blocks from the blockstack, used by the SETUP_XXX and POP_BLOCK opcodes.""" - def __init__(self, stackdepth, handlerposition): - self.handlerposition = handlerposition + def __init__(self, stackdepth, handler): + self.handler = handler self.stackdepth = stackdepth def __eq__(self, other): return (self.__class__ is other.__class__ and - self.handlerposition == other.handlerposition and + self.handler == other.handler and self.stackdepth == other.stackdepth) def __ne__(self, other): return not (self == other) def __hash__(self): - return hash((self.handlerposition, self.stackdepth)) + return hash((self.handler, self.stackdepth)) def cleanupstack(self, ctx): ctx.dropvaluesuntil(self.stackdepth) @@ -1161,7 +1161,7 @@ else: # jump to the end of the loop self.cleanupstack(ctx) - return self.handlerposition + return self.handler class ExceptBlock(FrameBlock): """An try:except: block. Stores the position of the exception handler.""" @@ -1181,7 +1181,7 @@ ctx.pushvalue(w_exc.w_value) ctx.pushvalue(w_exc.w_type) ctx.last_exception = w_exc - return self.handlerposition # jump to the handler + return self.handler # jump to the handler class FinallyBlock(FrameBlock): """A try:finally: block. Stores the position of the exception handler.""" @@ -1193,7 +1193,7 @@ # the block unrolling and the entering the finally: handler. self.cleanupstack(ctx) ctx.pushvalue(unroller) - return self.handlerposition # jump to the handler + return self.handler # jump to the handler class WithBlock(FinallyBlock): From noreply at buildbot.pypy.org Mon Dec 1 22:14:28 2014 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 1 Dec 2014 22:14:28 +0100 (CET) Subject: [pypy-commit] creflect default: another reorganization, split more the ffi and the lib Message-ID: <20141201211428.BBE401C34C4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r137:111c65f6cc20 Date: 2014-12-01 21:40 +0100 http://bitbucket.org/cffi/creflect/changeset/111c65f6cc20/ Log: another reorganization, split more the ffi and the lib diff --git a/zeffir/zef_builder.c b/zeffir/builder.c rename from zeffir/zef_builder.c rename to zeffir/builder.c --- a/zeffir/zef_builder.c +++ b/zeffir/builder.c @@ -5,11 +5,36 @@ typedef struct { _crx_builder_t cb; ZefLibObject *lib; + PyObject *l_dict; ZefFFIObject *ffi; - PyObject *l_dict; + PyObject *types_dict; } zeffir_builder_t; -static PyObject *zef_cache_primitive_signed; +static CTypeDescrObject *get_cached_type(_crx_builder_t *cb, const char *name, + int accept_flags) +{ + PyObject *types_dict = ((zeffir_builder_t *)cb)->types_dict; + PyObject *x = PyDict_GetItemString(types_dict, name); + CTypeDescrObject *ct; + + if (x == NULL || !CTypeDescr_Check(x)) + return NULL; + ct = (CTypeDescrObject *)x; + if ((ct->ct_flags & accept_flags) == 0) + return NULL; + return ct; +} + +static _crx_type_t *put_cached_type(_crx_builder_t *cb, const char *name, + CTypeDescrObject *ct) +{ + PyObject *types_dict = ((zeffir_builder_t *)cb)->types_dict; + int err = PyDict_SetItemString(types_dict, name, (PyObject *)ct); + Py_DECREF(ct); + if (err < 0) + return NULL; + return ct; /* still a reference in the dict */ +} static _crx_type_t *zef_get_void_type(_crx_builder_t *cb) { @@ -29,33 +54,26 @@ static _crx_type_t *zef_get_signed_type(_crx_builder_t *cb, size_t sz, const char *name) { - PyObject *x = PyDict_GetItemString(zef_cache_primitive_signed, name); - CTypeDescrObject *td = (CTypeDescrObject *)x; + CTypeDescrObject *td = get_cached_type(cb, name, CT_PRIMITIVE_SIGNED); + if (td != NULL && td->ct_size == sz) + return td; - if (td == NULL) { - int err; - size_t name_length = strlen(name); + size_t name_length = strlen(name); - td = ctypedescr_new(name_length + 1); - if (td == NULL) - return NULL; + td = ctypedescr_new(name_length + 1); + if (td == NULL) + return NULL; - memcpy(td->ct_name, name, name_length + 1); - td->ct_name_position = name_length; - td->ct_size = sz; - //td->ct_length = ptypes->align; - //td->ct_extra = ffitype; - td->ct_flags = CT_PRIMITIVE_SIGNED; - if (td->ct_size <= sizeof(long)) - td->ct_flags |= CT_PRIMITIVE_FITS_LONG; + memcpy(td->ct_name, name, name_length + 1); + td->ct_name_position = name_length; + td->ct_size = sz; + //td->ct_length = ptypes->align; + //td->ct_extra = ffitype; + td->ct_flags = CT_PRIMITIVE_SIGNED; + if (td->ct_size <= sizeof(long)) + td->ct_flags |= CT_PRIMITIVE_FITS_LONG; - x = (PyObject *)td; - err = PyDict_SetItemString(zef_cache_primitive_signed, name, x); - Py_DECREF(x); - if (err < 0) - return NULL; - } - return td; + return put_cached_type(cb, name, td); } static _crx_type_t *zef_get_unsigned_type(_crx_builder_t *cb, size_t sz, @@ -158,10 +176,11 @@ _crx_trampoline0_fn trampl, void *directcall) { PyObject *l_dict = ((zeffir_builder_t *)cb)->l_dict; - ZefFFIObject *ffi = ((zeffir_builder_t *)cb)->ffi; + PyObject *l_libname_obj = ((zeffir_builder_t *)cb)->lib->l_libname_obj; assert(trampl != NULL); - PyObject *x = make_builtin_func(ffi, name, ret, args, nargs, trampl); + PyObject *x = make_builtin_func(l_libname_obj, name, ret, + args, nargs, trampl); if (x == NULL) return; @@ -189,27 +208,27 @@ abort(); } -static int load_creflect_main(ZefLibObject *lib) +static int load_creflect_main(ZefFFIObject *ffi, ZefLibObject *lib) { const char *creflect_main = "_creflect_main"; /* XXX fixed for now */ int (*crxmain)(_crx_builder_t *); - crxmain = (int(*)(_crx_builder_t *))dlsym(lib->ffi->f_dl_lib, - creflect_main); + + crxmain = (int(*)(_crx_builder_t *))dlsym(lib->l_dl_lib, creflect_main); if (crxmain == NULL) { PyErr_Format(PyExc_OSError, "%s: symbol '%s' not found", - lib->ffi->f_libname, creflect_main); + lib->l_libname, creflect_main); return -1; } int result = crxmain(NULL); if ((result & ~0xFF) != MAGIC_CREFLECT_TAG) { PyErr_Format(PyExc_OSError, "%s: %s() is not a creflect entry point", - lib->ffi->f_libname, creflect_main); + lib->l_libname, creflect_main); return -1; } if ((result & 0xFF) != CREFLECT_VERSION) { PyErr_Format(PyExc_OSError, "%s was made with creflect version %d, " - "expected %d", lib->ffi->f_libname, result & 0xFF, + "expected %d", lib->l_libname, result & 0xFF, CREFLECT_VERSION); return -1; } @@ -240,17 +259,12 @@ zef_define_num_const, zef_error, }, - lib, /* lib */ - lib->ffi, /* ffi */ - lib->l_dict, /* l_dict */ + lib, /* lib */ + lib->l_dict, /* l_dict */ + ffi, /* ffi */ + ffi->types_dict, /* types_dict */ }; crxmain(&builder.cb); return PyErr_Occurred() ? -1 : 0; } - -static void init_caches(void) -{ - if ((zef_cache_primitive_signed = PyDict_New()) == NULL) - return; -} diff --git a/zeffir/zef_cdata.c b/zeffir/cdata.c rename from zeffir/zef_cdata.c rename to zeffir/cdata.c diff --git a/zeffir/zef_cfunc.c b/zeffir/cfunc.c rename from zeffir/zef_cfunc.c rename to zeffir/cfunc.c --- a/zeffir/zef_cfunc.c +++ b/zeffir/cfunc.c @@ -2,7 +2,6 @@ typedef struct { PyObject_HEAD - ZefFFIObject *zfs_ffi; int zfs_nargs; _crx_trampoline0_fn zfs_trampl; PyMethodDef zfs_md; @@ -12,13 +11,12 @@ static void zef_builtin_support_dealloc(ZefFuncSupportObject *zfs) { - Py_DECREF(zfs->zfs_ffi); PyObject_Del(zfs); } static PyTypeObject ZefFuncSupport_Type = { PyVarObject_HEAD_INIT(NULL, 0) - "zeffir.BuiltinSupport", + "zeffir.FuncSupport", sizeof(ZefFuncSupportObject), 0, (destructor)zef_builtin_support_dealloc, /* tp_dealloc */ @@ -67,8 +65,8 @@ return PyInt_FromLong(lloutput); } -static PyObject *make_builtin_func(ZefFFIObject *ffi, const char *funcname, - _crx_type_t *ret, +static PyObject *make_builtin_func(PyObject *libname_obj, + const char *funcname, _crx_type_t *ret, _crx_qual_type args[], int nargs, _crx_trampoline0_fn trampl) { @@ -78,8 +76,6 @@ return PyErr_NoMemory(); PyObject_Init((PyObject *)zfs, &ZefFuncSupport_Type); - Py_INCREF(ffi); - zfs->zfs_ffi = ffi; zfs->zfs_nargs = nargs; zfs->zfs_trampl = trampl; @@ -90,7 +86,7 @@ /*zfs->zfs_md.ml_doc = ... */ PyObject *res = PyCFunction_NewEx(&zfs->zfs_md, (PyObject *)zfs, - ffi->f_libname_obj); + libname_obj); Py_DECREF(zfs); return res; } diff --git a/zeffir/zef_ctype.c b/zeffir/ctype.c rename from zeffir/zef_ctype.c rename to zeffir/ctype.c diff --git a/zeffir/zef_ffi_obj.c b/zeffir/ffi_obj.c rename from zeffir/zef_ffi_obj.c rename to zeffir/ffi_obj.c --- a/zeffir/zef_ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -1,24 +1,125 @@ + +/* An FFI object has methods like ffi.new(). It is also a container for the + type declarations (typedefs and structs) that you can use, say in ffi.new(). + They are in a dictionary available in the 'types' attribute, which you + can edit manually (e.g. 'ffi.types.update(ffi2.types)'). + + The method ffi.load_library() finds a creflect dynamic library, load + its type declarations into ffi.types, and returns a Lib object with + the functions, global variables and constants as attributes. Once the + Lib object goes out of scope (or ffi.close_library() is called), the + library is unloaded; accessing functions or global variables afterwards + will segfault. + + There is no direct internal reference between the FFI and the Lib object. +*/ struct ZefFFIObject_s { PyObject_HEAD - void *f_dl_lib; /* keep the library returned by 'dlopen()' */ - char *f_libname; /* the original argument to 'dlopen()' */ - PyObject *f_libname_obj; /* same, as a PyObject */ + PyObject *types_dict; }; static void ffi_dealloc(ZefFFIObject *ffi) { - if (ffi->f_dl_lib != NULL) - dlclose(ffi->f_dl_lib); - Py_DECREF(ffi->f_libname_obj); - PyObject_Del(ffi); + PyObject_GC_UnTrack(ffi); + Py_DECREF(ffi->types_dict); + PyObject_GC_Del(ffi); } -static PyObject *ffi_repr(ZefFFIObject *ffi) +static int ffi_traverse(ZefFFIObject *ffi, visitproc visit, void *arg) { - return PyString_FromFormat("", ffi->f_libname); + Py_VISIT(ffi->types_dict); + return 0; } +static PyObject *ffiobj_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + char *keywords[] = {NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "", keywords)) + return NULL; + + PyObject *dict = PyDict_New(); + if (dict == NULL) + return NULL; + + ZefFFIObject *ffi = PyObject_GC_New(ZefFFIObject, &ZefFFI_Type); + if (ffi == NULL) { + Py_DECREF(dict); + return NULL; + } + ffi->types_dict = dict; + PyObject_GC_Track(ffi); + + return (PyObject *)ffi; +} + +static PyObject *ffi_load_library(ZefFFIObject *self, PyObject *args, + PyObject *kwds) +{ + char *keywords[] = {"libname", "relative_to", NULL}; + char *libname, *relative_to = NULL; + char *relative_dir; + PyObject *path; + ZefLibObject *lib; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|z", keywords, + &libname, &relative_to)) + return NULL; + + if (relative_to == NULL) { + relative_dir = strdup(""); + } + else { + char *last_slash = strrchr(relative_to, '/'); + if (last_slash == NULL) + relative_dir = strdup("./"); + else + relative_dir = strndup(relative_to, last_slash + 1 - relative_to); + } + if (relative_dir == NULL) + return PyErr_NoMemory(); + + path = PyString_FromFormat("%slib%s.so", relative_dir, libname); + free(relative_dir); + if (path == NULL) + return NULL; + + lib = lib_create(path); + Py_DECREF(path); + + if (load_creflect_main(self, lib) < 0) { + Py_DECREF(lib); + return NULL; + } + return (PyObject *)lib; +} + +static PyObject *ffi_close_library(PyObject *no_self, PyObject *args) +{ + ZefLibObject *lib; + + if (!PyArg_ParseTuple(args, "O!", &lib, &ZefLib_Type)) + return NULL; + + if (lib_close(lib) < 0) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef ffi_methods[] = { + {"load_library", (PyCFunction)ffi_load_library, + METH_VARARGS | METH_KEYWORDS}, + {"close_library", ffi_close_library, METH_VARARGS | METH_STATIC}, + {NULL} +}; + +static PyMemberDef ffi_members[] = { + {"types", T_OBJECT, offsetof(ZefFFIObject, types_dict), READONLY}, + {NULL} +}; + static PyTypeObject ZefFFI_Type = { PyVarObject_HEAD_INIT(NULL, 0) "zeffir.FFI", @@ -29,7 +130,7 @@ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ - (reprfunc)ffi_repr, /* tp_repr */ + 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -39,14 +140,24 @@ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ - 0, /* tp_traverse */ + (traverseproc)ffi_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ + ffi_methods, /* tp_methods */ + ffi_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + ffiobj_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ }; diff --git a/zeffir/zef_lib_obj.c b/zeffir/lib_obj.c rename from zeffir/zef_lib_obj.c rename to zeffir/lib_obj.c --- a/zeffir/zef_lib_obj.c +++ b/zeffir/lib_obj.c @@ -1,21 +1,47 @@ + +/* A Lib object is special in the sense that it has a custom __getattr__ + which only returns objects from the internal, inaccessible 'l_dict'. + (It raises AttributeError for anything else, like '__class__'.) +*/ struct ZefLibObject_s { PyObject_HEAD - PyObject *l_dict; - ZefFFIObject *ffi; + PyObject *l_dict; /* functions, global variables and constants */ + void *l_dl_lib; /* keep the library returned by 'dlopen()' */ + char *l_libname; /* the original argument to 'dlopen()' */ + PyObject *l_libname_obj; /* same, as a PyObject */ }; static void lib_dealloc(ZefLibObject *lib) { - Py_DECREF(lib->l_dict); - Py_DECREF(lib->ffi); + (void)lib_close(lib); PyObject_Del(lib); } static PyObject *lib_repr(ZefLibObject *lib) { - return PyString_FromFormat("", - lib->ffi->f_libname); + return PyString_FromFormat("", + lib->l_libname, + lib->l_dl_lib == NULL ? " (closed)" : ""); +} + +static PyObject *lib_getattr(ZefLibObject *lib, PyObject *name) +{ + if (lib->l_dict == NULL) { + PyErr_Format(PyExc_ValueError, "lib '%.200s' was closed", + lib->l_libname); + return NULL; + } + + PyObject *x = PyDict_GetItem(lib->l_dict, name); + if (x == NULL) { + PyErr_Format(PyExc_AttributeError, + "lib '%.200s' has no function," + " global variable or constant '%.200s'", + lib->l_libname, + PyString_Check(name) ? PyString_AS_STRING(name) : "?"); + } + return x; } static PyObject *lib_dir(PyObject *lib, PyObject *noarg) @@ -28,11 +54,6 @@ {NULL, NULL} /* sentinel */ }; -static PyMemberDef lib_members[] = { - {"__dict__", T_OBJECT, offsetof(ZefLibObject, l_dict), READONLY}, - {NULL} -}; - static PyTypeObject ZefLib_Type = { PyVarObject_HEAD_INIT(NULL, 0) "zeffir.Lib", @@ -50,7 +71,7 @@ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ + (getattrofunc)lib_getattr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ @@ -62,7 +83,7 @@ 0, /* tp_iter */ 0, /* tp_iternext */ lib_methods, /* tp_methods */ - lib_members, /* tp_members */ + 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ @@ -70,3 +91,54 @@ 0, /* tp_descr_set */ offsetof(ZefLibObject, l_dict), /* tp_dictoffset */ }; + +static void lib_dlerror(ZefLibObject *lib) +{ + char *error = dlerror(); + if (error == NULL) + error = "(no error reported)"; + PyErr_Format(PyExc_OSError, "%s: %s", lib->l_libname, error); +} + +static ZefLibObject *lib_create(PyObject *path) +{ + ZefLibObject *lib; + + lib = PyObject_New(ZefLibObject, &ZefLib_Type); + if (lib == NULL) + return NULL; + + lib->l_dl_lib = NULL; + lib->l_libname = PyString_AS_STRING(path); + Py_INCREF(path); + lib->l_libname_obj = path; + lib->l_dict = PyDict_New(); + if (lib->l_dict == NULL) { + Py_DECREF(lib); + return NULL; + } + + lib->l_dl_lib = dlopen(lib->l_libname, RTLD_LAZY); + if (lib->l_dl_lib == NULL) { + lib_dlerror(lib); + Py_DECREF(lib); + return NULL; + } + return lib; +} + +static int lib_close(ZefLibObject *lib) +{ + void *dl_lib; + Py_CLEAR(lib->l_dict); + + dl_lib = lib->l_dl_lib; + if (dl_lib != NULL) { + lib->l_dl_lib = NULL; + if (dlclose(dl_lib) != 0) { + lib_dlerror(lib); + return -1; + } + } + return 0; +} diff --git a/zeffir/test/support.py b/zeffir/test/support.py --- a/zeffir/test/support.py +++ b/zeffir/test/support.py @@ -11,9 +11,8 @@ if err: raise OSError("%r\n==> error code %s" % (cmd, err)) -def compile_and_open(modname): - """Process with creflect 'modname.crx', compile the result, and load it.""" +def new_ffi(): if not os.path.exists(zeffir_lib_path): run("cd '%s' && " "gcc -g -I'%s' -Wall -Werror -fPIC -shared zeffir.c -o '%s'" % @@ -24,6 +23,13 @@ import zeffir del sys.path[0] + return zeffir.FFI() + + +def compile_and_open(modname): + """Process with creflect 'modname.crx', compile the result, and load it.""" + + ffi = new_ffi() mod_c_path = str(udir.join('%s.c' % modname)) mod_lib_path = str(udir.join('lib%s.so' % modname)) if not os.path.exists(mod_lib_path): @@ -33,4 +39,5 @@ (zeffir_dir, modname, mod_c_path, mod_c_path, mod_lib_path)) assert os.path.exists(mod_lib_path) - return zeffir.open(modname, relative_to=zeffir_lib_path) + lib = ffi.load_library(modname, relative_to=zeffir_lib_path) + return ffi, lib diff --git a/zeffir/test/test_basic.py b/zeffir/test/test_basic.py --- a/zeffir/test/test_basic.py +++ b/zeffir/test/test_basic.py @@ -1,3 +1,4 @@ +import py import os import support @@ -6,7 +7,7 @@ ffi, lib = support.compile_and_open('basic') assert type(ffi).__module__ == 'zeffir' assert type(ffi).__name__ == 'FFI' - assert repr(ffi) == "" % ( + assert repr(lib) == "" % ( os.path.dirname(support.zeffir_lib_path),) def test_forty_two(): @@ -17,3 +18,7 @@ def test_dir(): ffi, lib = support.compile_and_open('basic') assert dir(lib) == ['forty_two'] + +def test_no_special_attribute(): + ffi, lib = support.compile_and_open('basic') + py.test.raises(AttributeError, getattr, lib, '__class__') diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c --- a/zeffir/zeffir.c +++ b/zeffir/zeffir.c @@ -5,98 +5,21 @@ #include "../creflect/creflect_cdecl.h" -typedef struct _crx_type_s CTypeDescrObject; -typedef struct ZefLibObject_s ZefLibObject; -typedef struct ZefFFIObject_s ZefFFIObject; - - /************************************************************/ /* Works by including all other .c files. */ /* Allows all function and global symbols to remain static. */ -#include "zef_ctype.c" -#include "zef_cdata.c" -#include "zef_ffi_obj.c" -#include "zef_lib_obj.c" -#include "zef_cfunc.c" -#include "zef_builder.c" +#include "zeffir.h" +#include "ctype.c" +#include "cdata.c" +#include "lib_obj.c" +#include "ffi_obj.c" +#include "cfunc.c" +#include "builder.c" /************************************************************/ - -static PyObject *z_open(PyObject *self, PyObject *args, PyObject *kwds) -{ - char *keywords[] = {"libname", "relative_to", NULL}; - char *libname, *relative_to, *relative_dir; - PyObject *path; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", keywords, - &libname, &relative_to)) - return NULL; - - char *last_slash = strrchr(relative_to, '/'); - if (last_slash == NULL) - relative_dir = strdup("."); - else - relative_dir = strndup(relative_to, last_slash - relative_to); - if (relative_dir == NULL) - return PyErr_NoMemory(); - - path = PyString_FromFormat("%s/lib%s.so", relative_dir, libname); - free(relative_dir); - if (path == NULL) - return NULL; - - ZefFFIObject *ffi = NULL; - ZefLibObject *lib = NULL; - PyObject *dict = NULL; - - dlerror(); /* clear errors */ - void *dl_lib = dlopen(PyString_AS_STRING(path), RTLD_LAZY); - if (dl_lib == NULL) { - char *error = dlerror(); - if (error == NULL) - error = "failed to open"; - PyErr_Format(PyExc_OSError, "%s: %s", PyString_AS_STRING(path), error); - goto error; - } - - ffi = PyObject_New(ZefFFIObject, &ZefFFI_Type); - if (ffi == NULL) - goto error; - ffi->f_dl_lib = dl_lib; dl_lib = NULL; - ffi->f_libname = PyString_AS_STRING(path); - ffi->f_libname_obj = path; path = NULL; - - dict = PyDict_New(); - if (dict == NULL) - goto error; - - lib = PyObject_New(ZefLibObject, &ZefLib_Type); - if (lib == NULL) - goto error; - lib->ffi = ffi; ffi = NULL; - lib->l_dict = dict; dict = NULL; - - if (load_creflect_main(lib) < 0) - goto error; - - PyObject *result = Py_BuildValue("OO", lib->ffi, lib); - Py_DECREF(lib); - return result; - - error: - Py_XDECREF(dict); - Py_XDECREF(lib); - Py_XDECREF(ffi); - if (dl_lib != NULL) - dlclose(dl_lib); - Py_XDECREF(path); - return NULL; -} - static PyMethodDef ZeffirMethods[] = { - {"open", (PyCFunction)z_open, METH_KEYWORDS}, {NULL, NULL} /* Sentinel */ }; @@ -106,10 +29,7 @@ PyObject *m; m = Py_InitModule("zeffir", ZeffirMethods); - (void)m; - - init_caches(); - if (PyErr_Occurred()) + if (m == NULL) return; if (PyType_Ready(&ZefFFI_Type) < 0) @@ -120,4 +40,7 @@ return; if (PyType_Ready(&ZefFuncSupport_Type) < 0) return; + + if (PyModule_AddObject(m, "FFI", (PyObject *)&ZefFFI_Type) < 0) + return; } diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h new file mode 100644 --- /dev/null +++ b/zeffir/zeffir.h @@ -0,0 +1,9 @@ + +typedef struct _crx_type_s CTypeDescrObject; +typedef struct ZefLibObject_s ZefLibObject; +typedef struct ZefFFIObject_s ZefFFIObject; + +static PyTypeObject ZefFFI_Type; + +static int lib_close(ZefLibObject *); +static int load_creflect_main(ZefFFIObject *, ZefLibObject *); From noreply at buildbot.pypy.org Mon Dec 1 22:14:29 2014 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 1 Dec 2014 22:14:29 +0100 (CET) Subject: [pypy-commit] creflect default: add minimal test Message-ID: <20141201211429.DA4A21C34C4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r138:26ec90ac79fe Date: 2014-12-01 21:41 +0100 http://bitbucket.org/cffi/creflect/changeset/26ec90ac79fe/ Log: add minimal test diff --git a/zeffir/test/test_basic.py b/zeffir/test/test_basic.py --- a/zeffir/test/test_basic.py +++ b/zeffir/test/test_basic.py @@ -22,3 +22,7 @@ def test_no_special_attribute(): ffi, lib = support.compile_and_open('basic') py.test.raises(AttributeError, getattr, lib, '__class__') + +def test_types(): + ffi = support.new_ffi() + assert ffi.types == {} From noreply at buildbot.pypy.org Mon Dec 1 22:14:31 2014 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 1 Dec 2014 22:14:31 +0100 (CET) Subject: [pypy-commit] creflect default: in-progress: parsing types given in ffi.xyz() Message-ID: <20141201211431.08CED1C34C4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r139:c04b2a53ae95 Date: 2014-12-01 22:14 +0100 http://bitbucket.org/cffi/creflect/changeset/c04b2a53ae95/ Log: in-progress: parsing types given in ffi.xyz() diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -268,3 +268,46 @@ return PyErr_Occurred() ? -1 : 0; } + +static CTypeDescrObject *parse_c_decl(ZefFFIObject *ffi, const char *str) +{ + zeffir_builder_t builder = { + { + zef_get_void_type, + zef_get_char_type, + zef_get_bool_type, + zef_get_signed_type, + zef_get_unsigned_type, + zef_get_float_type, + zef_get_function_type, + zef_get_ellipsis_function_type, + zef_get_pointer_type, + zef_get_array_type, + zef_get_incomplete_array_type, + zef_get_struct_type, + zef_get_union_type, + zef_get_enum_type, + zef_get_user_type, + zef_get_unknown_type, + 0, /* complete */ + 0, /* complete_enum */ + 0, /* define_type */ + 0, /* define_var */ + 0, /* define_func */ + 0, /* define_num_const */ + zef_error, + }, + NULL, /* lib */ + NULL, /* l_dict */ + ffi, /* ffi */ + ffi->types_dict, /* types_dict */ + }; + + _crx_qual_type result; + const char *err = creflect_decl_parser(&builder.cb, str, &result); + if (err != NULL) + abort(); + + Py_INCREF(result.type); + return result.type; +} diff --git a/zeffir/ctype.c b/zeffir/ctype.c --- a/zeffir/ctype.c +++ b/zeffir/ctype.c @@ -81,6 +81,11 @@ return ct; } +static PyObject *ctypedescr_repr(CTypeDescrObject *ct) +{ + return PyString_FromFormat("", ct->ct_name); +} + static void ctypedescr_dealloc(CTypeDescrObject *ct) { PyObject_GC_UnTrack(ct); @@ -109,7 +114,7 @@ static PyTypeObject CTypeDescr_Type = { PyVarObject_HEAD_INIT(NULL, 0) - "_cffi_backend.CTypeDescr", + "zeffir.CType", offsetof(CTypeDescrObject, ct_name), sizeof(char), (destructor)ctypedescr_dealloc, /* tp_dealloc */ @@ -117,7 +122,7 @@ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ - 0,//(reprfunc)ctypedescr_repr, /* tp_repr */ + (reprfunc)ctypedescr_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -108,10 +108,30 @@ return Py_None; } +static PyObject *ffi_typeof(ZefFFIObject *self, PyObject *arg) +{ + if (!PyString_Check(arg)) { + PyErr_SetString(PyExc_TypeError, "XXX"); + return NULL; + } + + PyObject *x = PyDict_GetItem(self->types_dict, arg); + if (x != NULL) { + Py_INCREF(x); + return x; + } + + x = (PyObject *)parse_c_decl(self, PyString_AS_STRING(arg)); + if (x != NULL) + PyDict_SetItem(self->types_dict, arg, x); + return x; +} + static PyMethodDef ffi_methods[] = { - {"load_library", (PyCFunction)ffi_load_library, - METH_VARARGS | METH_KEYWORDS}, - {"close_library", ffi_close_library, METH_VARARGS | METH_STATIC}, + {"close_library", ffi_close_library, METH_VARARGS | METH_STATIC}, + {"load_library", (PyCFunction)ffi_load_library, + METH_VARARGS | METH_KEYWORDS}, + {"typeof", (PyCFunction)ffi_typeof, METH_O}, {NULL} }; diff --git a/zeffir/lib_obj.c b/zeffir/lib_obj.c --- a/zeffir/lib_obj.c +++ b/zeffir/lib_obj.c @@ -28,8 +28,7 @@ static PyObject *lib_getattr(ZefLibObject *lib, PyObject *name) { if (lib->l_dict == NULL) { - PyErr_Format(PyExc_ValueError, "lib '%.200s' was closed", - lib->l_libname); + PyErr_Format(ZefError, "lib '%.200s' was closed", lib->l_libname); return NULL; } diff --git a/zeffir/test/test_ctype.py b/zeffir/test/test_ctype.py new file mode 100644 --- /dev/null +++ b/zeffir/test/test_ctype.py @@ -0,0 +1,8 @@ +import support + + +def test_typeof(): + ffi = support.new_ffi() + assert repr(ffi.typeof("int")) == "" + assert repr(ffi.typeof("long int")) == "" + #assert repr(ffi.typeof("int*")) == "" diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c --- a/zeffir/zeffir.c +++ b/zeffir/zeffir.c @@ -16,6 +16,7 @@ #include "ffi_obj.c" #include "cfunc.c" #include "builder.c" +#include "../creflect/creflect_cdecl.c" /************************************************************/ @@ -43,4 +44,13 @@ if (PyModule_AddObject(m, "FFI", (PyObject *)&ZefFFI_Type) < 0) return; + if (PyModule_AddObject(m, "CType", (PyObject *)&CTypeDescr_Type) < 0) + return; + + ZefError = PyErr_NewException("zeffir.error", NULL, NULL); + if (ZefError == NULL) + return; + Py_INCREF(ZefError); + if (PyModule_AddObject(m, "error", ZefError) < 0) + return; } diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h --- a/zeffir/zeffir.h +++ b/zeffir/zeffir.h @@ -5,5 +5,8 @@ static PyTypeObject ZefFFI_Type; +static PyObject *ZefError; + static int lib_close(ZefLibObject *); static int load_creflect_main(ZefFFIObject *, ZefLibObject *); +static CTypeDescrObject *parse_c_decl(ZefFFIObject *ffi, const char *str); From noreply at buildbot.pypy.org Tue Dec 2 12:52:31 2014 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 2 Dec 2014 12:52:31 +0100 (CET) Subject: [pypy-commit] pypy ufuncapi: move implementation-level methods to base file to simplify circular imports Message-ID: <20141202115231.356F31C3581@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: ufuncapi Changeset: r74780:34c0bc5ac7e8 Date: 2014-12-02 13:50 +0200 http://bitbucket.org/pypy/pypy/changeset/34c0bc5ac7e8/ Log: move implementation-level methods to base file to simplify circular imports diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -25,6 +25,7 @@ class W_NDimArray(W_NumpyObject): __metaclass__ = extendabletype + _immutable_fields_ = ['implementation'] def __init__(self, implementation): from pypy.module.micronumpy.concrete import BaseConcreteArray @@ -98,6 +99,19 @@ w_arr.set_scalar_value(w_scalar) return w_arr + def get_shape(self): + return self.implementation.get_shape() + + def get_dtype(self): + return self.implementation.dtype + + def get_order(self): + return self.implementation.order + + def ndims(self): + return len(self.get_shape()) + ndims._always_inline_ = True + def convert_to_array(space, w_obj): from pypy.module.micronumpy.ctors import array diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -50,9 +50,6 @@ shape = self.get_shape() return space.newtuple([space.wrap(i) for i in shape]) - def get_shape(self): - return self.implementation.get_shape() - def descr_set_shape(self, space, w_new_shape): shape = get_shape_from_iterable(space, self.get_size(), w_new_shape) self.implementation = self.implementation.set_shape(space, self, shape) @@ -61,12 +58,6 @@ strides = self.implementation.get_strides() return space.newtuple([space.wrap(i) for i in strides]) - def get_dtype(self): - return self.implementation.dtype - - def get_order(self): - return self.implementation.order - def descr_get_dtype(self, space): return self.implementation.dtype @@ -83,10 +74,6 @@ raise OperationError(space.w_AttributeError, space.wrap( "Cannot delete array dtype")) - def ndims(self): - return len(self.get_shape()) - ndims._always_inline_ = True - def descr_get_ndim(self, space): return space.wrap(self.ndims()) From noreply at buildbot.pypy.org Tue Dec 2 12:52:32 2014 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 2 Dec 2014 12:52:32 +0100 (CET) Subject: [pypy-commit] pypy ufuncapi: pass resolver tests, still need to use results in creating output arrays Message-ID: <20141202115232.82F3D1C3581@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: ufuncapi Changeset: r74781:af2cb61cc4b1 Date: 2014-12-02 13:50 +0200 http://bitbucket.org/pypy/pypy/changeset/af2cb61cc4b1/ Log: pass resolver tests, still need to use results in creating output arrays diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -108,18 +108,25 @@ def test_type_resolver(self, space): c128_dtype = get_dtype_cache(space).w_complex128dtype + c64_dtype = get_dtype_cache(space).w_complex64dtype f64_dtype = get_dtype_cache(space).w_float64dtype + f32_dtype = get_dtype_cache(space).w_float32dtype u32_dtype = get_dtype_cache(space).w_uint32dtype b_dtype = get_dtype_cache(space).w_booldtype - ufunc = W_UfuncGeneric(space, [None, None], 'eigenvals', None, 1, 1, - [f64_dtype, c128_dtype, c128_dtype, c128_dtype], + ufunc = W_UfuncGeneric(space, [None, None, None], 'eigenvals', None, 1, 1, + [f32_dtype, c64_dtype, + f64_dtype, c128_dtype, + c128_dtype, c128_dtype], '') - f64 = W_NDimArray(VoidBoxStorage(0, f64_dtype)) - c128 = W_NDimArray(VoidBoxStorage(0, c128_dtype)) - index, dtypes = ufunc.type_resolver(space, [f64], [c128], 'd->D') + f32_array = W_NDimArray(VoidBoxStorage(0, f32_dtype)) + index, dtypes = ufunc.type_resolver(space, [f32_array], [None], 'd->D') + #needs to cast input type, create output type + assert index == 1 + assert dtypes == [f64_dtype, c128_dtype] + index, dtypes = ufunc.type_resolver(space, [f32_array], [None], '') assert index == 0 - assert dtypes == [f64_dtype, c128_dtype] + assert dtypes == [f32_dtype, c64_dtype] class AppTestUfuncs(BaseNumpyAppTest): diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -6,7 +6,9 @@ from rpython.rlib import jit from rpython.rlib.rarithmetic import LONG_BIT, maxint from rpython.tool.sourcetools import func_with_new_name -from pypy.module.micronumpy import boxes, descriptor, loop, constants as NPY +from pypy.module.micronumpy import boxes, loop, constants as NPY +from pypy.module.micronumpy.descriptor import (get_dtype_cache, + variable_dtype, decode_w_dtype) from pypy.module.micronumpy.base import convert_to_array, W_NDimArray from pypy.module.micronumpy.ctors import numpify from pypy.module.micronumpy.nditer import W_NDIter, coalesce_iter @@ -201,10 +203,10 @@ if axis < 0: axis += shapelen assert axis >= 0 - dtype = descriptor.decode_w_dtype(space, dtype) + dtype = decode_w_dtype(space, dtype) if dtype is None: if self.comparison_func: - dtype = descriptor.get_dtype_cache(space).w_booldtype + dtype = get_dtype_cache(space).w_booldtype else: dtype = find_unaryop_result_dtype( space, obj.get_dtype(), @@ -360,14 +362,14 @@ # raise oefmt(space.w_TypeError, # "Cannot cast ufunc %s output from dtype('%s') to dtype('%s') with casting rule 'same_kind'", self.name, w_obj.get_dtype().name, res_dtype.name) elif self.bool_result: - res_dtype = descriptor.get_dtype_cache(space).w_booldtype + res_dtype = get_dtype_cache(space).w_booldtype else: res_dtype = calc_dtype if self.complex_to_float and calc_dtype.is_complex(): if calc_dtype.num == NPY.CFLOAT: - res_dtype = descriptor.get_dtype_cache(space).w_float32dtype + res_dtype = get_dtype_cache(space).w_float32dtype else: - res_dtype = descriptor.get_dtype_cache(space).w_float64dtype + res_dtype = get_dtype_cache(space).w_float64dtype if w_obj.is_scalar(): w_val = self.func(calc_dtype, w_obj.get_scalar_value().convert_to(space, calc_dtype)) @@ -474,7 +476,7 @@ out = w_out calc_dtype = out.get_dtype() if self.comparison_func: - res_dtype = descriptor.get_dtype_cache(space).w_booldtype + res_dtype = get_dtype_cache(space).w_booldtype else: res_dtype = calc_dtype if w_lhs.is_scalar() and w_rhs.is_scalar(): @@ -559,6 +561,7 @@ self.name, self.nin, len(args_w)) for i in range(self.nin): inargs[i] = convert_to_array(space, args_w[i]) + assert isinstance(inargs[i], W_NDimArray) outargs = [None] * self.nout for i in range(len(args_w)-self.nin): out = args_w[i+self.nin] @@ -784,7 +787,7 @@ if sig: raise oefmt(space.w_RuntimeError, "cannot specify both 'sig' and 'dtype'") - dtype = descriptor.decode_w_dtype(space, dtype_w) + dtype = decode_w_dtype(space, dtype_w) sig = space.newtuple([dtype]) order = kwargs_w.pop('dtype', None) if not space.is_w(order, space.w_None) and not order is None: @@ -810,32 +813,54 @@ # linear_search_type_resolver in numpy ufunc_type_resolutions.c # type_tup can be '', a tuple of dtypes, or a string # of the form d,t -> D where the letters are dtype specs - inargs0 = inargs[0] - assert isinstance(inargs0, W_NDimArray) nop = len(inargs) + len(outargs) dtypes = [] - if isinstance(type_tup, str): + if isinstance(type_tup, str) and len(type_tup) > 0: if len(type_tup) == 1: dtypes = [get_dtype_cache(space).dtypes_by_name[type_tup]] * self.nargs elif len(type_tup) == self.nargs + 2: - for i in range(len(inargs)): - dtypes.append(get_dtype_cache(space).dtype_by_name[type_tup[i]]) + for i in range(self.nin): + dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[i]]) #skip the '->' in the signature - for i in range(len(self.nout)): - dtypes.append(get_dtype_cache(space).dtype_by_name[type_tup[i+2]]) + for i in range(self.nout): + j = i + self.nin + 2 + dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[j]]) else: - raise oefmt(space.w_TypeError, "a type-string for %s," \ + raise oefmt(space.w_TypeError, "a type-string for %s " \ "requires 1 typecode or %d typecode(s) before and %d" \ - " after the -> sign", self.name, self.nin, self.nout) + " after the -> sign, not '%s'", self.name, self.nin, + self.nout, type_tup) + else: + # XXX does not pass translation + # dtypes = [i.get_dtype() for i in inargs] + for i in inargs: + if isinstance(i, W_NDimArray): + dtypes.append(i.get_dtype()) + else: + dtypes.append(None) + for i in outargs: + if isinstance(i, W_NDimArray): + dtypes.append(i.get_dtype()) + else: + dtypes.append(None) + #Find the first matchup of dtypes with self.dtypes for i in range(0, len(self.dtypes), self.nargs): - if inargs0.get_dtype() == self.dtypes[i]: + allok = True + for j in range(self.nargs): + if dtypes[j] is not None and dtypes[j] != self.dtypes[i+j]: + allok = False + if allok: break else: if len(self.funcs) < 2: return 0, dtypes raise oefmt(space.w_TypeError, - 'input dtype %s did not match any known dtypes', - str(inargs0.get_dtype())) + 'input dtype did not match any known dtypes', + ) + # Fill in empty dtypes + for j in range(self.nargs): + if dtypes[j] is None: + dtypes[j] = self.dtypes[i+j] return i / self.nargs, dtypes def alloc_outargs(self, space, index, inargs, outargs, dtypes): @@ -880,7 +905,7 @@ dt1, dt2 = dt2, dt1 # Some operations promote op(bool, bool) to return int8, rather than bool if promote_bools and (dt1.kind == dt2.kind == NPY.GENBOOLLTR): - return descriptor.get_dtype_cache(space).w_int8dtype + return get_dtype_cache(space).w_int8dtype # Everything numeric promotes to complex if dt2.is_complex() or dt1.is_complex(): @@ -888,16 +913,16 @@ dt1, dt2 = dt2, dt1 if dt2.num == NPY.CFLOAT: if dt1.num == NPY.DOUBLE: - return descriptor.get_dtype_cache(space).w_complex128dtype + return get_dtype_cache(space).w_complex128dtype elif dt1.num == NPY.LONGDOUBLE: - return descriptor.get_dtype_cache(space).w_complexlongdtype - return descriptor.get_dtype_cache(space).w_complex64dtype + return get_dtype_cache(space).w_complexlongdtype + return get_dtype_cache(space).w_complex64dtype elif dt2.num == NPY.CDOUBLE: if dt1.num == NPY.LONGDOUBLE: - return descriptor.get_dtype_cache(space).w_complexlongdtype - return descriptor.get_dtype_cache(space).w_complex128dtype + return get_dtype_cache(space).w_complexlongdtype + return get_dtype_cache(space).w_complex128dtype elif dt2.num == NPY.CLONGDOUBLE: - return descriptor.get_dtype_cache(space).w_complexlongdtype + return get_dtype_cache(space).w_complexlongdtype else: raise OperationError(space.w_TypeError, space.wrap("Unsupported types")) @@ -912,11 +937,11 @@ # Everything promotes to float, and bool promotes to everything. if dt2.kind == NPY.FLOATINGLTR or dt1.kind == NPY.GENBOOLLTR: if dt2.num == NPY.HALF and dt1.itemtype.get_element_size() == 2: - return descriptor.get_dtype_cache(space).w_float32dtype + return get_dtype_cache(space).w_float32dtype if dt2.num == NPY.HALF and dt1.itemtype.get_element_size() >= 4: - return descriptor.get_dtype_cache(space).w_float64dtype + return get_dtype_cache(space).w_float64dtype if dt2.num == NPY.FLOAT and dt1.itemtype.get_element_size() >= 4: - return descriptor.get_dtype_cache(space).w_float64dtype + return get_dtype_cache(space).w_float64dtype return dt2 # for now this means mixing signed and unsigned @@ -942,7 +967,7 @@ else: # increase to the next signed type dtypenum = dt2.num + 1 - newdtype = descriptor.get_dtype_cache(space).dtypes_by_num[dtypenum] + newdtype = get_dtype_cache(space).dtypes_by_num[dtypenum] if (newdtype.itemtype.get_element_size() > dt2.itemtype.get_element_size() or newdtype.kind == NPY.FLOATINGLTR): @@ -951,7 +976,7 @@ # we only promoted to long on 32-bit or to longlong on 64-bit # this is really for dealing with the Long and Ulong dtypes dtypenum += 2 - return descriptor.get_dtype_cache(space).dtypes_by_num[dtypenum] + return get_dtype_cache(space).dtypes_by_num[dtypenum] @jit.unroll_safe @@ -960,21 +985,21 @@ if promote_to_largest: if dt.kind == NPY.GENBOOLLTR or dt.kind == NPY.SIGNEDLTR: if dt.elsize * 8 < LONG_BIT: - return descriptor.get_dtype_cache(space).w_longdtype + return get_dtype_cache(space).w_longdtype elif dt.kind == NPY.UNSIGNEDLTR: if dt.elsize * 8 < LONG_BIT: - return descriptor.get_dtype_cache(space).w_ulongdtype + return get_dtype_cache(space).w_ulongdtype else: assert dt.kind == NPY.FLOATINGLTR or dt.kind == NPY.COMPLEXLTR return dt if promote_bools and (dt.kind == NPY.GENBOOLLTR): - return descriptor.get_dtype_cache(space).w_int8dtype + return get_dtype_cache(space).w_int8dtype if promote_to_float: if dt.kind == NPY.FLOATINGLTR or dt.kind == NPY.COMPLEXLTR: return dt if dt.num >= NPY.INT: - return descriptor.get_dtype_cache(space).w_float64dtype - for bytes, dtype in descriptor.get_dtype_cache(space).float_dtypes_by_num_bytes: + return get_dtype_cache(space).w_float64dtype + for bytes, dtype in get_dtype_cache(space).float_dtypes_by_num_bytes: if (dtype.kind == NPY.FLOATINGLTR and dtype.itemtype.get_element_size() > dt.itemtype.get_element_size()): @@ -983,12 +1008,12 @@ def find_dtype_for_scalar(space, w_obj, current_guess=None): - bool_dtype = descriptor.get_dtype_cache(space).w_booldtype - long_dtype = descriptor.get_dtype_cache(space).w_longdtype - int64_dtype = descriptor.get_dtype_cache(space).w_int64dtype - uint64_dtype = descriptor.get_dtype_cache(space).w_uint64dtype - complex_dtype = descriptor.get_dtype_cache(space).w_complex128dtype - float_dtype = descriptor.get_dtype_cache(space).w_float64dtype + bool_dtype = get_dtype_cache(space).w_booldtype + long_dtype = get_dtype_cache(space).w_longdtype + int64_dtype = get_dtype_cache(space).w_int64dtype + uint64_dtype = get_dtype_cache(space).w_uint64dtype + complex_dtype = get_dtype_cache(space).w_complex128dtype + float_dtype = get_dtype_cache(space).w_float64dtype if isinstance(w_obj, boxes.W_GenericBox): dtype = w_obj.get_dtype(space) return find_binop_result_dtype(space, dtype, current_guess) @@ -1012,11 +1037,11 @@ return complex_dtype elif space.isinstance_w(w_obj, space.w_str): if current_guess is None: - return descriptor.variable_dtype(space, + return variable_dtype(space, 'S%d' % space.len_w(w_obj)) elif current_guess.num == NPY.STRING: if current_guess.elsize < space.len_w(w_obj): - return descriptor.variable_dtype(space, + return variable_dtype(space, 'S%d' % space.len_w(w_obj)) return current_guess raise oefmt(space.w_NotImplementedError, @@ -1033,7 +1058,7 @@ raise oefmt(space.w_NotImplementedError, "%s not implemented for %s", ufunc_name, dtype.get_name()) - dtype_cache = descriptor.get_dtype_cache(space) + dtype_cache = get_dtype_cache(space) if nin == 1: def impl(res_dtype, value): res = get_op(res_dtype)(value) @@ -1162,7 +1187,7 @@ identity = extra_kwargs.get("identity") if identity is not None: identity = \ - descriptor.get_dtype_cache(space).w_longdtype.box(identity) + get_dtype_cache(space).w_longdtype.box(identity) extra_kwargs["identity"] = identity func = ufunc_dtype_caller(space, ufunc_name, op_name, nin, @@ -1264,7 +1289,7 @@ else: dtypes = [None]*len(_dtypes) for i in range(len(dtypes)): - dtypes[i] = descriptor.decode_w_dtype(space, _dtypes[i]) + dtypes[i] = decode_w_dtype(space, _dtypes[i]) else: raise oefmt(space.w_ValueError, 'dtypes must be None or a list of dtypes') @@ -1273,7 +1298,7 @@ identity = None elif space.isinstance_w(w_identity, space.w_int): identity = \ - descriptor.get_dtype_cache(space).w_longdtype.box(space.int_w(w_identity)) + get_dtype_cache(space).w_longdtype.box(space.int_w(w_identity)) else: raise oefmt(space.w_ValueError, 'identity must be None or an int') From noreply at buildbot.pypy.org Tue Dec 2 14:31:03 2014 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 2 Dec 2014 14:31:03 +0100 (CET) Subject: [pypy-commit] pypy default: implement strides argument when buffer=something for ndarray constructor, Message-ID: <20141202133103.EB8471D2A97@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r74782:86fcd1d9f5df Date: 2014-12-02 15:29 +0200 http://bitbucket.org/pypy/pypy/changeset/86fcd1d9f5df/ Log: implement strides argument when buffer=something for ndarray constructor, also for from_shape_and_storage diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -44,11 +44,16 @@ return W_NDimArray(impl) @staticmethod - def from_shape_and_storage(space, shape, storage, dtype, order='C', owning=False, - w_subtype=None, w_base=None, writable=True): + def from_shape_and_storage(space, shape, storage, dtype, order='C', + owning=False, w_subtype=None, w_base=None, + writable=True, strides=None): from pypy.module.micronumpy import concrete - from pypy.module.micronumpy.strides import calc_strides - strides, backstrides = calc_strides(shape, dtype, order) + from pypy.module.micronumpy.strides import (calc_strides, + calc_backstrides) + if strides is None: + strides, backstrides = calc_strides(shape, dtype, order) + else: + backstrides = calc_backstrides(strides, shape) if w_base is not None: if owning: raise OperationError(space.w_ValueError, diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -11,7 +11,7 @@ from pypy.module.micronumpy.iterators import ArrayIter from pypy.module.micronumpy.strides import (Chunk, Chunks, NewAxisChunk, RecordChunk, calc_strides, calc_new_strides, shape_agreement, - calculate_broadcast_strides) + calculate_broadcast_strides, calc_backstrides) class BaseConcreteArray(object): @@ -79,10 +79,7 @@ self.get_strides(), self.order) if new_strides is not None: # We can create a view, strides somehow match up. - ndims = len(new_shape) - new_backstrides = [0] * ndims - for nd in range(ndims): - new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd] + new_backstrides = calc_backstrides(new_strides, new_shape) assert isinstance(orig_array, W_NDimArray) or orig_array is None return SliceArray(self.start, new_strides, new_backstrides, new_shape, self, orig_array) diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -1213,8 +1213,10 @@ if not space.is_none(w_buffer): if (not space.is_none(w_strides)): - raise OperationError(space.w_NotImplementedError, - space.wrap("unsupported param")) + strides = [space.int_w(w_i) for w_i in + space.unpackiterable(w_strides)] + else: + strides = None try: buf = space.writebuf_w(w_buffer) @@ -1237,7 +1239,8 @@ return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, w_subtype=w_subtype, w_base=w_buffer, - writable=not buf.readonly) + writable=not buf.readonly, + strides=strides) order = order_converter(space, w_order, NPY.CORDER) if order == NPY.CORDER: @@ -1256,7 +1259,7 @@ @unwrap_spec(addr=int) -def descr__from_shape_and_storage(space, w_cls, w_shape, addr, w_dtype, w_subtype=None): +def descr__from_shape_and_storage(space, w_cls, w_shape, addr, w_dtype, w_subtype=None, w_strides=None): """ Create an array from an existing buffer, given its address as int. PyPy-only implementation detail. @@ -1265,14 +1268,21 @@ dtype = space.interp_w(descriptor.W_Dtype, space.call_function( space.gettypefor(descriptor.W_Dtype), w_dtype)) shape = shape_converter(space, w_shape, dtype) + if not space.is_none(w_strides): + strides = [space.int_w(w_i) for w_i in + space.unpackiterable(w_strides)] + else: + strides = None if w_subtype: if not space.isinstance_w(w_subtype, space.w_type): raise OperationError(space.w_ValueError, space.wrap( "subtype must be a subtype of ndarray, not a class instance")) return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, - 'C', False, w_subtype) + 'C', False, w_subtype, + strides=strides) else: - return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype) + return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, + strides=strides) app_take = applevel(r""" def take(a, indices, axis, out, mode): diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py --- a/pypy/module/micronumpy/strides.py +++ b/pypy/module/micronumpy/strides.py @@ -362,6 +362,13 @@ backstrides.reverse() return strides, backstrides + at jit.unroll_safe +def calc_backstrides(strides, shape): + ndims = len(shape) + new_backstrides = [0] * ndims + for nd in range(ndims): + new_backstrides[nd] = (shape[nd] - 1) * strides[nd] + return new_backstrides # Recalculating strides. Find the steps that the iteration does for each # dimension, given the stride and shape. Then try to create a new stride that diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -3926,3 +3926,27 @@ assert x.__pypy_data__ is obj del x.__pypy_data__ assert x.__pypy_data__ is None + + def test_ndarray_buffer_strides(self): + from numpypy import ndarray, array + base = array([1, 2, 3, 4], dtype=int) + a = ndarray((4,), buffer=base, dtype=int) + assert a[1] == 2 + a = ndarray((4,), buffer=base, dtype=int, strides=[base.strides[0]]) + assert a[1] == 2 + a = ndarray((4,), buffer=base, dtype=int, strides=[2 * base.strides[0]]) + assert a[1] == 3 + + def test_from_shape_and_storage_strides(self): + from numpypy import ndarray, array + base = array([1, 2, 3, 4], dtype=int) + addr, _ = base.__array_interface__['data'] + a = ndarray._from_shape_and_storage((4,), addr, int) + assert a[1] == 2 + a = ndarray._from_shape_and_storage((4,), addr, int, + strides=[base.strides[0]]) + assert a[1] == 2 + a = ndarray._from_shape_and_storage((4,), addr, int, + strides=[2 * base.strides[0]]) + assert a[1] == 3 + From noreply at buildbot.pypy.org Tue Dec 2 17:54:55 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Tue, 2 Dec 2014 17:54:55 +0100 (CET) Subject: [pypy-commit] pypy default: add failing test for int_signext case Message-ID: <20141202165455.C62F91D2A97@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74783:a48527cf9df5 Date: 2014-12-02 11:54 -0500 http://bitbucket.org/pypy/pypy/changeset/a48527cf9df5/ Log: add failing test for int_signext case diff --git a/rpython/jit/metainterp/test/test_ajit.py b/rpython/jit/metainterp/test/test_ajit.py --- a/rpython/jit/metainterp/test/test_ajit.py +++ b/rpython/jit/metainterp/test/test_ajit.py @@ -3068,8 +3068,12 @@ def test_int_signext(self): def f(n): return rffi.cast(rffi.SIGNEDCHAR, n) + def f1(n): + return rffi.cast(rffi.SIGNEDCHAR, n + 1) res = self.interp_operations(f, [128]) assert res == -128 + res = self.interp_operations(f1, [127]) + assert res == -128 res = self.interp_operations(f, [-35 + 256 * 29]) assert res == -35 res = self.interp_operations(f, [127 - 256 * 29]) From noreply at buildbot.pypy.org Tue Dec 2 18:15:09 2014 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 2 Dec 2014 18:15:09 +0100 (CET) Subject: [pypy-commit] pypy default: move test so it runs (fails) with -A Message-ID: <20141202171509.AAC521C142A@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r74784:7b945fce0e06 Date: 2014-12-02 15:59 +0200 http://bitbucket.org/pypy/pypy/changeset/7b945fce0e06/ Log: move test so it runs (fails) with -A diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -3416,6 +3416,17 @@ assert str(array(1.5)) == '1.5' assert str(array(1.5).real) == '1.5' + def test_ndarray_buffer_strides(self): + from numpy import ndarray, array + base = array([1, 2, 3, 4], dtype=int) + a = ndarray((4,), buffer=base, dtype=int) + assert a[1] == 2 + a = ndarray((4,), buffer=base, dtype=int, strides=[base.strides[0]]) + assert a[1] == 2 + a = ndarray((4,), buffer=base, dtype=int, strides=[2 * base.strides[0]]) + assert a[1] == 3 + + class AppTestRepr(BaseNumpyAppTest): def setup_class(cls): @@ -3883,6 +3894,7 @@ assert np.greater(a, a) is NotImplemented assert np.less_equal(a, a) is NotImplemented + class AppTestPyPy(BaseNumpyAppTest): def setup_class(cls): if option.runappdirect and '__pypy__' not in sys.builtin_module_names: @@ -3927,18 +3939,8 @@ del x.__pypy_data__ assert x.__pypy_data__ is None - def test_ndarray_buffer_strides(self): - from numpypy import ndarray, array - base = array([1, 2, 3, 4], dtype=int) - a = ndarray((4,), buffer=base, dtype=int) - assert a[1] == 2 - a = ndarray((4,), buffer=base, dtype=int, strides=[base.strides[0]]) - assert a[1] == 2 - a = ndarray((4,), buffer=base, dtype=int, strides=[2 * base.strides[0]]) - assert a[1] == 3 - def test_from_shape_and_storage_strides(self): - from numpypy import ndarray, array + from numpy import ndarray, array base = array([1, 2, 3, 4], dtype=int) addr, _ = base.__array_interface__['data'] a = ndarray._from_shape_and_storage((4,), addr, int) @@ -3949,4 +3951,3 @@ a = ndarray._from_shape_and_storage((4,), addr, int, strides=[2 * base.strides[0]]) assert a[1] == 3 - From noreply at buildbot.pypy.org Tue Dec 2 18:15:11 2014 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 2 Dec 2014 18:15:11 +0100 (CET) Subject: [pypy-commit] pypy default: check strides, shape agains buf_len when creating array with a buffer Message-ID: <20141202171511.195F81C142A@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r74785:46e91c62f6b8 Date: 2014-12-02 19:13 +0200 http://bitbucket.org/pypy/pypy/changeset/46e91c62f6b8/ Log: check strides, shape agains buf_len when creating array with a buffer diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -1,7 +1,7 @@ from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, oefmt from rpython.tool.pairtype import extendabletype - +from pypy.module.micronumpy import support def wrap_impl(space, w_cls, w_instance, impl): if w_cls is None or space.is_w(w_cls, space.gettypefor(W_NDimArray)): @@ -44,15 +44,31 @@ return W_NDimArray(impl) @staticmethod - def from_shape_and_storage(space, shape, storage, dtype, order='C', - owning=False, w_subtype=None, w_base=None, - writable=True, strides=None): + def from_shape_and_storage(space, shape, storage, dtype, storage_bytes=-1, + order='C', owning=False, w_subtype=None, + w_base=None, writable=True, strides=None): from pypy.module.micronumpy import concrete from pypy.module.micronumpy.strides import (calc_strides, calc_backstrides) + isize = dtype.elsize + if storage_bytes > 0 : + totalsize = support.product(shape) * isize + if totalsize > storage_bytes: + raise OperationError(space.w_TypeError, space.wrap( + "buffer is too small for requested array")) + else: + storage_bytes = support.product(shape) * isize if strides is None: strides, backstrides = calc_strides(shape, dtype, order) else: + if len(strides) != len(shape): + raise oefmt(space.w_ValueError, + 'strides, if given, must be the same length as shape') + for i in range(len(strides)): + if strides[i] < 0 or strides[i]*shape[i] > storage_bytes: + raise oefmt(space.w_ValueError, + 'strides is incompatible with shape of requested ' + 'array and size of buffer') backstrides = calc_backstrides(strides, shape) if w_base is not None: if owning: diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py --- a/pypy/module/micronumpy/ctors.py +++ b/pypy/module/micronumpy/ctors.py @@ -302,5 +302,5 @@ return a else: writable = not buf.readonly - return W_NDimArray.from_shape_and_storage(space, [n], storage, dtype=dtype, - w_base=w_buffer, writable=writable) + return W_NDimArray.from_shape_and_storage(space, [n], storage, storage_bytes=s, + dtype=dtype, w_base=w_buffer, writable=writable) diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -529,9 +529,10 @@ "__array__(dtype) not implemented")) if type(self) is W_NDimArray: return self + sz = support.product(self.get_shape()) * self.get_dtype().elsize return W_NDimArray.from_shape_and_storage( space, self.get_shape(), self.implementation.storage, - self.get_dtype(), w_base=self) + self.get_dtype(), storage_bytes=sz, w_base=self) def descr_array_iface(self, space): addr = self.implementation.get_storage_as_int(space) @@ -1188,8 +1189,8 @@ "improper dtype '%R'", dtype) self.implementation = W_NDimArray.from_shape_and_storage( space, [space.int_w(i) for i in space.listview(shape)], - rffi.str2charp(space.str_w(storage), track_allocation=False), - dtype, owning=True).implementation + rffi.str2charp(space.str_w(storage), track_allocation=False), + dtype, storage_bytes=space.len_w(storage), owning=True).implementation def descr___array_finalize__(self, space, w_obj): pass @@ -1230,15 +1231,12 @@ if not shape: raise OperationError(space.w_TypeError, space.wrap( "numpy scalars from buffers not supported yet")) - totalsize = support.product(shape) * dtype.elsize - if totalsize + offset > buf.getlength(): - raise OperationError(space.w_TypeError, space.wrap( - "buffer is too small for requested array")) storage = rffi.cast(RAW_STORAGE_PTR, raw_ptr) storage = rffi.ptradd(storage, offset) - return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, + return W_NDimArray.from_shape_and_storage(space, shape, storage, + dtype, w_base=w_buffer, + storage_bytes=buf.getlength()-offset, w_subtype=w_subtype, - w_base=w_buffer, writable=not buf.readonly, strides=strides) @@ -1258,9 +1256,12 @@ return w_ret - at unwrap_spec(addr=int) -def descr__from_shape_and_storage(space, w_cls, w_shape, addr, w_dtype, w_subtype=None, w_strides=None): + at unwrap_spec(addr=int, buf_len=int) +def descr__from_shape_and_storage(space, w_cls, w_shape, addr, w_dtype, + buf_len=-1, w_subtype=None, w_strides=None): """ + _from_shape_and_storage(shape, addr, dtype, buf_len, + subtype=None, strides=None) Create an array from an existing buffer, given its address as int. PyPy-only implementation detail. """ @@ -1278,10 +1279,11 @@ raise OperationError(space.w_ValueError, space.wrap( "subtype must be a subtype of ndarray, not a class instance")) return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, - 'C', False, w_subtype, + buf_len, 'C', False, w_subtype, strides=strides) else: return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, + storage_bytes=buf_len, strides=strides) app_take = applevel(r""" diff --git a/pypy/module/micronumpy/test/test_ndarray.py b/pypy/module/micronumpy/test/test_ndarray.py --- a/pypy/module/micronumpy/test/test_ndarray.py +++ b/pypy/module/micronumpy/test/test_ndarray.py @@ -186,7 +186,8 @@ # dtypes = get_dtype_cache(self.space) w_array = W_NDimArray.from_shape_and_storage(self.space, [2, 2], - storage, dtypes.w_int8dtype) + storage, dtypes.w_int8dtype, + storage_bytes=4) def get(i, j): return w_array.getitem(self.space, [i, j]).value assert get(0, 0) == 0 @@ -3423,8 +3424,12 @@ assert a[1] == 2 a = ndarray((4,), buffer=base, dtype=int, strides=[base.strides[0]]) assert a[1] == 2 - a = ndarray((4,), buffer=base, dtype=int, strides=[2 * base.strides[0]]) + a = ndarray((2,), buffer=base, dtype=int, strides=[2 * base.strides[0]]) assert a[1] == 3 + exc = raises(ValueError, ndarray, (4,), buffer=base, dtype=int, strides=[2 * base.strides[0]]) + assert exc.value[0] == 'strides is incompatible with shape of requested array and size of buffer' + exc = raises(ValueError, ndarray, (2, 1), buffer=base, dtype=int, strides=[base.strides[0]]) + assert exc.value[0] == 'strides, if given, must be the same length as shape' @@ -3918,13 +3923,14 @@ from numpypy import array, ndarray x = array([1, 2, 3, 4]) addr, _ = x.__array_interface__['data'] - y = ndarray._from_shape_and_storage([2, 2], addr, x.dtype) + sz = x.size * x.dtype.itemsize + y = ndarray._from_shape_and_storage([2, 2], addr, x.dtype, sz) assert y[0, 1] == 2 y[0, 1] = 42 assert x[1] == 42 class C(ndarray): pass - z = ndarray._from_shape_and_storage([4, 1], addr, x.dtype, C) + z = ndarray._from_shape_and_storage([4, 1], addr, x.dtype, sz, C) assert isinstance(z, C) assert z.shape == (4, 1) assert z[1, 0] == 42 @@ -3943,11 +3949,12 @@ from numpy import ndarray, array base = array([1, 2, 3, 4], dtype=int) addr, _ = base.__array_interface__['data'] - a = ndarray._from_shape_and_storage((4,), addr, int) + sz = base.size * base.dtype.itemsize + a = ndarray._from_shape_and_storage((4,), addr, int, sz) assert a[1] == 2 - a = ndarray._from_shape_and_storage((4,), addr, int, + a = ndarray._from_shape_and_storage((4,), addr, int, sz, strides=[base.strides[0]]) assert a[1] == 2 - a = ndarray._from_shape_and_storage((4,), addr, int, + a = ndarray._from_shape_and_storage((2,), addr, int, sz, strides=[2 * base.strides[0]]) assert a[1] == 3 From noreply at buildbot.pypy.org Tue Dec 2 18:32:24 2014 From: noreply at buildbot.pypy.org (mattip) Date: Tue, 2 Dec 2014 18:32:24 +0100 (CET) Subject: [pypy-commit] pypy default: overzelous docstring removed Message-ID: <20141202173224.4AF6F1D28F0@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: Changeset: r74786:8471ffc38d46 Date: 2014-12-02 19:32 +0200 http://bitbucket.org/pypy/pypy/changeset/8471ffc38d46/ Log: overzelous docstring removed diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -1260,8 +1260,6 @@ def descr__from_shape_and_storage(space, w_cls, w_shape, addr, w_dtype, buf_len=-1, w_subtype=None, w_strides=None): """ - _from_shape_and_storage(shape, addr, dtype, buf_len, - subtype=None, strides=None) Create an array from an existing buffer, given its address as int. PyPy-only implementation detail. """ From noreply at buildbot.pypy.org Tue Dec 2 19:22:42 2014 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 2 Dec 2014 19:22:42 +0100 (CET) Subject: [pypy-commit] pypy optresult: finish porting test_optimizebasic Message-ID: <20141202182242.B87CB1D29E9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult Changeset: r74787:e2c252e3b7eb Date: 2014-12-02 20:22 +0200 http://bitbucket.org/pypy/pypy/changeset/e2c252e3b7eb/ Log: finish porting test_optimizebasic diff --git a/rpython/jit/metainterp/optimizeopt/intbounds.py b/rpython/jit/metainterp/optimizeopt/intbounds.py --- a/rpython/jit/metainterp/optimizeopt/intbounds.py +++ b/rpython/jit/metainterp/optimizeopt/intbounds.py @@ -151,8 +151,8 @@ # nonneg % power-of-two ==> nonneg & (power-of-two - 1) arg1 = op.getarg(0) arg2 = ConstInt(val-1) - xxx - op = op.copy_and_change(rop.INT_AND, args=[arg1, arg2]) + op = self.replace_op_with(op, rop.INT_AND, + args=[arg1, arg2]) self.emit_operation(op) if v2.is_constant(): val = v2.box.getint() @@ -268,8 +268,7 @@ v2 = self.getvalue(op.getarg(1)) resbound = v1.intbound.mul_bound(v2.intbound) if resbound.bounded(): - xxx - op = op.copy_and_change(rop.INT_MUL) + op = self.replace_op_with(op, rop.INT_MUL) self.emit_operation(op) r = self.getvalue(op) r.intbound.intersect(resbound) @@ -482,9 +481,9 @@ v1 = self.getvalue(op.getarg(0)) v2 = self.getvalue(op.getarg(1)) if v1.intbound.intersect(v2.intbound): - self.propagate_bounds_backward(op.getarg(0)) + self.propagate_bounds_backward(op.getarg(0), v1) if v2.intbound.intersect(v1.intbound): - self.propagate_bounds_backward(op.getarg(1)) + self.propagate_bounds_backward(op.getarg(1), v2) def propagate_bounds_INT_IS_TRUE(self, op): r = self.getvalue(op) @@ -535,10 +534,10 @@ r = self.getvalue(op) b = r.intbound.div_bound(v2.intbound) if v1.intbound.intersect(b): - self.propagate_bounds_backward(op.getarg(0)) + self.propagate_bounds_backward(op.getarg(0), v1) b = r.intbound.div_bound(v1.intbound) if v2.intbound.intersect(b): - self.propagate_bounds_backward(op.getarg(1)) + self.propagate_bounds_backward(op.getarg(1), v2) def propagate_bounds_INT_LSHIFT(self, op): v1 = self.getvalue(op.getarg(0)) diff --git a/rpython/jit/metainterp/optimizeopt/optimizer.py b/rpython/jit/metainterp/optimizeopt/optimizer.py --- a/rpython/jit/metainterp/optimizeopt/optimizer.py +++ b/rpython/jit/metainterp/optimizeopt/optimizer.py @@ -293,8 +293,8 @@ def getvalue(self, box): return self.optimizer.getvalue(box) - def replace_op_with(self, op, newopnum, args=None): - return self.optimizer.replace_op_with(op, newopnum, args) + def replace_op_with(self, op, newopnum, args=None, descr=None): + return self.optimizer.replace_op_with(op, newopnum, args, descr) def make_constant(self, box, constbox): return self.optimizer.make_constant(box, constbox) @@ -466,6 +466,8 @@ def get_constant_box(self, box): if isinstance(box, Const): return box + while box.source_op is not None: + box = box.source_op try: value = self.values[box] self.ensure_imported(value) @@ -494,15 +496,17 @@ def make_constant(self, box, constbox): try: + while box.source_op is not None: + box = box.source_op value = self.values[box] value.level = LEVEL_CONSTANT value.make_constant(constbox) except KeyError: self.values[box] = ConstantValue(constbox) - def replace_op_with(self, op, newopnum, args=None): + def replace_op_with(self, op, newopnum, args=None, descr=None): v = self.getvalue(op) - newop = op.copy_and_change(newopnum, args=args) + newop = op.copy_and_change(newopnum, args=args, descr=descr) v.box = newop return newop diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -114,7 +114,7 @@ if v2.is_constant() and v2.box.getint() == 0: self.make_equal_to(op, v1) elif v1.is_constant() and v1.box.getint() == 0: - op = op.copy_and_change(rop.INT_NEG, args=[v2.box]) + op = self.replace_op_with(op, rop.INT_NEG, args=[v2.box]) self.emit_operation(op) elif v1 is v2: self.make_constant_int(op, 0) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -4131,7 +4131,7 @@ def test_str_concat_1(self): ops = """ [p1, p2] - p3 = call(0, p1, p2, descr=strconcatdescr) + p3 = call_r(0, p1, p2, descr=strconcatdescr) jump(p2, p3) """ expected = """ @@ -4152,7 +4152,7 @@ p1 = newstr(2) strsetitem(p1, 0, i0) strsetitem(p1, 1, i1) - p3 = call(0, p1, p2, descr=strconcatdescr) + p3 = call_r(0, p1, p2, descr=strconcatdescr) jump(i1, i0, p3) """ expected = """ @@ -4173,7 +4173,7 @@ p1 = newstr(2) strsetitem(p1, 0, i0) strsetitem(p1, 1, i1) - p3 = call(0, p2, p1, descr=strconcatdescr) + p3 = call_r(0, p2, p1, descr=strconcatdescr) jump(i1, i0, p3) """ expected = """ @@ -4193,8 +4193,8 @@ def test_str_concat_str_str_str(self): ops = """ [p1, p2, p3] - p4 = call(0, p1, p2, descr=strconcatdescr) - p5 = call(0, p4, p3, descr=strconcatdescr) + p4 = call_r(0, p1, p2, descr=strconcatdescr) + p5 = call_r(0, p4, p3, descr=strconcatdescr) jump(p2, p3, p5) """ expected = """ @@ -4215,7 +4215,7 @@ def test_str_concat_str_cstr1(self): ops = """ [p2] - p3 = call(0, p2, s"x", descr=strconcatdescr) + p3 = call_r(0, p2, s"x", descr=strconcatdescr) jump(p3) """ expected = """ @@ -4232,9 +4232,9 @@ def test_str_concat_consts(self): ops = """ [] - p1 = same_as(s"ab") - p2 = same_as(s"cde") - p3 = call(0, p1, p2, descr=strconcatdescr) + p1 = same_as_r(s"ab") + p2 = same_as_r(s"cde") + p3 = call_r(0, p1, p2, descr=strconcatdescr) escape(p3) jump() """ @@ -4251,8 +4251,8 @@ p0 = newstr(1) strsetitem(p0, 0, i0) p1 = newstr(0) - p2 = call(0, p0, p1, descr=strconcatdescr) - i1 = call(0, p2, p0, descr=strequaldescr) + p2 = call_r(0, p0, p1, descr=strconcatdescr) + i1 = call_i(0, p2, p0, descr=strequaldescr) finish(i1) """ expected = """ @@ -4267,8 +4267,8 @@ p0 = newstr(0) p1 = newstr(1) strsetitem(p1, 0, i0) - p2 = call(0, p0, p1, descr=strconcatdescr) - i1 = call(0, p2, p1, descr=strequaldescr) + p2 = call_r(0, p0, p1, descr=strconcatdescr) + i1 = call_i(0, p2, p1, descr=strequaldescr) finish(i1) """ expected = """ @@ -4280,7 +4280,7 @@ def test_str_slice_1(self): ops = """ [p1, i1, i2] - p2 = call(0, p1, i1, i2, descr=strslicedescr) + p2 = call_r(0, p1, i1, i2, descr=strslicedescr) jump(p2, i1, i2) """ expected = """ @@ -4295,7 +4295,7 @@ def test_str_slice_2(self): ops = """ [p1, i2] - p2 = call(0, p1, 0, i2, descr=strslicedescr) + p2 = call_r(0, p1, 0, i2, descr=strslicedescr) jump(p2, i2) """ expected = """ @@ -4309,8 +4309,8 @@ def test_str_slice_3(self): ops = """ [p1, i1, i2, i3, i4] - p2 = call(0, p1, i1, i2, descr=strslicedescr) - p3 = call(0, p2, i3, i4, descr=strslicedescr) + p2 = call_r(0, p1, i1, i2, descr=strslicedescr) + p3 = call_r(0, p2, i3, i4, descr=strslicedescr) jump(p3, i1, i2, i3, i4) """ expected = """ @@ -4327,7 +4327,7 @@ def test_str_slice_getitem1(self): ops = """ [p1, i1, i2, i3] - p2 = call(0, p1, i1, i2, descr=strslicedescr) + p2 = call_r(0, p1, i1, i2, descr=strslicedescr) i4 = strgetitem(p2, i3) escape(i4) jump(p1, i1, i2, i3) @@ -4348,7 +4348,7 @@ p1 = newstr(2) strsetitem(p1, 0, i3) strsetitem(p1, 1, i4) - p2 = call(0, p1, 1, 2, descr=strslicedescr) + p2 = call_r(0, p1, 1, 2, descr=strslicedescr) i5 = strgetitem(p2, 0) escape(i5) jump(i3, i4) @@ -4363,8 +4363,8 @@ def test_str_slice_concat(self): ops = """ [p1, i1, i2, p2] - p3 = call(0, p1, i1, i2, descr=strslicedescr) - p4 = call(0, p3, p2, descr=strconcatdescr) + p3 = call_r(0, p1, i1, i2, descr=strslicedescr) + p4 = call_r(0, p3, p2, descr=strconcatdescr) jump(p4, i1, i2, p2) """ expected = """ @@ -4384,7 +4384,7 @@ [] p0 = newstr(11) copystrcontent(s"hello world", p0, 0, 0, 11) - p1 = call(0, p0, 0, 5, descr=strslicedescr) + p1 = call_r(0, p0, 0, 5, descr=strslicedescr) finish(p1) """ expected = """ @@ -4415,7 +4415,7 @@ def test_str_equal_noop1(self): ops = """ [p1, p2] - i0 = call(0, p1, p2, descr=strequaldescr) + i0 = call_i(0, p1, p2, descr=strequaldescr) escape(i0) jump(p1, p2) """ @@ -4424,8 +4424,8 @@ def test_str_equal_noop2(self): ops = """ [p1, p2, p3] - p4 = call(0, p1, p2, descr=strconcatdescr) - i0 = call(0, p3, p4, descr=strequaldescr) + p4 = call_r(0, p1, p2, descr=strconcatdescr) + i0 = call_i(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) """ @@ -4437,7 +4437,7 @@ p4 = newstr(i3) copystrcontent(p1, p4, 0, 0, i1) copystrcontent(p2, p4, 0, i1, i2) - i0 = call(0, p3, p4, descr=strequaldescr) + i0 = call_i(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, p2, p3) """ @@ -4446,15 +4446,15 @@ def test_str_equal_slice1(self): ops = """ [p1, i1, i2, p3] - p4 = call(0, p1, i1, i2, descr=strslicedescr) - i0 = call(0, p4, p3, descr=strequaldescr) + p4 = call_r(0, p1, i1, i2, descr=strslicedescr) + i0 = call_i(0, p4, p3, descr=strequaldescr) escape(i0) jump(p1, i1, i2, p3) """ expected = """ [p1, i1, i2, p3] i3 = int_sub(i2, i1) - i0 = call(0, p1, i1, i3, p3, descr=streq_slice_checknull_descr) + i0 = call_i(0, p1, i1, i3, p3, descr=streq_slice_checknull_descr) escape(i0) jump(p1, i1, i2, p3) """ @@ -4463,15 +4463,15 @@ def test_str_equal_slice2(self): ops = """ [p1, i1, i2, p3] - p4 = call(0, p1, i1, i2, descr=strslicedescr) - i0 = call(0, p3, p4, descr=strequaldescr) + p4 = call_r(0, p1, i1, i2, descr=strslicedescr) + i0 = call_i(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, i1, i2, p3) """ expected = """ [p1, i1, i2, p3] i4 = int_sub(i2, i1) - i0 = call(0, p1, i1, i4, p3, descr=streq_slice_checknull_descr) + i0 = call_i(0, p1, i1, i4, p3, descr=streq_slice_checknull_descr) escape(i0) jump(p1, i1, i2, p3) """ @@ -4481,8 +4481,8 @@ ops = """ [p1, i1, i2, p3] guard_nonnull(p3) [] - p4 = call(0, p1, i1, i2, descr=strslicedescr) - i0 = call(0, p3, p4, descr=strequaldescr) + p4 = call_r(0, p1, i1, i2, descr=strslicedescr) + i0 = call_i(0, p3, p4, descr=strequaldescr) escape(i0) jump(p1, i1, i2, p3) """ @@ -4490,7 +4490,7 @@ [p1, i1, i2, p3] guard_nonnull(p3) [] i4 = int_sub(i2, i1) - i0 = call(0, p1, i1, i4, p3, descr=streq_slice_nonnull_descr) + i0 = call_i(0, p1, i1, i4, p3, descr=streq_slice_nonnull_descr) escape(i0) jump(p1, i1, i2, p3) """ @@ -4499,15 +4499,15 @@ def test_str_equal_slice4(self): ops = """ [p1, i1, i2] - p3 = call(0, p1, i1, i2, descr=strslicedescr) - i0 = call(0, p3, s"x", descr=strequaldescr) + p3 = call_r(0, p1, i1, i2, descr=strslicedescr) + i0 = call_i(0, p3, s"x", descr=strequaldescr) escape(i0) jump(p1, i1, i2) """ expected = """ [p1, i1, i2] i3 = int_sub(i2, i1) - i0 = call(0, p1, i1, i3, 120, descr=streq_slice_char_descr) + i0 = call_i(0, p1, i1, i3, 120, descr=streq_slice_char_descr) escape(i0) jump(p1, i1, i2) """ @@ -4516,17 +4516,17 @@ def test_str_equal_slice5(self): ops = """ [p1, i1, i2, i3] - p4 = call(0, p1, i1, i2, descr=strslicedescr) + p4 = call_r(0, p1, i1, i2, descr=strslicedescr) p5 = newstr(1) strsetitem(p5, 0, i3) - i0 = call(0, p5, p4, descr=strequaldescr) + i0 = call_i(0, p5, p4, descr=strequaldescr) escape(i0) jump(p1, i1, i2, i3) """ expected = """ [p1, i1, i2, i3] i4 = int_sub(i2, i1) - i0 = call(0, p1, i1, i4, i3, descr=streq_slice_char_descr) + i0 = call_i(0, p1, i1, i4, i3, descr=streq_slice_char_descr) escape(i0) jump(p1, i1, i2, i3) """ @@ -4535,7 +4535,7 @@ def test_str_equal_none1(self): ops = """ [p1] - i0 = call(0, p1, NULL, descr=strequaldescr) + i0 = call_i(0, p1, NULL, descr=strequaldescr) escape(i0) jump(p1) """ @@ -4550,7 +4550,7 @@ def test_str_equal_none2(self): ops = """ [p1] - i0 = call(0, NULL, p1, descr=strequaldescr) + i0 = call_i(0, NULL, p1, descr=strequaldescr) escape(i0) jump(p1) """ @@ -4566,14 +4566,14 @@ ops = """ [p1] guard_nonnull(p1) [] - i0 = call(0, p1, s"hello world", descr=strequaldescr) + i0 = call_i(0, p1, s"hello world", descr=strequaldescr) escape(i0) jump(p1) """ expected = """ [p1] guard_nonnull(p1) [] - i0 = call(0, p1, s"hello world", descr=streq_nonnull_descr) + i0 = call_i(0, p1, s"hello world", descr=streq_nonnull_descr) escape(i0) jump(p1) """ @@ -4583,7 +4583,7 @@ ops = """ [p1] guard_nonnull(p1) [] - i0 = call(0, p1, s"", descr=strequaldescr) + i0 = call_i(0, p1, s"", descr=strequaldescr) escape(i0) jump(p1) """ @@ -4601,14 +4601,14 @@ ops = """ [p1] guard_nonnull(p1) [] - i0 = call(0, p1, s"x", descr=strequaldescr) + i0 = call_i(0, p1, s"x", descr=strequaldescr) escape(i0) jump(p1) """ expected = """ [p1] guard_nonnull(p1) [] - i0 = call(0, p1, 120, descr=streq_nonnull_char_descr) + i0 = call_i(0, p1, 120, descr=streq_nonnull_char_descr) escape(i0) jump(p1) """ @@ -4617,8 +4617,8 @@ def test_str_equal_nonnull4(self): ops = """ [p1, p2] - p4 = call(0, p1, p2, descr=strconcatdescr) - i0 = call(0, s"hello world", p4, descr=strequaldescr) + p4 = call_r(0, p1, p2, descr=strconcatdescr) + i0 = call_i(0, s"hello world", p4, descr=strequaldescr) escape(i0) jump(p1, p2) """ @@ -4630,7 +4630,7 @@ p4 = newstr(i3) copystrcontent(p1, p4, 0, 0, i1) copystrcontent(p2, p4, 0, i1, i2) - i0 = call(0, s"hello world", p4, descr=streq_nonnull_descr) + i0 = call_i(0, s"hello world", p4, descr=streq_nonnull_descr) escape(i0) jump(p1, p2) """ @@ -4640,7 +4640,7 @@ ops = """ [i1] p1 = newstr(0) - i0 = call(0, p1, s"", descr=strequaldescr) + i0 = call_i(0, p1, s"", descr=strequaldescr) escape(i0) jump(i1) """ @@ -4656,7 +4656,7 @@ [i1] p1 = newstr(1) strsetitem(p1, 0, i1) - i0 = call(0, p1, s"x", descr=strequaldescr) + i0 = call_i(0, p1, s"x", descr=strequaldescr) escape(i0) jump(i1) """ @@ -4674,7 +4674,7 @@ p1 = newstr(2) strsetitem(p1, 0, i1) strsetitem(p1, 1, i2) - i0 = call(0, p1, s"xy", descr=strequaldescr) + i0 = call_i(0, p1, s"xy", descr=strequaldescr) escape(i0) jump(i1, i2) """ @@ -4683,7 +4683,7 @@ p1 = newstr(2) strsetitem(p1, 0, i1) strsetitem(p1, 1, i2) - i0 = call(0, p1, s"xy", descr=streq_lengthok_descr) + i0 = call_i(0, p1, s"xy", descr=streq_lengthok_descr) escape(i0) jump(i1, i2) """ @@ -4692,13 +4692,13 @@ def test_str_equal_chars3(self): ops = """ [p1] - i0 = call(0, s"x", p1, descr=strequaldescr) + i0 = call_i(0, s"x", p1, descr=strequaldescr) escape(i0) jump(p1) """ expected = """ [p1] - i0 = call(0, p1, 120, descr=streq_checknull_char_descr) + i0 = call_i(0, p1, 120, descr=streq_checknull_char_descr) escape(i0) jump(p1) """ @@ -4709,7 +4709,7 @@ [i1] p1 = newstr(1) strsetitem(p1, 0, i1) - i0 = call(0, s"xy", p1, descr=strequaldescr) + i0 = call_i(0, s"xy", p1, descr=strequaldescr) escape(i0) jump(i1) """ @@ -4723,7 +4723,7 @@ def test_str2unicode_constant(self): ops = """ [] - p0 = call(0, "xy", descr=s2u_descr) # string -> unicode + p0 = call_r(0, "xy", descr=s2u_descr) # string -> unicode escape(p0) jump() """ @@ -4737,7 +4737,7 @@ def test_str2unicode_nonconstant(self): ops = """ [p0] - p1 = call(0, p0, descr=s2u_descr) # string -> unicode + p1 = call_r(0, p0, descr=s2u_descr) # string -> unicode escape(p1) jump(p1) """ @@ -4787,7 +4787,7 @@ ops = """ [p0, i0] i1 = int_add(i0, 1) - p1 = call(0, p0, i0, i1, descr=strslicedescr) + p1 = call_r(0, p0, i0, i1, descr=strslicedescr) escape(p1) jump(p0, i1) """ @@ -4956,10 +4956,10 @@ [p0, i0] i1 = int_gt(i0, 2) guard_true(i1) [] - setarrayitem_gc(p0, 0, 3) - setarrayitem_gc(p0, 2, 4) - setarrayitem_gc(p0, i0, 15) - i2 = getarrayitem_gc(p0, 2) + setarrayitem_gc(p0, 0, 3, descr=arraydescr) + setarrayitem_gc(p0, 2, 4, descr=arraydescr) + setarrayitem_gc(p0, i0, 15, descr=arraydescr) + i2 = getarrayitem_gc_i(p0, 2, descr=arraydescr) jump(p0, i2) """ # Remove the getarrayitem_gc, because we know that p[i0] does not alias @@ -4968,9 +4968,9 @@ [p0, i0] i1 = int_gt(i0, 2) guard_true(i1) [] - setarrayitem_gc(p0, i0, 15) - setarrayitem_gc(p0, 0, 3) - setarrayitem_gc(p0, 2, 4) + setarrayitem_gc(p0, i0, 15, descr=arraydescr) + setarrayitem_gc(p0, 0, 3, descr=arraydescr) + setarrayitem_gc(p0, 2, 4, descr=arraydescr) jump(p0, 4) """ self.optimize_loop(ops, expected) @@ -5036,7 +5036,7 @@ [i1] p0 = newstr(6) copystrcontent(s"hello!", p0, 0, 0, 6) - p1 = call(0, p0, s"abc123", descr=strconcatdescr) + p1 = call_r(0, p0, s"abc123", descr=strconcatdescr) i0 = strgetitem(p1, i1) finish(i0) """ @@ -5052,7 +5052,7 @@ [] p0 = newstr(6) copystrcontent(s"hello!", p0, 0, 0, 6) - p1 = call(0, p0, s"abc123", descr=strconcatdescr) + p1 = call_r(0, p0, s"abc123", descr=strconcatdescr) i0 = strgetitem(p1, 0) finish(i0) """ diff --git a/rpython/jit/metainterp/optimizeopt/virtualize.py b/rpython/jit/metainterp/optimizeopt/virtualize.py --- a/rpython/jit/metainterp/optimizeopt/virtualize.py +++ b/rpython/jit/metainterp/optimizeopt/virtualize.py @@ -568,7 +568,9 @@ if self._last_guard_not_forced_2 is not None: guard_op = self._last_guard_not_forced_2 self.emit_operation(op) - guard_op = self.optimizer.store_final_boxes_in_guard(guard_op, []) + v = self.getvalue(op) + guard_op = self.optimizer.store_final_boxes_in_guard(guard_op, [], + v) i = len(self.optimizer._newoperations) - 1 assert i >= 0 self.optimizer._newoperations.insert(i, guard_op) diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -5,7 +5,7 @@ from rpython.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1 from rpython.jit.metainterp.optimizeopt.optimizer import llhelper, REMOVED from rpython.jit.metainterp.optimizeopt.util import make_dispatcher_method -from rpython.jit.metainterp.resoperation import rop, ResOperation +from rpython.jit.metainterp.resoperation import rop, ResOperation, DONT_CHANGE from rpython.rlib.objectmodel import specialize, we_are_translated from rpython.rlib.unroll import unrolling_iterable from rpython.rtyper import annlowlevel @@ -61,11 +61,12 @@ return None self.ensure_nonnull() box = self.force_box(string_optimizer) - if lengthop is None: - xxx - else: + if lengthop is not None: lengthop = string_optimizer.optimizer.replace_op_with(lengthop, mode.STRLEN, [box]) + else: + lengthop = ResOperation(mode.STRLEN, [box]) + lengthop.is_source_op = True string_optimizer.emit_operation(lengthop) return lengthop @@ -90,9 +91,8 @@ class VAbstractStringValue(virtualize.AbstractVirtualValue): _attrs_ = ('mode',) - def __init__(self, keybox, source_op, mode): - virtualize.AbstractVirtualValue.__init__(self, keybox, - source_op) + def __init__(self, source_op, mode): + virtualize.AbstractVirtualValue.__init__(self, source_op) self.mode = mode def _really_force(self, optforce): @@ -109,13 +109,14 @@ self.make_constant(c_s) return assert self.source_op is not None - self.box = box = self.source_op.result lengthbox = self.getstrlen(optforce, self.mode, None) - op = ResOperation(self.mode.NEWSTR, [lengthbox], box) + op = ResOperation(self.mode.NEWSTR, [lengthbox]) + op.source_op = self.source_op + self.box = op if not we_are_translated(): op.name = 'FORCE' optforce.emit_operation(op) - self.initialize_forced_string(optforce, box, CONST_0, self.mode) + self.initialize_forced_string(optforce, self.box, CONST_0, self.mode) def initialize_forced_string(self, string_optimizer, targetbox, offsetbox, mode): @@ -188,7 +189,7 @@ def initialize_forced_string(self, string_optimizer, targetbox, offsetbox, mode): for i in range(len(self._chars)): - assert isinstance(targetbox, BoxPtr) # ConstPtr never makes sense + assert not isinstance(targetbox, Const) # ConstPtr never makes sense charvalue = self.getitem(i) if charvalue is not None: charbox = charvalue.force_box(string_optimizer) @@ -281,7 +282,6 @@ self.vlength = vlength def getstrlen(self, optforce, mode, lengthbox): - xxx return self.vlength.force_box(optforce) @specialize.arg(1) @@ -330,7 +330,7 @@ for i in range(lengthbox.value): charbox = _strgetitem(string_optimizer, srcbox, srcoffsetbox, mode) srcoffsetbox = _int_add(string_optimizer, srcoffsetbox, CONST_1) - assert isinstance(targetbox, BoxPtr) # ConstPtr never makes sense + assert not isinstance(targetbox, Const)# ConstPtr never makes sense string_optimizer.emit_operation(ResOperation(mode.STRSETITEM, [targetbox, offsetbox, charbox], @@ -341,10 +341,10 @@ nextoffsetbox = _int_add(string_optimizer, offsetbox, lengthbox) else: nextoffsetbox = None - assert isinstance(targetbox, BoxPtr) # ConstPtr never makes sense + assert not isinstance(targetbox, Const) # ConstPtr never makes sense op = ResOperation(mode.COPYSTRCONTENT, [srcbox, targetbox, srcoffsetbox, offsetbox, - lengthbox], None) + lengthbox]) string_optimizer.emit_operation(op) offsetbox = nextoffsetbox return offsetbox @@ -359,9 +359,10 @@ return box1 if string_optimizer is None: return None - resbox = BoxInt() - string_optimizer.emit_operation(ResOperation(rop.INT_ADD, [box1, box2], resbox)) - return resbox + op = ResOperation(rop.INT_ADD, [box1, box2]) + op.is_source_op = True + string_optimizer.emit_operation(op) + return op def _int_sub(string_optimizer, box1, box2): if isinstance(box2, ConstInt): @@ -369,9 +370,10 @@ return box1 if isinstance(box1, ConstInt): return ConstInt(box1.value - box2.value) - resbox = BoxInt() - string_optimizer.emit_operation(ResOperation(rop.INT_SUB, [box1, box2], resbox)) - return resbox + op = ResOperation(rop.INT_SUB, [box1, box2]) + op.is_source_op = True + string_optimizer.emit_operation(op) + return op def _strgetitem(string_optimizer, strbox, indexbox, mode, resbox=None): if isinstance(strbox, ConstPtr) and isinstance(indexbox, ConstInt): @@ -382,28 +384,30 @@ s = strbox.getref(lltype.Ptr(rstr.UNICODE)) return ConstInt(ord(s.chars[indexbox.getint()])) if resbox is None: - resbox = BoxInt() - string_optimizer.emit_operation(ResOperation(mode.STRGETITEM, [strbox, indexbox], - resbox)) + resbox = ResOperation(mode.STRGETITEM, [strbox, indexbox]) + else: + resbox = string_optimizer.replace_op_with(resbox, mode.STRGETITEM, + [strbox, indexbox]) + string_optimizer.emit_operation(resbox) return resbox class OptString(optimizer.Optimization): "Handling of strings and unicodes." - def make_vstring_plain(self, box, source_op, mode): - vvalue = VStringPlainValue(box, source_op, mode) - self.make_equal_to(box, vvalue) + def make_vstring_plain(self, source_op, mode): + vvalue = VStringPlainValue(source_op, mode) + self.make_equal_to(source_op, vvalue) return vvalue - def make_vstring_concat(self, box, source_op, mode): - vvalue = VStringConcatValue(box, source_op, mode) - self.make_equal_to(box, vvalue) + def make_vstring_concat(self, source_op, mode): + vvalue = VStringConcatValue(source_op, mode) + self.make_equal_to(source_op, vvalue) return vvalue - def make_vstring_slice(self, box, source_op, mode): - vvalue = VStringSliceValue(box, source_op, mode) - self.make_equal_to(box, vvalue) + def make_vstring_slice(self, source_op, mode): + vvalue = VStringSliceValue(source_op, mode) + self.make_equal_to(source_op, vvalue) return vvalue def optimize_NEWSTR(self, op): @@ -417,13 +421,13 @@ # if the original 'op' did not have a ConstInt as argument, # build a new one with the ConstInt argument if not isinstance(op.getarg(0), ConstInt): - op = ResOperation(mode.NEWSTR, [length_box], op.result) - vvalue = self.make_vstring_plain(op.result, op, mode) + op = self.replace_op_with(op, mode.NEWSTR, [length_box]) + vvalue = self.make_vstring_plain(op, mode) vvalue.setup(length_box.getint()) else: - self.getvalue(op.result).ensure_nonnull() + self.getvalue(op).ensure_nonnull() self.emit_operation(op) - self.pure(mode.STRLEN, [op.result], op.getarg(0)) + self.pure(mode.STRLEN, [op], op.getarg(0)) def optimize_STRSETITEM(self, op): value = self.getvalue(op.getarg(0)) @@ -446,11 +450,11 @@ def _optimize_STRGETITEM(self, op, mode): value = self.getvalue(op.getarg(0)) vindex = self.getvalue(op.getarg(1)) - vresult = self.strgetitem(value, vindex, mode, op.result) - if op.result in self.optimizer.values: - assert self.getvalue(op.result) is vresult + vresult = self.strgetitem(value, vindex, mode, op) + if op in self.optimizer.values: + assert self.getvalue(op) is vresult else: - self.make_equal_to(op.result, vresult) + self.make_equal_to(op, vresult) def strgetitem(self, value, vindex, mode, resbox=None): value.ensure_nonnull() @@ -595,7 +599,7 @@ u = unicode(s) except UnicodeDecodeError: return False - self.make_constant(op.result, get_const_ptr_for_unicode(u)) + self.make_constant(op, get_const_ptr_for_unicode(u)) self.last_emitted_operation = REMOVED return True @@ -604,7 +608,7 @@ vright = self.getvalue(op.getarg(2)) vleft.ensure_nonnull() vright.ensure_nonnull() - value = self.make_vstring_concat(op.result, op, mode) + value = self.make_vstring_concat(op, mode) value.setup(vleft, vright) return True @@ -633,7 +637,7 @@ vstart.force_box(self)) vstart = self.getvalue(startbox) # - value = self.make_vstring_slice(op.result, op, mode) + value = self.make_vstring_slice(op, mode) value.setup(vstr, vstart, self.getvalue(lengthbox)) return True @@ -648,16 +652,16 @@ isinstance(l2box, ConstInt) and l1box.value != l2box.value): # statically known to have a different length - self.make_constant(op.result, CONST_0) + self.make_constant(op, CONST_0) return True # - if self.handle_str_equal_level1(v1, v2, op.result, mode): + if self.handle_str_equal_level1(v1, v2, op, mode): return True - if self.handle_str_equal_level1(v2, v1, op.result, mode): + if self.handle_str_equal_level1(v2, v1, op, mode): return True - if self.handle_str_equal_level2(v1, v2, op.result, mode): + if self.handle_str_equal_level2(v1, v2, op, mode): return True - if self.handle_str_equal_level2(v2, v1, op.result, mode): + if self.handle_str_equal_level2(v2, v1, op, mode): return True # if v1.is_nonnull() and v2.is_nonnull(): @@ -666,17 +670,20 @@ else: do = EffectInfo.OS_STREQ_NONNULL self.generate_modified_call(do, [v1.force_box(self), - v2.force_box(self)], op.result, mode) + v2.force_box(self)], op, mode) return True return False - def handle_str_equal_level1(self, v1, v2, resultbox, mode): + def handle_str_equal_level1(self, v1, v2, resultop, mode): l2box = v2.getstrlen(None, mode, None) if isinstance(l2box, ConstInt): if l2box.value == 0: lengthbox = v1.getstrlen(self, mode, None) seo = self.optimizer.send_extra_operation - seo(ResOperation(rop.INT_EQ, [lengthbox, CONST_0], resultbox)) + op = self.replace_op_with(resultop, rop.INT_EQ, + [lengthbox, CONST_0], + descr=DONT_CHANGE) + seo(op) return True if l2box.value == 1: l1box = v1.getstrlen(None, mode, None) @@ -685,9 +692,10 @@ vchar1 = self.strgetitem(v1, optimizer.CVAL_ZERO, mode) vchar2 = self.strgetitem(v2, optimizer.CVAL_ZERO, mode) seo = self.optimizer.send_extra_operation - seo(ResOperation(rop.INT_EQ, [vchar1.force_box(self), - vchar2.force_box(self)], - resultbox)) + op = self.optimizer.replace_op_with(resultop, rop.INT_EQ, + [vchar1.force_box(self), vchar2.force_box(self)], + descr=DONT_CHANGE) + seo(op) return True if isinstance(v1, VStringSliceValue): vchar = self.strgetitem(v2, optimizer.CVAL_ZERO, mode) @@ -696,19 +704,20 @@ v1.vstart.force_box(self), v1.vlength.force_box(self), vchar.force_box(self)], - resultbox, mode) + resultop, mode) return True # if v2.is_null(): if v1.is_nonnull(): - self.make_constant(resultbox, CONST_0) + self.make_constant(resultop, CONST_0) return True if v1.is_null(): - self.make_constant(resultbox, CONST_1) + self.make_constant(resultop, CONST_1) return True - op = ResOperation(rop.PTR_EQ, [v1.force_box(self), - llhelper.CONST_NULL], - resultbox) + op = self.optimizer.replace_op_with(resultop, rop.PTR_EQ, + [v1.force_box(self), + llhelper.CONST_NULL], + descr=DONT_CHANGE) self.emit_operation(op) return True # @@ -776,8 +785,9 @@ oopspecindex += mode.OS_offset cic = self.optimizer.metainterp_sd.callinfocollection calldescr, func = cic.callinfo_for_oopspec(oopspecindex) - op = ResOperation(rop.CALL, [ConstInt(func)] + args, result, - descr=calldescr) + op = self.optimizer.replace_op_with(result, rop.CALL_I, + [ConstInt(func)] + args, + descr=calldescr) self.emit_operation(op) def propagate_forward(self, op): diff --git a/rpython/jit/metainterp/quasiimmut.py b/rpython/jit/metainterp/quasiimmut.py --- a/rpython/jit/metainterp/quasiimmut.py +++ b/rpython/jit/metainterp/quasiimmut.py @@ -120,12 +120,12 @@ return ConstInt(self.cpu.bh_getfield_gc_i(struct, fielddescr)) def is_still_valid_for(self, structconst): - assert self.structbox is not None - if not self.structbox.constbox().same_constant(structconst): + assert self.struct + if self.struct != structconst.getref_base(): return False cpu = self.cpu - gcref = self.structbox.getref_base() - qmut = get_current_qmut_instance(cpu, gcref, self.mutatefielddescr) + qmut = get_current_qmut_instance(cpu, self.struct, + self.mutatefielddescr) if qmut is not self.qmut: return False else: diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -13,6 +13,8 @@ def repr_short(self, memo): return self.repr(memo) +DONT_CHANGE = AbstractValue() + def ResOperation(opnum, args, descr=None): cls = opclasses[opnum] op = cls() @@ -96,6 +98,8 @@ args = self.getarglist() if descr is None: descr = self.getdescr() + if descr is DONT_CHANGE: + descr = None newop = ResOperation(opnum, args, descr) if self.type != 'v': newop.copy_value_from(self) From noreply at buildbot.pypy.org Tue Dec 2 19:23:53 2014 From: noreply at buildbot.pypy.org (fijal) Date: Tue, 2 Dec 2014 19:23:53 +0100 (CET) Subject: [pypy-commit] pypy optresult: two untested cases Message-ID: <20141202182353.A68A51D29E9@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult Changeset: r74788:a64ec027f6c0 Date: 2014-12-02 20:23 +0200 http://bitbucket.org/pypy/pypy/changeset/a64ec027f6c0/ Log: two untested cases diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py --- a/rpython/jit/metainterp/optimizeopt/vstring.py +++ b/rpython/jit/metainterp/optimizeopt/vstring.py @@ -762,9 +762,10 @@ vchar1 = self.strgetitem(v1, optimizer.CVAL_ZERO, mode) vchar2 = self.strgetitem(v2, optimizer.CVAL_ZERO, mode) seo = self.optimizer.send_extra_operation - seo(ResOperation(rop.INT_SUB, [vchar1.force_box(self), - vchar2.force_box(self)], - op.result)) + op = self.replace_op_with(op, rop.INT_SUB, + [vchar1.force_box(self), + vchar2.force_box(self)]) + seo(op) return True return False @@ -777,7 +778,7 @@ length = v2.box.getint() v1.shrink(length) self.last_emitted_operation = REMOVED - self.make_equal_to(op.result, v1) + self.make_equal_to(op, v1) return True return False From noreply at buildbot.pypy.org Tue Dec 2 20:02:32 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Tue, 2 Dec 2014 20:02:32 +0100 (CET) Subject: [pypy-commit] pypy framestate: progress Message-ID: <20141202190232.B8B0F1C3288@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74789:2796501df19e Date: 2014-12-01 17:27 +0100 http://bitbucket.org/pypy/pypy/changeset/2796501df19e/ Log: progress diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -521,32 +521,35 @@ self.target = reader.get_block_at(self.arg) def eval(self, ctx): - block = self.make_block(ctx) + block = self.make_block(ctx.stackdepth) ctx.blockstack.append(block) @bc_reader.register_opcode class SETUP_EXCEPT(SetupInstruction): - def make_block(self, ctx): + def make_block(self, stackdepth): from rpython.flowspace.flowcontext import ExceptBlock - return ExceptBlock(ctx.stackdepth, self.target) + return ExceptBlock(stackdepth, self.target) @bc_reader.register_opcode class SETUP_LOOP(SetupInstruction): - def make_block(self, ctx): + def make_block(self, stackdepth): from rpython.flowspace.flowcontext import LoopBlock - return LoopBlock(ctx.stackdepth, self.target) + return LoopBlock(stackdepth, self.target) @bc_reader.register_opcode class SETUP_FINALLY(SetupInstruction): - def make_block(self, ctx): + def make_block(self, stackdepth): from rpython.flowspace.flowcontext import FinallyBlock - return FinallyBlock(ctx.stackdepth, self.target) + return FinallyBlock(stackdepth, self.target) @bc_reader.register_opcode class SETUP_WITH(SetupInstruction): + def make_block(self, stackdepth): + from rpython.flowspace.flowcontext import WithBlock + return WithBlock(stackdepth, self.target) + def eval(self, ctx): - from rpython.flowspace.flowcontext import WithBlock # A simpler version than the 'real' 2.7 one: # directly call manager.__enter__(), don't use special lookup functions # which don't make sense on the RPython type system. @@ -555,7 +558,7 @@ ctx.settopvalue(w_exit) w_enter = op.getattr(w_manager, const('__enter__')).eval(ctx) w_result = op.simple_call(w_enter).eval(ctx) - block = WithBlock(ctx.stackdepth, self.target) + block = self.make_block(ctx.stackdepth) ctx.blockstack.append(block) ctx.pushvalue(w_result) From noreply at buildbot.pypy.org Tue Dec 2 20:02:34 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Tue, 2 Dec 2014 20:02:34 +0100 (CET) Subject: [pypy-commit] pypy framestate: remove BCInstruction.decode() and decode LOAD_CONST arg later Message-ID: <20141202190234.014371C3288@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74790:bc3042836ed0 Date: 2014-12-02 16:03 +0100 http://bitbucket.org/pypy/pypy/changeset/bc3042836ed0/ Log: remove BCInstruction.decode() and decode LOAD_CONST arg later diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -128,7 +128,7 @@ elif opnum in opcode.hasname: oparg = code.names[oparg] try: - op = self.num2cls[opnum].decode(oparg, offset, code) + op = self.num2cls[opnum](oparg, offset) except KeyError: op = GenericOpcode(self.opnames[opnum], opnum, oparg, offset) return next_offset, op @@ -329,10 +329,6 @@ self.arg = arg self.offset = offset - @classmethod - def decode(cls, arg, offset, code): - return cls(arg, offset) - def eval(self, ctx): pass @@ -375,12 +371,9 @@ @bc_reader.register_opcode class LOAD_CONST(BCInstruction): - @staticmethod - def decode(arg, offset, code): - return LOAD_CONST(code.consts[arg], offset) - def eval(self, ctx): - ctx.pushvalue(const(self.arg)) + v_arg = const(ctx.pycode.consts[self.arg]) + ctx.pushvalue(v_arg) @bc_reader.register_opcode class DUP_TOP(BCInstruction): From noreply at buildbot.pypy.org Tue Dec 2 20:02:35 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Tue, 2 Dec 2014 20:02:35 +0100 (CET) Subject: [pypy-commit] pypy framestate: extract a bc_reader.new_instr() method Message-ID: <20141202190235.8BA7B1C3288@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74791:1d97ee1c1edd Date: 2014-12-02 16:33 +0100 http://bitbucket.org/pypy/pypy/changeset/1d97ee1c1edd/ Log: extract a bc_reader.new_instr() method diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -127,11 +127,17 @@ oparg += next_offset elif opnum in opcode.hasname: oparg = code.names[oparg] + instr = self.new_instr(opnum, oparg, offset) + return next_offset, instr + + def new_instr(self, opnum, arg, offset=-1): + if not isinstance(opnum, int): + opnum = opcode.opmap[opnum] try: - op = self.num2cls[opnum](oparg, offset) + return self.num2cls[opnum](arg, offset) except KeyError: - op = GenericOpcode(self.opnames[opnum], opnum, oparg, offset) - return next_offset, op + return GenericOpcode(self.opnames[opnum], opnum, arg, offset) + def _iter_instr(self, code): self.offset = 0 @@ -344,6 +350,10 @@ def __repr__(self): return "%s(%s)" % (self.name, self.arg) + def __eq__(self, other): + # NB: offsets are ignored, for testing convenience + return other.num == self.num and other.arg == self.arg + class GenericOpcode(BCInstruction): def __init__(self, name, opcode, arg, offset=-1): self.name = name diff --git a/rpython/flowspace/test/test_bytecode.py b/rpython/flowspace/test/test_bytecode.py --- a/rpython/flowspace/test/test_bytecode.py +++ b/rpython/flowspace/test/test_bytecode.py @@ -9,5 +9,5 @@ else: return 0 bc_graph = bc_reader.build_flow(bc_reader.build_code(f.__code__)) - print bc_graph.dump() assert [lst[0].offset for lst in bc_graph.dump()] == [0, 6, 10] + assert bc_graph.dump()[0][0] == bc_reader.new_instr('LOAD_FAST', 0) From noreply at buildbot.pypy.org Tue Dec 2 20:02:36 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Tue, 2 Dec 2014 20:02:36 +0100 (CET) Subject: [pypy-commit] pypy framestate: WIP: storing blockstack status on bc_graph Message-ID: <20141202190236.C24D91C3288@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74792:af6873879d10 Date: 2014-12-02 19:02 +0000 http://bitbucket.org/pypy/pypy/changeset/af6873879d10/ Log: WIP: storing blockstack status on bc_graph diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -263,9 +263,11 @@ instr = self.read(offset) yield instr + def all_blocks(self): + return set(x[0] for x in self.pos_index.values()) + def dump(self): - all_blocks = set(x[0] for x in self.pos_index.values()) - blocks = sorted(all_blocks, key=lambda b: b.startpos) + blocks = sorted(self.all_blocks(), key=lambda b: b.startpos) return [b.operations for b in blocks] @@ -274,6 +276,7 @@ def __init__(self): self.parents = set() self._exits = [] + self.blockstack = [] def __getitem__(self, i): return self.operations[i] @@ -522,6 +525,7 @@ def bc_flow(self, reader): reader.curr_block.operations.append(self) self.target = reader.get_block_at(self.arg) + reader.curr_block.blockstack.append(self.make_block(-1)) def eval(self, ctx): block = self.make_block(ctx.stackdepth) diff --git a/rpython/flowspace/test/test_bytecode.py b/rpython/flowspace/test/test_bytecode.py --- a/rpython/flowspace/test/test_bytecode.py +++ b/rpython/flowspace/test/test_bytecode.py @@ -2,12 +2,27 @@ from rpython.flowspace.bytecode import bc_reader +def make_graph(func): + return bc_reader.build_flow(bc_reader.build_code(func.__code__)) + def test_graph_dump(): def f(x): if x: return 1 else: return 0 - bc_graph = bc_reader.build_flow(bc_reader.build_code(f.__code__)) + bc_graph = make_graph(f) assert [lst[0].offset for lst in bc_graph.dump()] == [0, 6, 10] assert bc_graph.dump()[0][0] == bc_reader.new_instr('LOAD_FAST', 0) + +def test_blockstack(): + def f(): + for x in lst: + xxx + graph = make_graph(f) + for block in graph.all_blocks(): + if bc_reader.new_instr('LOAD_GLOBAL', 'xxx') in block.operations: + break + else: + assert False + assert len(block.blockstack) == 1 From noreply at buildbot.pypy.org Wed Dec 3 00:06:59 2014 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 3 Dec 2014 00:06:59 +0100 (CET) Subject: [pypy-commit] stmgc c8-private-pages: in-progress Message-ID: <20141202230700.399551D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: c8-private-pages Changeset: r1510:e305d59e0a3d Date: 2014-12-02 21:07 +0100 http://bitbucket.org/pypy/stmgc/changeset/e305d59e0a3d/ Log: in-progress diff --git a/c8/stm/core.c b/c8/stm/core.c --- a/c8/stm/core.c +++ b/c8/stm/core.c @@ -3,20 +3,6 @@ #endif -#ifdef NDEBUG -#define EVENTUALLY(condition) {/* nothing */} -#else -#define EVENTUALLY(condition) \ - { \ - if (!(condition)) { \ - acquire_privatization_lock(STM_SEGMENT->segment_num);\ - if (!(condition)) \ - stm_fatalerror("fails: " #condition); \ - release_privatization_lock(STM_SEGMENT->segment_num);\ - } \ - } -#endif - /* General helper: copies objects into our own segment, from some source described by a range of 'struct stm_undo_s'. Maybe later we could specialize this function to avoid the checks in the @@ -280,7 +266,7 @@ dprintf(("_stm_validate(%p)\n", free_if_abort)); /* go from last known entry in commit log to the most current one and apply all changes done - by other transactions. Abort if we read one of + by other transactions. Abort if we have read one of the committed objs. */ struct stm_commit_log_entry_s *first_cl = STM_PSEGMENT->last_commit_log_entry; struct stm_commit_log_entry_s *next_cl, *last_cl, *cl; @@ -346,6 +332,10 @@ segment_really_copied_from |= (1UL << cl->segment_num); import_objects(cl->segment_num, -1, undo, end); + + copy_bk_objs_in_page_from( + segnum, -1, /* any page */ + !needs_abort); /* if we abort, we still want to copy everything */ } /* last fully validated entry */ @@ -355,18 +345,15 @@ } assert(cl == last_cl); - OPT_ASSERT(segment_really_copied_from < (1 << NB_SEGMENTS)); - int segnum; - for (segnum = 0; segnum < NB_SEGMENTS; segnum++) { - if (segment_really_copied_from & (1UL << segnum)) { - /* here we can actually have our own modified version, so - make sure to only copy things that are not modified in our - segment... (if we do not abort) */ - copy_bk_objs_in_page_from( - segnum, -1, /* any page */ - !needs_abort); /* if we abort, we still want to copy everything */ - } - } + /* OPT_ASSERT(segment_really_copied_from <= ((1UL << NB_SEGMENTS) - 1)); */ + /* int segnum; */ + /* for (segnum = 0; segnum < NB_SEGMENTS; segnum++) { */ + /* if (segment_really_copied_from & (1UL << segnum)) { */ + /* /\* here we can actually have our own modified version, so */ + /* make sure to only copy things that are not modified in our */ + /* segment... (if we do not abort) *\/ */ + /* } */ + /* } */ } /* done with modifications */ @@ -654,7 +641,7 @@ enter_safe_point_if_requested(); dprintf(("> start_transaction\n")); - s_mutex_unlock(); + s_mutex_unlock(); // XXX it's probably possible to not acquire this here uint8_t old_rv = STM_SEGMENT->transaction_read_version; STM_SEGMENT->transaction_read_version = old_rv + 1; diff --git a/c8/stm/core.h b/c8/stm/core.h --- a/c8/stm/core.h +++ b/c8/stm/core.h @@ -73,7 +73,7 @@ struct tree_s *young_outside_nursery; struct tree_s *nursery_objects_shadows; - uint8_t privatization_lock; + uint8_t privatization_lock; // XXX KILL uint8_t safe_point; uint8_t transaction_state; diff --git a/c8/stm/gcpage.c b/c8/stm/gcpage.c --- a/c8/stm/gcpage.c +++ b/c8/stm/gcpage.c @@ -5,9 +5,8 @@ static void setup_gcpage(void) { - /* XXXXXXX should use stm_file_pages, no? */ - uninitialized_page_start = stm_file_pages; - uninitialized_page_stop = stm_file_pages + NB_SHARED_PAGES * 4096UL; + //uninitialized_page_start = stm_file_pages; + //uninitialized_page_stop = stm_file_pages + NB_SHARED_PAGES * 4096UL; } static void teardown_gcpage(void) diff --git a/c8/stm/gcpage.h b/c8/stm/gcpage.h --- a/c8/stm/gcpage.h +++ b/c8/stm/gcpage.h @@ -2,8 +2,8 @@ /* Granularity when grabbing more unused pages: take 50 at a time */ #define GCPAGE_NUM_PAGES 50 -static char *uninitialized_page_start; /* within segment 0 */ -static char *uninitialized_page_stop; +//static char *uninitialized_page_start; /* within segment 0 */ +//static char *uninitialized_page_stop; static void setup_gcpage(void); static void teardown_gcpage(void); diff --git a/c8/stm/pages.c b/c8/stm/pages.c --- a/c8/stm/pages.c +++ b/c8/stm/pages.c @@ -16,71 +16,26 @@ /************************************************************/ -static void pages_initialize_shared_for(long segnum, uintptr_t pagenum, uintptr_t count) + +static void page_mark_accessible(long segnum, uintptr_t pagenum) { - /* call remap_file_pages() to make all pages in the range(pagenum, - pagenum+count) PAGE_SHARED in segnum, and PAGE_NO_ACCESS in other segments - initialize to |S|N|N|N| */ + assert(get_page_status_in(segnum, pagenum) == PAGE_NO_ACCESS); + dprintf(("page_mark_accessible(%lu) in seg:%ld\n", pagenum, segnum)); - dprintf(("pages_initialize_shared: 0x%ld - 0x%ld\n", pagenum, pagenum + count)); + mprotect(get_virtual_page(segnum, pagenum), 4096, PROT_READ | PROT_WRITE); - assert(all_privatization_locks_acquired()); - - assert(pagenum < NB_PAGES); - if (count == 0) - return; - - /* already shared after setup.c (also for the other count-1 pages) */ - assert(get_page_status_in(segnum, pagenum) == PAGE_SHARED); - - /* make other segments NO_ACCESS: */ - uintptr_t i; - for (i = 0; i < NB_SEGMENTS; i++) { - if (i != segnum) { - char *segment_base = get_segment_base(i); - mprotect(segment_base + pagenum * 4096UL, - count * 4096UL, PROT_NONE); - - /* char *result = mmap( */ - /* segment_base + pagenum * 4096UL, */ - /* count * 4096UL, */ - /* PROT_NONE, */ - /* MAP_FIXED|MAP_NORESERVE|MAP_PRIVATE|MAP_ANONYMOUS, */ - /* -1, 0); */ - /* if (result == MAP_FAILED) */ - /* stm_fatalerror("pages_initialize_shared failed (mmap): %m"); */ - - - long amount = count; - while (amount-->0) { - set_page_status_in(i, pagenum + amount, PAGE_NO_ACCESS); - } - } - } + /* set this flag *after* we un-protected it, because XXX later */ + set_page_status_in(segnum, pagenum, PAGE_ACCESSIBLE); } +static void page_mark_inaccessible(long segnum, uintptr_t pagenum) +{ + assert(get_page_status_in(segnum, pagenum) == PAGE_ACCESSIBLE); + dprintf(("page_mark_inaccessible(%lu) in seg:%ld\n", pagenum, segnum)); -static void page_privatize_in(int segnum, uintptr_t pagenum) -{ -#ifndef NDEBUG - long l; - for (l = 0; l < NB_SEGMENTS; l++) { - assert(get_priv_segment(l)->privatization_lock); - } -#endif - assert(get_page_status_in(segnum, pagenum) == PAGE_NO_ACCESS); - dprintf(("page_privatize(%lu) in seg:%d\n", pagenum, segnum)); + set_page_status_in(segnum, pagenum, PAGE_ACCESSIBLE); - char *addr = (char*)(get_virt_page_of(segnum, pagenum) * 4096UL); - char *result = mmap( - addr, 4096UL, PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_PRIVATE | MAP_NORESERVE, - stm_object_pages_fd, get_file_page_of(pagenum) * 4096UL); - if (result == MAP_FAILED) - stm_fatalerror("page_privatize_in failed (mmap): %m"); - - set_page_status_in(segnum, pagenum, PAGE_PRIVATE); - - volatile char *dummy = REAL_ADDRESS(get_segment_base(segnum), pagenum*4096UL); - *dummy = *dummy; /* force copy-on-write from shared page */ + char *addr = get_virtual_page(segnum, pagenum); + madvise(get_virtual_page(segnum, pagenum), 4096, MADV_DONTNEED); + mprotect(addr, 4096, PROT_NONE); } diff --git a/c8/stm/pages.h b/c8/stm/pages.h --- a/c8/stm/pages.h +++ b/c8/stm/pages.h @@ -3,90 +3,61 @@ logical page We have virtual pages: one virtual address can point in some virtual page. We have NB_SEGMENTS virtual pages per logical page. - We have file pages: they correspond mostly to physical memory pages - used for mmap/remap_file_pages - A logical page is SHARED iff all NB_SEGMENTS virtual pages point to - one file page, and thus to the same logical page. - - A logical page becomes PRIVATE if one virtual page still maps to the - original file page, and all others turn read protected. - -> only one can modify it. - - A logical page can also be "PRIVATE IN A SEGMENT", referring to - the virtual page of the segment having its own file page backing. - It also implies the logical page is not read protected. + Each virtual page is either accessible, or PAGE_NO_ACCESS (and then + has no underlying memory). */ #define PAGE_FLAG_START END_NURSERY_PAGE #define PAGE_FLAG_END NB_PAGES -/* == NB_SHARED_PAGES */ struct page_shared_s { -#if NB_SEGMENTS <= 4 +#if NB_SEGMENTS <= 8 uint8_t by_segment; -#elif NB_SEGMENTS <= 8 +#elif NB_SEGMENTS <= 16 uint16_t by_segment; -#elif NB_SEGMENTS <= 16 +#elif NB_SEGMENTS <= 32 uint32_t by_segment; -#elif NB_SEGMENTS <= 32 +#elif NB_SEGMENTS <= 64 uint64_t by_segment; #else -# error "NB_SEGMENTS > 32 not supported right now" +# error "NB_SEGMENTS > 64 not supported right now" #endif }; enum { - PAGE_SHARED = 0, - PAGE_PRIVATE = 1, - PAGE_NO_ACCESS = 2, + PAGE_NO_ACCESS = 0, + PAGE_ACCESSIBLE = 1 }; -static struct page_shared_s pages_status[NB_SHARED_PAGES]; +static struct page_shared_s pages_status[PAGE_FLAG_END - PAGE_FLAG_START]; -static void pages_initialize_shared_for(long segnum, uintptr_t pagenum, uintptr_t count); -static void page_privatize_in(int segnum, uintptr_t pagenum); +static void page_mark_accessible(long segnum, uintptr_t pagenum); +static void page_mark_inaccessible(long segnum, uintptr_t pagenum); - - -static inline uintptr_t get_virt_page_of(long segnum, uintptr_t pagenum) +static inline char *get_virtual_page(long segnum, uintptr_t pagenum) { /* logical page -> virtual page */ - return (uintptr_t)get_segment_base(segnum) / 4096UL + pagenum; + return get_segment_base(segnum) + pagenum * 4096; } -static inline uintptr_t get_file_page_of(uintptr_t pagenum) +static inline bool get_page_status_in(long segnum, uintptr_t pagenum) { - /* logical page -> file page */ - return pagenum - PAGE_FLAG_START; + OPT_ASSERT(segnum < 8 * sizeof(struct page_shared_s)); + volatile struct page_shared_s *ps = (volatile struct page_shared_s *) + &pages_status[pagenum - PAGE_FLAG_START]; + + return (ps->by_segment >> segnum) & 1; } -static inline uintptr_t get_page_of_file_page(uintptr_t file_page) +static inline void set_page_status_in(long segnum, uintptr_t pagenum, + bool status) { - return file_page + END_NURSERY_PAGE; -} - -static inline uint8_t get_page_status_in(long segnum, uintptr_t pagenum) -{ - int seg_shift = segnum * 2; - OPT_ASSERT(seg_shift < 8 * sizeof(struct page_shared_s)); + OPT_ASSERT(segnum < 8 * sizeof(struct page_shared_s)); volatile struct page_shared_s *ps = (volatile struct page_shared_s *) - &pages_status[get_file_page_of(pagenum)]; - - return (ps->by_segment >> seg_shift) & 3; -} - -static inline void set_page_status_in(long segnum, uintptr_t pagenum, uint8_t status) -{ - OPT_ASSERT(status < 3); - - int seg_shift = segnum * 2; - OPT_ASSERT(seg_shift < 8 * sizeof(struct page_shared_s)); - volatile struct page_shared_s *ps = (volatile struct page_shared_s *) - &pages_status[get_file_page_of(pagenum)]; + &pages_status[pagenum - PAGE_FLAG_START]; assert(status != get_page_status_in(segnum, pagenum)); - ps->by_segment &= ~(3UL << seg_shift); /* clear */ - ps->by_segment |= status << seg_shift; /* set */ + __sync_fetch_and_xor(&ps->by_segment, 1UL << segnum); /* invert the flag */ } diff --git a/c8/stm/setup.c b/c8/stm/setup.c --- a/c8/stm/setup.c +++ b/c8/stm/setup.c @@ -7,56 +7,14 @@ static void setup_mmap(char *reason) { - char name[] = "/__stmgc_c8__"; - - /* Create the big shared memory object, and immediately unlink it. - There is a small window where if this process is killed the - object is left around. It doesn't seem possible to do anything - about it... - */ - stm_object_pages_fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); - shm_unlink(name); - - if (stm_object_pages_fd == -1) - stm_fatalerror("%s failed (stm_open): %m", reason); - - if (ftruncate(stm_object_pages_fd, NB_SHARED_PAGES * 4096UL) != 0) - stm_fatalerror("%s failed (ftruncate): %m", reason); - - stm_file_pages = mmap(NULL, NB_SHARED_PAGES * 4096UL, - PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_NORESERVE, - stm_object_pages_fd, 0); - - if (stm_file_pages == MAP_FAILED) - stm_fatalerror("%s failed (mmap): %m", reason); - - /* reserve the whole virtual memory space of the program for - all segments: */ - stm_object_pages = mmap(NULL, TOTAL_MEMORY, - PROT_READ | PROT_WRITE, + all segments: (for now in one big block, but later could be + allocated per-segment) */ + stm_object_pages = mmap(NULL, TOTAL_MEMORY, PROT_NONE, MAP_PRIVATE | MAP_NORESERVE | MAP_ANONYMOUS, -1, 0); if (stm_object_pages == MAP_FAILED) stm_fatalerror("%s failed (mmap): %m", reason); - - /* remap the shared part of the segments to the file pages */ - long l; - for (l = 0; l < NB_SEGMENTS; l++) { - char *result = mmap( - stm_object_pages + (l * NB_PAGES + END_NURSERY_PAGE) * 4096UL, /* addr */ - NB_SHARED_PAGES * 4096UL, /* len */ - PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_SHARED | MAP_NORESERVE, - stm_object_pages_fd, 0); /* file & offset */ - if (result == MAP_FAILED) - stm_fatalerror("%s failed (mmap): %m", reason); - } -} -static void close_fd_mmap(int map_fd) -{ - close(map_fd); } static void setup_protection_settings(void) @@ -65,17 +23,13 @@ for (i = 0; i < NB_SEGMENTS; i++) { char *segment_base = get_segment_base(i); - /* In each segment, the first page is where TLPREFIX'ed - NULL accesses land. We mprotect it so that accesses fail. */ - mprotect(segment_base, 4096, PROT_NONE); + /* In each segment, the second page is where STM_SEGMENT lands. */ + mprotect(segment_base + 4096, 4096, PROT_READ | PROT_WRITE); - /* Pages in range(2, FIRST_READMARKER_PAGE) are never used */ - if (FIRST_READMARKER_PAGE > 2) - mprotect(segment_base + 2 * 4096, - (FIRST_READMARKER_PAGE - 2) * 4096UL, - PROT_NONE); - - /* STM_SEGMENT-TL is in page 1 */ + /* Make the read marker pages accessible, as well as the nursery. */ + mprotect(segment_base + FIRST_READMARKER_PAGE * 4096, + (NB_READMARKER_PAGES + NB_NURSERY_PAGES) * 4096, + PROT_READ | PROT_WRITE); } } @@ -184,7 +138,6 @@ stm_object_pages = NULL; commit_log_root.next = NULL; /* xxx:free them */ commit_log_root.segment_num = -1; - close_fd_mmap(stm_object_pages_fd); teardown_sync(); teardown_gcpage(); From noreply at buildbot.pypy.org Wed Dec 3 08:31:13 2014 From: noreply at buildbot.pypy.org (Raemi) Date: Wed, 3 Dec 2014 08:31:13 +0100 (CET) Subject: [pypy-commit] stmgc c8-small-uniform: add test showing a bug in stm_validate() Message-ID: <20141203073113.87C581C07E8@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: c8-small-uniform Changeset: r1511:c849b169bc4e Date: 2014-12-02 15:56 +0100 http://bitbucket.org/pypy/stmgc/changeset/c849b169bc4e/ Log: add test showing a bug in stm_validate() diff --git a/c8/stm/gcpage.c b/c8/stm/gcpage.c --- a/c8/stm/gcpage.c +++ b/c8/stm/gcpage.c @@ -5,7 +5,6 @@ static void setup_gcpage(void) { - /* XXXXXXX should use stm_file_pages, no? */ uninitialized_page_start = stm_file_pages; uninitialized_page_stop = stm_file_pages + NB_SHARED_PAGES * 4096UL; } diff --git a/c8/test/test_basic.py b/c8/test/test_basic.py --- a/c8/test/test_basic.py +++ b/c8/test/test_basic.py @@ -811,6 +811,33 @@ assert stm_get_char(lp_char_5, 384 - 1) == 'o' + def test_bug3(self): + lp_char_5 = stm_allocate_old(384) + + for i in range(NB_SEGMENTS): + self.start_transaction() + stm_set_char(lp_char_5, '\0', HDR, False) + self.commit_transaction() + + # + self.switch(2) + self.start_transaction() + stm_set_char(lp_char_5, 'i', HDR, False) + self.commit_transaction() + + self.start_transaction() + stm_set_char(lp_char_5, 'x', HDR, False) + + self.switch(1) + self.start_transaction() + stm_set_char(lp_char_5, 'a', HDR, False) + self.commit_transaction() + + self.switch(0) + self.start_transaction() + assert stm_get_char(lp_char_5, HDR) == 'a' + + def test_repeated_wb(self): lp_char_5 = stm_allocate_old(384) From noreply at buildbot.pypy.org Wed Dec 3 08:31:14 2014 From: noreply at buildbot.pypy.org (Raemi) Date: Wed, 3 Dec 2014 08:31:14 +0100 (CET) Subject: [pypy-commit] stmgc c8-small-uniform: fix for previous commit Message-ID: <20141203073114.9AB061C07E8@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: c8-small-uniform Changeset: r1512:757f479c2b41 Date: 2014-12-02 16:12 +0100 http://bitbucket.org/pypy/stmgc/changeset/757f479c2b41/ Log: fix for previous commit diff --git a/c8/stm/core.c b/c8/stm/core.c --- a/c8/stm/core.c +++ b/c8/stm/core.c @@ -3,20 +3,6 @@ #endif -#ifdef NDEBUG -#define EVENTUALLY(condition) {/* nothing */} -#else -#define EVENTUALLY(condition) \ - { \ - if (!(condition)) { \ - acquire_privatization_lock(STM_SEGMENT->segment_num);\ - if (!(condition)) \ - stm_fatalerror("fails: " #condition); \ - release_privatization_lock(STM_SEGMENT->segment_num);\ - } \ - } -#endif - /* General helper: copies objects into our own segment, from some source described by a range of 'struct stm_undo_s'. Maybe later we could specialize this function to avoid the checks in the @@ -346,6 +332,13 @@ segment_really_copied_from |= (1UL << cl->segment_num); import_objects(cl->segment_num, -1, undo, end); + + /* here we can actually have our own modified version, so + make sure to only copy things that are not modified in our + segment... (if we do not abort) */ + copy_bk_objs_in_page_from + (cl->segment_num, -1, /* any page */ + !needs_abort); /* if we abort, we still want to copy everything */ } /* last fully validated entry */ @@ -355,18 +348,19 @@ } assert(cl == last_cl); - OPT_ASSERT(segment_really_copied_from < (1 << NB_SEGMENTS)); - int segnum; - for (segnum = 0; segnum < NB_SEGMENTS; segnum++) { - if (segment_really_copied_from & (1UL << segnum)) { - /* here we can actually have our own modified version, so - make sure to only copy things that are not modified in our - segment... (if we do not abort) */ - copy_bk_objs_in_page_from( - segnum, -1, /* any page */ - !needs_abort); /* if we abort, we still want to copy everything */ - } - } + /* XXX: this optimization fails in test_basic.py, bug3 */ + /* OPT_ASSERT(segment_really_copied_from < (1 << NB_SEGMENTS)); */ + /* int segnum; */ + /* for (segnum = 0; segnum < NB_SEGMENTS; segnum++) { */ + /* if (segment_really_copied_from & (1UL << segnum)) { */ + /* /\* here we can actually have our own modified version, so */ + /* make sure to only copy things that are not modified in our */ + /* segment... (if we do not abort) *\/ */ + /* copy_bk_objs_in_page_from( */ + /* segnum, -1, /\* any page *\/ */ + /* !needs_abort); /\* if we abort, we still want to copy everything *\/ */ + /* } */ + /* } */ } /* done with modifications */ @@ -503,6 +497,7 @@ assert(!(bk_obj->stm_flags & GCFLAG_WB_EXECUTED)); dprintf(("write_slowpath(%p): sz=%lu, bk=%p\n", obj, obj_size, bk_obj)); + retry: /* privatize pages: */ /* XXX don't always acquire all locks... */ @@ -553,6 +548,7 @@ /* all pages are either private or we were the first to write to a shared page and therefore got it as our private one */ + /* phew, now add the obj to the write-set and register the backup copy. */ /* XXX: we should not be here at all fiddling with page status diff --git a/c8/test/test_basic.py b/c8/test/test_basic.py --- a/c8/test/test_basic.py +++ b/c8/test/test_basic.py @@ -828,15 +828,20 @@ self.start_transaction() stm_set_char(lp_char_5, 'x', HDR, False) + # self.switch(1) self.start_transaction() stm_set_char(lp_char_5, 'a', HDR, False) self.commit_transaction() - + + # self.switch(0) self.start_transaction() assert stm_get_char(lp_char_5, HDR) == 'a' + # + py.test.raises(Conflict, self.switch, 2) + def test_repeated_wb(self): lp_char_5 = stm_allocate_old(384) From noreply at buildbot.pypy.org Wed Dec 3 08:31:15 2014 From: noreply at buildbot.pypy.org (Raemi) Date: Wed, 3 Dec 2014 08:31:15 +0100 (CET) Subject: [pypy-commit] stmgc c8-small-uniform: fix another (currently untestable) bug Message-ID: <20141203073115.C9D261C07E8@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: c8-small-uniform Changeset: r1513:222d1845dff3 Date: 2014-12-02 17:00 +0100 http://bitbucket.org/pypy/stmgc/changeset/222d1845dff3/ Log: fix another (currently untestable) bug diff --git a/c8/stm/core.c b/c8/stm/core.c --- a/c8/stm/core.c +++ b/c8/stm/core.c @@ -278,94 +278,108 @@ return; } - /* Find the set of segments we need to copy from and lock them: */ - uint64_t segments_to_lock = 1UL << my_segnum; - cl = first_cl; - while ((next_cl = cl->next) != NULL) { - if (next_cl == INEV_RUNNING) { + bool needs_abort = false; + + while(1) { + /* retry IF: */ + /* if at the time of "HERE" (s.b.) there happen to be + more commits (and bk copies) then it could be that + copy_bk_objs_in_page_from (s.b.) reads a bk copy that + is itself more recent than last_cl. This is fixed + by re-validating. */ + first_cl = STM_PSEGMENT->last_commit_log_entry; + if (first_cl->next == NULL) + break; + + /* Find the set of segments we need to copy from and lock them: */ + uint64_t segments_to_lock = 1UL << my_segnum; + cl = first_cl; + while ((next_cl = cl->next) != NULL) { + if (next_cl == INEV_RUNNING) { #if STM_TESTS - if (free_if_abort != (void *)-1) - free(free_if_abort); - stm_abort_transaction(); + if (free_if_abort != (void *)-1) + free(free_if_abort); + stm_abort_transaction(); #endif - /* only validate entries up to INEV */ - break; + /* only validate entries up to INEV */ + break; + } + assert(next_cl->rev_num > cl->rev_num); + cl = next_cl; + + if (cl->written_count) { + segments_to_lock |= (1UL << cl->segment_num); + } } - assert(next_cl->rev_num > cl->rev_num); - cl = next_cl; + last_cl = cl; + /* HERE */ + acquire_modification_lock_set(segments_to_lock); - if (cl->written_count) { - segments_to_lock |= (1UL << cl->segment_num); - } - } - last_cl = cl; - acquire_modification_lock_set(segments_to_lock); + /* import objects from first_cl to last_cl: */ + if (first_cl != last_cl) { + uint64_t segment_really_copied_from = 0UL; - /* import objects from first_cl to last_cl: */ - bool needs_abort = false; - if (first_cl != last_cl) { - uint64_t segment_really_copied_from = 0UL; - - cl = first_cl; - while ((cl = cl->next) != NULL) { - if (!needs_abort) { - struct stm_undo_s *undo = cl->written; - struct stm_undo_s *end = cl->written + cl->written_count; - for (; undo < end; undo++) { - if (_stm_was_read(undo->object)) { - /* first reset all modified objects from the backup - copies as soon as the first conflict is detected; - then we will proceed below to update our segment from - the old (but unmodified) version to the newer version. - */ - reset_modified_from_backup_copies(my_segnum); - needs_abort = true; - break; + cl = first_cl; + while ((cl = cl->next) != NULL) { + if (!needs_abort) { + struct stm_undo_s *undo = cl->written; + struct stm_undo_s *end = cl->written + cl->written_count; + for (; undo < end; undo++) { + if (_stm_was_read(undo->object)) { + /* first reset all modified objects from the backup + copies as soon as the first conflict is detected; + then we will proceed below to update our segment from + the old (but unmodified) version to the newer version. + */ + reset_modified_from_backup_copies(my_segnum); + needs_abort = true; + break; + } } } + + if (cl->written_count) { + struct stm_undo_s *undo = cl->written; + struct stm_undo_s *end = cl->written + cl->written_count; + + segment_really_copied_from |= (1UL << cl->segment_num); + import_objects(cl->segment_num, -1, undo, end); + + /* here we can actually have our own modified version, so + make sure to only copy things that are not modified in our + segment... (if we do not abort) */ + copy_bk_objs_in_page_from + (cl->segment_num, -1, /* any page */ + !needs_abort); /* if we abort, we still want to copy everything */ + } + + /* last fully validated entry */ + STM_PSEGMENT->last_commit_log_entry = cl; + if (cl == last_cl) + break; } + assert(cl == last_cl); - if (cl->written_count) { - struct stm_undo_s *undo = cl->written; - struct stm_undo_s *end = cl->written + cl->written_count; + /* XXX: this optimization fails in test_basic.py, bug3 */ + /* OPT_ASSERT(segment_really_copied_from < (1 << NB_SEGMENTS)); */ + /* int segnum; */ + /* for (segnum = 0; segnum < NB_SEGMENTS; segnum++) { */ + /* if (segment_really_copied_from & (1UL << segnum)) { */ + /* /\* here we can actually have our own modified version, so */ + /* make sure to only copy things that are not modified in our */ + /* segment... (if we do not abort) *\/ */ + /* copy_bk_objs_in_page_from( */ + /* segnum, -1, /\* any page *\/ */ + /* !needs_abort); /\* if we abort, we still want to copy everything *\/ */ + /* } */ + /* } */ + } - segment_really_copied_from |= (1UL << cl->segment_num); - import_objects(cl->segment_num, -1, undo, end); - - /* here we can actually have our own modified version, so - make sure to only copy things that are not modified in our - segment... (if we do not abort) */ - copy_bk_objs_in_page_from - (cl->segment_num, -1, /* any page */ - !needs_abort); /* if we abort, we still want to copy everything */ - } - - /* last fully validated entry */ - STM_PSEGMENT->last_commit_log_entry = cl; - if (cl == last_cl) - break; - } - assert(cl == last_cl); - - /* XXX: this optimization fails in test_basic.py, bug3 */ - /* OPT_ASSERT(segment_really_copied_from < (1 << NB_SEGMENTS)); */ - /* int segnum; */ - /* for (segnum = 0; segnum < NB_SEGMENTS; segnum++) { */ - /* if (segment_really_copied_from & (1UL << segnum)) { */ - /* /\* here we can actually have our own modified version, so */ - /* make sure to only copy things that are not modified in our */ - /* segment... (if we do not abort) *\/ */ - /* copy_bk_objs_in_page_from( */ - /* segnum, -1, /\* any page *\/ */ - /* !needs_abort); /\* if we abort, we still want to copy everything *\/ */ - /* } */ - /* } */ + /* done with modifications */ + release_modification_lock_set(segments_to_lock); } - /* done with modifications */ - release_modification_lock_set(segments_to_lock); - if (needs_abort) { if (free_if_abort != (void *)-1) free(free_if_abort); From noreply at buildbot.pypy.org Wed Dec 3 11:06:40 2014 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 3 Dec 2014 11:06:40 +0100 (CET) Subject: [pypy-commit] pypy default: oups. test and fix Message-ID: <20141203100640.0C54F1D2925@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r74793:d088178015dd Date: 2014-12-03 11:06 +0100 http://bitbucket.org/pypy/pypy/changeset/d088178015dd/ Log: oups. test and fix diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py --- a/rpython/jit/backend/test/runner_test.py +++ b/rpython/jit/backend/test/runner_test.py @@ -3892,12 +3892,16 @@ def test_int_signext(self): numbytes_cases = [1, 2] if IS_32_BIT else [1, 2, 4] - for numbytes in numbytes_cases: + for spill in ["", "force_spill(i1)"]: + for numbytes in numbytes_cases: + print (spill, numbytes) ops = """ [i0] - i1 = int_signext(i0, %d) - finish(i1, descr=descr) - """ % numbytes + i1 = int_sub(i0, 0) # force in register + %s + i2 = int_signext(i1, %d) + finish(i2, descr=descr) + """ % (spill, numbytes) descr = BasicFinalDescr() loop = parse(ops, self.cpu, namespace=locals()) looptoken = JitCellToken() diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1148,6 +1148,8 @@ argloc, numbytesloc = arglocs assert isinstance(numbytesloc, ImmedLoc) if numbytesloc.value == 1: + if isinstance(argloc, RegLoc): + argloc = argloc.lowest8bits() self.mc.MOVSX8(resloc, argloc) elif numbytesloc.value == 2: self.mc.MOVSX16(resloc, argloc) From noreply at buildbot.pypy.org Wed Dec 3 11:33:05 2014 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 3 Dec 2014 11:33:05 +0100 (CET) Subject: [pypy-commit] pypy default: Add INT_SIGNEXT to test_random, and found out another corner case on Message-ID: <20141203103305.9BD0E1C1147@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r74794:4634aad50952 Date: 2014-12-03 11:29 +0100 http://bitbucket.org/pypy/pypy/changeset/4634aad50952/ Log: Add INT_SIGNEXT to test_random, and found out another corner case on 32-bit only. diff --git a/rpython/jit/backend/test/test_random.py b/rpython/jit/backend/test/test_random.py --- a/rpython/jit/backend/test/test_random.py +++ b/rpython/jit/backend/test/test_random.py @@ -321,6 +321,14 @@ else: self.put(builder, [ConstFloat(r.random_float_storage())]) +class SignExtOperation(AbstractOperation): + def produce_into(self, builder, r): + sizes = [1, 2] + if sys.maxint > (1 << 32): + sizes.append(4) + self.put(builder, [r.choice(builder.intvars), + ConstInt(r.choice(sizes))]) + class BinaryOperation(AbstractOperation): def __init__(self, opnum, and_mask=-1, or_mask=0, boolres=False): AbstractOperation.__init__(self, opnum, boolres=boolres) @@ -509,6 +517,7 @@ OPERATIONS.append(UnaryOperation(rop.INT_IS_TRUE, boolres=True)) OPERATIONS.append(UnaryOperation(rop.INT_IS_ZERO, boolres=True)) OPERATIONS.append(ConstUnaryOperation(rop.SAME_AS, boolres='sometimes')) +OPERATIONS.append(SignExtOperation(rop.INT_SIGNEXT)) for _op in [rop.INT_ADD_OVF, rop.INT_SUB_OVF, diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1147,9 +1147,20 @@ def genop_int_signext(self, op, arglocs, resloc): argloc, numbytesloc = arglocs assert isinstance(numbytesloc, ImmedLoc) + assert isinstance(resloc, RegLoc) if numbytesloc.value == 1: if isinstance(argloc, RegLoc): - argloc = argloc.lowest8bits() + if WORD == 4 and argloc.value >= 4: + # meh, can't read the lowest byte of esi or edi on 32-bit + if resloc.value < 4: + self.mc.MOV(resloc, argloc) + argloc = resloc + else: + tmploc = RawEspLoc(0, INT) + self.mc.MOV(tmploc, argloc) + argloc = tmploc + if isinstance(argloc, RegLoc): + argloc = argloc.lowest8bits() self.mc.MOVSX8(resloc, argloc) elif numbytesloc.value == 2: self.mc.MOVSX16(resloc, argloc) diff --git a/rpython/jit/backend/x86/regloc.py b/rpython/jit/backend/x86/regloc.py --- a/rpython/jit/backend/x86/regloc.py +++ b/rpython/jit/backend/x86/regloc.py @@ -151,6 +151,8 @@ def lowest8bits(self): assert not self.is_xmm + if WORD == 4: + assert 0 <= self.value < 4 return RegLoc(rx86.low_byte(self.value), False) def higher8bits(self): diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py --- a/rpython/jit/backend/x86/rx86.py +++ b/rpython/jit/backend/x86/rx86.py @@ -33,8 +33,9 @@ xmmnames = ['xmm%d' % i for i in range(16)] def low_byte(reg): - # XXX: On 32-bit, this only works for 0 <= reg < 4 - # Maybe we should check this? + # On 32-bit, this only works for 0 <= reg < 4. The caller checks that. + # On 64-bit, it works for any register, but the assembler instruction + # must include a REX prefix (possibly with no modifier flags). return reg | BYTE_REG_FLAG def high_byte(reg): From noreply at buildbot.pypy.org Wed Dec 3 12:20:01 2014 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 3 Dec 2014 12:20:01 +0100 (CET) Subject: [pypy-commit] pypy default: fix a bit more cleanly without writing to the stack Message-ID: <20141203112001.5FB231D286C@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r74795:4e877792713b Date: 2014-12-03 12:19 +0100 http://bitbucket.org/pypy/pypy/changeset/4e877792713b/ Log: fix a bit more cleanly without writing to the stack diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py --- a/rpython/jit/backend/x86/assembler.py +++ b/rpython/jit/backend/x86/assembler.py @@ -1152,15 +1152,15 @@ if isinstance(argloc, RegLoc): if WORD == 4 and argloc.value >= 4: # meh, can't read the lowest byte of esi or edi on 32-bit - if resloc.value < 4: + if resloc is not argloc: self.mc.MOV(resloc, argloc) argloc = resloc - else: - tmploc = RawEspLoc(0, INT) - self.mc.MOV(tmploc, argloc) - argloc = tmploc - if isinstance(argloc, RegLoc): - argloc = argloc.lowest8bits() + if resloc.value >= 4: + # still annoyed, hack needed + self.mc.SHL_ri(resloc.value, 24) + self.mc.SAR_ri(resloc.value, 24) + return + argloc = argloc.lowest8bits() self.mc.MOVSX8(resloc, argloc) elif numbytesloc.value == 2: self.mc.MOVSX16(resloc, argloc) From noreply at buildbot.pypy.org Wed Dec 3 15:19:52 2014 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 3 Dec 2014 15:19:52 +0100 (CET) Subject: [pypy-commit] creflect default: pointer types Message-ID: <20141203141952.93E711C363D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r140:dc4373af8fab Date: 2014-12-03 15:20 +0100 http://bitbucket.org/cffi/creflect/changeset/dc4373af8fab/ Log: pointer types diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -10,30 +10,63 @@ PyObject *types_dict; } zeffir_builder_t; -static CTypeDescrObject *get_cached_type(_crx_builder_t *cb, const char *name, - int accept_flags) +static PyObject *combine_type_name(_crx_builder_t *cb, CTypeDescrObject *ct, + const char *extra_text) +{ + /* Build a PyString with the name given by combining 'ct' and 'extra_text'. + 'ct' can be NULL. If an error occurs (or has already occurred), + returns NULL. */ + size_t base_name_len, extra_name_len; + PyObject *result; + char *p; + + if (PyErr_Occurred()) + return NULL; + + base_name_len = (ct != NULL ? strlen(ct->ct_name) : 0); + extra_name_len = strlen(extra_text); + result = PyString_FromStringAndSize(NULL, base_name_len + extra_name_len); + if (result == NULL) + return NULL; + + p = PyString_AS_STRING(result); + if (ct != NULL) { + memcpy(p, ct->ct_name, ct->ct_name_position); + p += ct->ct_name_position; + } + memcpy(p, extra_text, extra_name_len); + if (ct != NULL) { + p += extra_name_len; + memcpy(p, ct->ct_name + ct->ct_name_position, + base_name_len - ct->ct_name_position); + } + return result; +} + +static CTypeDescrObject *get_cached_type(_crx_builder_t *cb, PyObject *name_obj) +{ + /* Look up the type called 'name_obj' and check that it's a type with the + right flags. Returns either the type or NULL, without changing + the reference counts. Never raises an exception. + */ + PyObject *types_dict = ((zeffir_builder_t *)cb)->types_dict; + PyObject *x; + + assert(name_obj != NULL); + x = PyDict_GetItem(types_dict, name_obj); + if (x == NULL || !CTypeDescr_Check(x)) + return NULL; + else + return (CTypeDescrObject *)x; +} + +static void put_cached_type(_crx_builder_t *cb, PyObject *name_obj, + CTypeDescrObject *ct) { PyObject *types_dict = ((zeffir_builder_t *)cb)->types_dict; - PyObject *x = PyDict_GetItemString(types_dict, name); - CTypeDescrObject *ct; - - if (x == NULL || !CTypeDescr_Check(x)) - return NULL; - ct = (CTypeDescrObject *)x; - if ((ct->ct_flags & accept_flags) == 0) - return NULL; - return ct; -} - -static _crx_type_t *put_cached_type(_crx_builder_t *cb, const char *name, - CTypeDescrObject *ct) -{ - PyObject *types_dict = ((zeffir_builder_t *)cb)->types_dict; - int err = PyDict_SetItemString(types_dict, name, (PyObject *)ct); - Py_DECREF(ct); - if (err < 0) - return NULL; - return ct; /* still a reference in the dict */ + PyDict_SetItem(types_dict, name_obj, (PyObject *)ct); + Py_DECREF(ct); /* still a reference in the dict, + unless PyDict_SetItem failed */ } static _crx_type_t *zef_get_void_type(_crx_builder_t *cb) @@ -54,26 +87,33 @@ static _crx_type_t *zef_get_signed_type(_crx_builder_t *cb, size_t sz, const char *name) { - CTypeDescrObject *td = get_cached_type(cb, name, CT_PRIMITIVE_SIGNED); - if (td != NULL && td->ct_size == sz) - return td; + PyObject *name_obj; + CTypeDescrObject *ct; - size_t name_length = strlen(name); - - td = ctypedescr_new(name_length + 1); - if (td == NULL) + name_obj = combine_type_name(cb, NULL, name); + if (name_obj == NULL) return NULL; - memcpy(td->ct_name, name, name_length + 1); - td->ct_name_position = name_length; - td->ct_size = sz; - //td->ct_length = ptypes->align; - //td->ct_extra = ffitype; - td->ct_flags = CT_PRIMITIVE_SIGNED; - if (td->ct_size <= sizeof(long)) - td->ct_flags |= CT_PRIMITIVE_FITS_LONG; + ct = get_cached_type(cb, name_obj); + if (ct && (ct->ct_flags & CT_PRIMITIVE_SIGNED) && ct->ct_size == sz) + goto done; - return put_cached_type(cb, name, td); + ct = ctypedescr_new(name_obj, PyString_GET_SIZE(name_obj)); + if (ct == NULL) + goto done; + + ct->ct_size = sz; + //ct->ct_length = ptypes->align; + //ct->ct_extra = ffitype; + ct->ct_flags = CT_PRIMITIVE_SIGNED; + if (ct->ct_size <= sizeof(long)) + ct->ct_flags |= CT_PRIMITIVE_FITS_LONG; + + put_cached_type(cb, name_obj, ct); + + done: + Py_DECREF(name_obj); + return ct; } static _crx_type_t *zef_get_unsigned_type(_crx_builder_t *cb, size_t sz, @@ -106,7 +146,41 @@ static _crx_type_t *zef_get_pointer_type(_crx_builder_t *cb, _crx_type_t *totype, int toquals) { - abort(); + const char *extra; + PyObject *name_obj; + CTypeDescrObject *ct; + + if (totype->ct_flags & CT_ARRAY) + extra = "(*)"; + else + extra = " *"; + + name_obj = combine_type_name(cb, totype, extra); + if (name_obj == NULL) + return NULL; + + ct = get_cached_type(cb, name_obj); + if (ct && (ct->ct_flags & CT_POINTER)) + goto done; + + ct = ctypedescr_new(name_obj, totype->ct_name_position + 2); + if (ct == NULL) + goto done; + + ct->ct_size = sizeof(void *); + ct->ct_flags = CT_POINTER; + if (totype->ct_flags & CT_VOID) + ct->ct_flags |= CT_IS_VOID_PTR; + if ((totype->ct_flags & CT_VOID) || + ((totype->ct_flags & CT_PRIMITIVE_CHAR) && + totype->ct_size == sizeof(char))) + ct->ct_flags |= CT_CAST_ANYTHING; /* 'void *' or 'char *' only */ + + put_cached_type(cb, name_obj, ct); + + done: + Py_DECREF(name_obj); + return ct; } static _crx_type_t *zef_get_array_type(_crx_builder_t *cb, _crx_type_t *t, diff --git a/zeffir/ctype.c b/zeffir/ctype.c --- a/zeffir/ctype.c +++ b/zeffir/ctype.c @@ -45,7 +45,7 @@ Py_ssize_t ct_length; /* length of arrays, or -1 if unknown */ int ct_flags; /* CT_xxx flags */ - int ct_name_position; /* index in ct_name of where to put a var name */ + size_t ct_name_position;/* index in ct_name of where to put a var name */ char ct_name[1]; /* string, e.g. "int *" for pointers to ints */ }; @@ -64,11 +64,12 @@ /************************************************************/ -static CTypeDescrObject *ctypedescr_new(size_t name_size) +static CTypeDescrObject *ctypedescr_new(PyObject *name_obj, + size_t name_position) { CTypeDescrObject *ct = PyObject_GC_NewVar(CTypeDescrObject, &CTypeDescr_Type, - name_size); + PyString_GET_SIZE(name_obj) + 1); if (ct == NULL) return NULL; @@ -77,6 +78,9 @@ ct->ct_weakreflist = NULL; ct->ct_size = -1; ct->ct_length = -1; + ct->ct_name_position = name_position; + memcpy(ct->ct_name, PyString_AS_STRING(name_obj), + PyString_GET_SIZE(name_obj) + 1); PyObject_GC_Track(ct); return ct; } diff --git a/zeffir/test/test_ctype.py b/zeffir/test/test_ctype.py --- a/zeffir/test/test_ctype.py +++ b/zeffir/test/test_ctype.py @@ -1,8 +1,18 @@ import support -def test_typeof(): +def test_typeof_primitive(): ffi = support.new_ffi() - assert repr(ffi.typeof("int")) == "" - assert repr(ffi.typeof("long int")) == "" - #assert repr(ffi.typeof("int*")) == "" + ct_int = ffi.typeof("int") + assert repr(ct_int) == "" + # + ct_long = ffi.typeof("long int") + assert repr(ct_long) == "" + # + assert ffi.types == {'int': ct_int, + 'long': ct_long, + 'long int': ct_long} + +def test_typeof_pointer(): + ffi = support.new_ffi() + assert repr(ffi.typeof("int*")) == "" From noreply at buildbot.pypy.org Wed Dec 3 18:00:39 2014 From: noreply at buildbot.pypy.org (fijal) Date: Wed, 3 Dec 2014 18:00:39 +0100 (CET) Subject: [pypy-commit] pypy optresult: clean the escape mess and start passing first unrolling tests Message-ID: <20141203170039.82C5C1C363D@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: optresult Changeset: r74796:fe81bdbcbbaa Date: 2014-12-03 18:59 +0200 http://bitbucket.org/pypy/pypy/changeset/fe81bdbcbbaa/ Log: clean the escape mess and start passing first unrolling tests diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py --- a/rpython/jit/metainterp/compile.py +++ b/rpython/jit/metainterp/compile.py @@ -13,7 +13,6 @@ TargetToken, AbstractFailDescr, ConstInt) from rpython.jit.metainterp import history, jitexc from rpython.jit.metainterp.optimize import InvalidLoop -from rpython.jit.metainterp.inliner import Inliner from rpython.jit.metainterp.resume import NUMBERING, PENDINGFIELDSP, ResumeDataDirectReader from rpython.jit.codewriter import heaptracker, longlong @@ -104,9 +103,12 @@ # ____________________________________________________________ class Memo(object): - def __init__(self): + def __init__(self, initial_args=None, initial_res=None): self.snapshots = {} self.box_mapping = {} + if initial_args is not None: + for i in range(len(initial_args)): + self.box_mapping[initial_args[i]] = initial_res[i] def get(self, box, default): return self.box_mapping.get(box, default) diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py --- a/rpython/jit/metainterp/history.py +++ b/rpython/jit/metainterp/history.py @@ -285,6 +285,9 @@ def getfloatstorage(self): return self.value + def getfloat(self): + return longlong.getrealfloat(self.value) + getvalue = getfloatstorage def _get_hash_(self): diff --git a/rpython/jit/metainterp/inliner.py b/rpython/jit/metainterp/inliner.py deleted file mode 100644 --- a/rpython/jit/metainterp/inliner.py +++ /dev/null @@ -1,57 +0,0 @@ -from rpython.jit.metainterp.history import Const -from rpython.jit.metainterp.resume import Snapshot - - -class Inliner(object): - def __init__(self, inputargs, jump_args): - assert len(inputargs) == len(jump_args) - self.argmap = {} - for i in range(len(inputargs)): - if inputargs[i] in self.argmap: - assert self.argmap[inputargs[i]] == jump_args[i] - else: - self.argmap[inputargs[i]] = jump_args[i] - self.snapshot_map = {None: None} - - def inline_op(self, newop, ignore_result=False, clone=True, - ignore_failargs=False): - if clone: - newop = newop.clone() - args = newop.getarglist() - newop.initarglist([self.inline_arg(a) for a in args]) - - if newop.is_guard(): - args = newop.getfailargs() - if args and not ignore_failargs: - newop.setfailargs([self.inline_arg(a) for a in args]) - else: - newop.setfailargs([]) - - if newop.result and not ignore_result: - old_result = newop.result - newop.result = newop.result.clonebox() - self.argmap[old_result] = newop.result - - self.inline_descr_inplace(newop.getdescr()) - - return newop - - def inline_descr_inplace(self, descr): - from rpython.jit.metainterp.compile import ResumeGuardDescr - if isinstance(descr, ResumeGuardDescr): - descr.rd_snapshot = self.inline_snapshot(descr.rd_snapshot) - - def inline_arg(self, arg): - if arg is None: - return None - if isinstance(arg, Const): - return arg - return self.argmap[arg] - - def inline_snapshot(self, snapshot): - if snapshot in self.snapshot_map: - return self.snapshot_map[snapshot] - boxes = [self.inline_arg(a) for a in snapshot.boxes] - new_snapshot = Snapshot(self.inline_snapshot(snapshot.prev), boxes) - self.snapshot_map[snapshot] = new_snapshot - return new_snapshot diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py --- a/rpython/jit/metainterp/optimizeopt/rewrite.py +++ b/rpython/jit/metainterp/optimizeopt/rewrite.py @@ -579,11 +579,11 @@ self.emit_operation(op) def optimize_CAST_PTR_TO_INT(self, op): - self.pure(rop.CAST_INT_TO_PTR, [op.result], op.getarg(0)) + self.pure(rop.CAST_INT_TO_PTR, [op], op.getarg(0)) self.emit_operation(op) def optimize_CAST_INT_TO_PTR(self, op): - self.pure(rop.CAST_PTR_TO_INT, [op.result], op.getarg(0)) + self.pure(rop.CAST_PTR_TO_INT, [op], op.getarg(0)) self.emit_operation(op) def optimize_SAME_AS_i(self, op): diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py @@ -219,14 +219,14 @@ ops = """ [i0] p0 = new_with_vtable(ConstClass(node_vtable)) - escape(p0) + escape_n(p0) guard_class(p0, ConstClass(node_vtable)) [] jump(i0) """ expected = """ [i0] p0 = new_with_vtable(ConstClass(node_vtable)) - escape(p0) + escape_n(p0) jump(i0) """ self.optimize_loop(ops, expected) @@ -315,19 +315,19 @@ def test_remove_consecutive_guard_value_constfold(self): ops = """ [] - i0 = escape() + i0 = escape_i() guard_value(i0, 0) [] i1 = int_add(i0, 1) guard_value(i1, 1) [] i2 = int_add(i1, 2) - escape(i2) + escape_n(i2) jump() """ expected = """ [] - i0 = escape() + i0 = escape_i() guard_value(i0, 0) [] - escape(3) + escape_n(3) jump() """ self.optimize_loop(ops, expected) @@ -428,14 +428,14 @@ def test_ooisnull_on_null_ptr_1(self): ops = """ [] - p0 = escape() + p0 = escape_r() guard_isnull(p0) [] guard_isnull(p0) [] jump() """ expected = """ [] - p0 = escape() + p0 = escape_r() guard_isnull(p0) [] jump() """ @@ -517,7 +517,7 @@ def test_constptr_guard_value(self): ops = """ [] - p1 = escape() + p1 = escape_r() guard_value(p1, ConstPtr(myptr)) [] jump() """ @@ -592,7 +592,7 @@ ops = """ [i1, p2, p3] i3 = getfield_gc_i(p3, descr=valuedescr) - escape(i3) + escape_n(i3) p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p1, i1, descr=valuedescr) jump(i1, p1, p2) @@ -604,7 +604,7 @@ ops = """ [i1, p2, p3] i3 = getfield_gc_i(p3, descr=valuedescr) - escape(i3) + escape_n(i3) p1 = new_with_vtable(ConstClass(node_vtable)) p1sub = new_with_vtable(ConstClass(node_vtable2)) setfield_gc(p1sub, i1, descr=valuedescr) @@ -621,7 +621,7 @@ [i1, p2, p3] p3sub = getfield_gc_r(p3, descr=nextdescr) i3 = getfield_gc_i(p3sub, descr=valuedescr) - escape(i3) + escape_n(i3) p1 = new_with_vtable(ConstClass(node_vtable)) p2sub = new_with_vtable(ConstClass(node_vtable2)) setfield_gc(p2sub, i1, descr=valuedescr) @@ -974,7 +974,7 @@ f2 = getinteriorfield_gc_f(p0, 0, descr=complexrealdescr) f3 = getinteriorfield_gc_f(p0, 0, descr=compleximagdescr) f4 = float_mul(f2, f3) - i0 = escape(f4, p0) + i0 = escape_i(f4, p0) finish(i0) """ expected = """ @@ -983,7 +983,7 @@ p0 = new_array_clear(1, descr=complexarraydescr) setinteriorfield_gc(p0, 0, f1, descr=compleximagdescr) setinteriorfield_gc(p0, 0, f0, descr=complexrealdescr) - i0 = escape(f2, p0) + i0 = escape_i(f2, p0) finish(i0) """ self.optimize_loop(ops, expected) @@ -1008,8 +1008,8 @@ setfield_gc(p1, i, descr=valuedescr) i0 = getfield_gc_i(p1, descr=valuedescr) i1 = int_add(i0, 1) - escape(p1) - escape(p1) + escape_n(p1) + escape_n(p1) jump(i1) """ expected = """ @@ -1017,8 +1017,8 @@ i1 = int_add(i, 1) p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p1, i, descr=valuedescr) - escape(p1) - escape(p1) + escape_n(p1) + escape_n(p1) jump(i1) """ self.optimize_loop(ops, expected) @@ -1027,7 +1027,7 @@ ops = """ [i, p0] i0 = getfield_gc_i(p0, descr=valuedescr) - escape(p0) + escape_n(p0) i1 = int_add(i0, i) p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p1, i1, descr=valuedescr) @@ -1042,7 +1042,7 @@ p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p1, i, descr=valuedescr) i1 = getfield_gc_i(p1, descr=valuedescr) - escape(p1) + escape_n(p1) i2 = getfield_gc_i(p1, descr=valuedescr) i3 = int_add(i1, i2) jump(i3) @@ -1051,7 +1051,7 @@ [i] p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p1, i, descr=valuedescr) - escape(p1) + escape_n(p1) i2 = getfield_gc_i(p1, descr=valuedescr) i3 = int_add(i, i2) jump(i3) @@ -1065,7 +1065,7 @@ setfield_gc(p1, i, descr=valuedescr) i1 = getfield_gc_i(p1, descr=valuedescr) setfield_gc(p1, 0, descr=valuedescr) - escape(p1) + escape_n(p1) i2 = getfield_gc_i(p1, descr=valuedescr) jump(i2) """ @@ -1073,7 +1073,7 @@ [i] p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p1, 0, descr=valuedescr) - escape(p1) + escape_n(p1) i2 = getfield_gc_i(p1, descr=valuedescr) jump(i2) """ @@ -1185,7 +1185,7 @@ p1 = new_array(5, descr=arraydescr) setarrayitem_gc(p1, 0, i1, descr=arraydescr) setarrayitem_gc(p1, 1, 0, descr=arraydescr) - escape(p1) + escape_n(p1) jump(i1) """ expected = """ @@ -1193,7 +1193,7 @@ p1 = new_array(5, descr=arraydescr) setarrayitem_gc(p1, 0, i1, descr=arraydescr) setarrayitem_gc(p1, 1, 0, descr=arraydescr) - escape(p1) + escape_n(p1) jump(i1) """ self.optimize_loop(ops, expected) @@ -1223,7 +1223,7 @@ ops = """ [i1, p2, p3] i3 = getarrayitem_gc_i(p3, 0, descr=arraydescr) - escape(i3) + escape_n(i3) p1 = new_array(1, descr=arraydescr) setarrayitem_gc(p1, 0, i1, descr=arraydescr) jump(i1, p1, p2) @@ -1238,17 +1238,17 @@ setfield_gc(p2, 3, descr=valuedescr) i1 = getfield_gc_i(p2, descr=valuedescr) # i1 = const 3 p1 = new_array(i1, descr=arraydescr) - escape(p1) + escape_n(p1) i2 = arraylen_gc(p1) - escape(i2) + escape_n(i2) jump() """ expected = """ [] p1 = new_array(3, descr=arraydescr) - escape(p1) + escape_n(p1) i2 = arraylen_gc(p1) - escape(i2) + escape_n(i2) jump() """ self.optimize_loop(ops, expected) @@ -1257,14 +1257,14 @@ ops = """ [i1, p2] i2 = getfield_gc(p2, descr=adescr) - escape(i2) + escape_n(i2) p3 = new(descr=ssize) setfield_gc(p3, i1, descr=adescr) jump(i1, p3) """ expected = """ [i1, i2] - escape(i2) + escape_n(i2) jump(i1, i1) """ py.test.skip("XXX") @@ -1274,7 +1274,7 @@ ops = """ [i1, p2, p3] i3 = getfield_gc_i(p3, descr=adescr) - escape(i3) + escape_n(i3) p1 = new(descr=ssize) setfield_gc(p1, i1, descr=adescr) jump(i1, p1, p2) @@ -1289,20 +1289,20 @@ i2 = getfield_gc_i(p2, descr=valuedescr) i3 = getfield_gc_i(p1, descr=valuedescr) i4 = getfield_gc_i(p2, descr=valuedescr) - escape(i1) - escape(i2) - escape(i3) - escape(i4) + escape_n(i1) + escape_n(i2) + escape_n(i3) + escape_n(i4) jump(p1, p2) """ expected = """ [p1, p2] i1 = getfield_gc_i(p1, descr=valuedescr) i2 = getfield_gc_i(p2, descr=valuedescr) - escape(i1) - escape(i2) - escape(i1) - escape(i2) + escape_n(i1) + escape_n(i2) + escape_n(i1) + escape_n(i2) jump(p1, p2) """ self.optimize_loop(ops, expected) @@ -1312,13 +1312,13 @@ [p1, i1] setfield_gc(p1, i1, descr=valuedescr) i2 = getfield_gc_i(p1, descr=valuedescr) - escape(i2) + escape_n(i2) jump(p1, i1) """ expected = """ [p1, i1] setfield_gc(p1, i1, descr=valuedescr) - escape(i1) + escape_n(i1) jump(p1, i1) """ self.optimize_loop(ops, expected) @@ -1329,14 +1329,14 @@ setfield_gc(p1, i1, descr=valuedescr) setfield_gc(p2, p1, descr=nextdescr) i2 = getfield_gc_i(p1, descr=valuedescr) - escape(i2) + escape_n(i2) jump(p1, p2, i1) """ expected = """ [p1, p2, i1] setfield_gc(p1, i1, descr=valuedescr) setfield_gc(p2, p1, descr=nextdescr) - escape(i1) + escape_n(i1) jump(p1, p2, i1) """ self.optimize_loop(ops, expected) @@ -1347,7 +1347,7 @@ setfield_gc(p1, i1, descr=valuedescr) setfield_gc(p2, i2, descr=valuedescr) i3 = getfield_gc_i(p1, descr=valuedescr) - escape(i3) + escape_n(i3) jump(p1, p2, i1, i3) """ self.optimize_loop(ops, ops) @@ -1358,16 +1358,16 @@ i1 = getfield_gc_i(p1, descr=valuedescr) debug_merge_point(15, 0) i2 = getfield_gc_i(p1, descr=valuedescr) - escape(i1) - escape(i2) + escape_n(i1) + escape_n(i2) jump(p1) """ expected = """ [p1] i1 = getfield_gc_i(p1, descr=valuedescr) debug_merge_point(15, 0) - escape(i1) - escape(i1) + escape_n(i1) + escape_n(i1) jump(p1) """ self.optimize_loop(ops, expected) @@ -1379,8 +1379,8 @@ i2 = int_add_ovf(i1, 14) guard_no_overflow() [] i3 = getfield_gc_i(p1, descr=valuedescr) - escape(i2) - escape(i3) + escape_n(i2) + escape_n(i3) jump(p1) """ expected = """ @@ -1388,8 +1388,8 @@ i1 = getfield_gc_i(p1, descr=valuedescr) i2 = int_add_ovf(i1, 14) guard_no_overflow() [] - escape(i2) - escape(i1) + escape_n(i2) + escape_n(i1) jump(p1) """ self.optimize_loop(ops, expected) @@ -1400,16 +1400,16 @@ i1 = getfield_gc_i(p1, descr=valuedescr) setarrayitem_gc(p2, 0, p1, descr=arraydescr2) i3 = getfield_gc_i(p1, descr=valuedescr) - escape(i1) - escape(i3) + escape_n(i1) + escape_n(i3) jump(p1, p2) """ expected = """ [p1, p2] i1 = getfield_gc_i(p1, descr=valuedescr) setarrayitem_gc(p2, 0, p1, descr=arraydescr2) - escape(i1) - escape(i1) + escape_n(i1) + escape_n(i1) jump(p1, p2) """ self.optimize_loop(ops, expected) @@ -1419,15 +1419,15 @@ [] i1 = getfield_gc_i(ConstPtr(myptr), descr=valuedescr) i2 = getfield_gc_i(ConstPtr(myptr), descr=valuedescr) - escape(i1) - escape(i2) + escape_n(i1) + escape_n(i2) jump() """ expected = """ [] i1 = getfield_gc_i(ConstPtr(myptr), descr=valuedescr) - escape(i1) - escape(i1) + escape_n(i1) + escape_n(i1) jump() """ self.optimize_loop(ops, expected) @@ -1438,15 +1438,15 @@ guard_value(p1, ConstPtr(myptr)) [] i1 = getfield_gc_i(p1, descr=valuedescr) i2 = getfield_gc_i(ConstPtr(myptr), descr=valuedescr) - escape(i1) - escape(i2) + escape_n(i1) + escape_n(i2) jump(p1) """ expected = """ [] i1 = getfield_gc_i(ConstPtr(myptr), descr=valuedescr) - escape(i1) - escape(i1) + escape_n(i1) + escape_n(i1) jump() """ py.test.skip("XXX") @@ -1456,10 +1456,10 @@ ops = """ [p1] i1 = getfield_gc_i(p1, descr=valuedescr) - escape() + escape_n() i2 = getfield_gc_i(p1, descr=valuedescr) - escape(i1) - escape(i2) + escape_n(i1) + escape_n(i2) jump(p1) """ self.optimize_loop(ops, ops) @@ -1468,9 +1468,9 @@ ops = """ [p1, i1] setfield_gc(p1, i1, descr=valuedescr) - escape() + escape_n() i2 = getfield_gc_i(p1, descr=valuedescr) - escape(i2) + escape_n(i2) jump(p1, i1) """ self.optimize_loop(ops, ops) @@ -1495,13 +1495,13 @@ setfield_gc(p1, i1, descr=valuedescr) i2 = getfield_gc_i(p1, descr=valuedescr) setfield_gc(p1, i3, descr=valuedescr) - escape(i2) + escape_n(i2) jump(p1, i1, i3) """ expected = """ [p1, i1, i3] setfield_gc(p1, i3, descr=valuedescr) - escape(i1) + escape_n(i1) jump(p1, i1, i3) """ self.optimize_loop(ops, expected) @@ -1512,7 +1512,7 @@ setfield_gc(p1, i1, descr=valuedescr) i2 = getfield_gc_i(p2, descr=valuedescr) setfield_gc(p1, i3, descr=valuedescr) - escape(i2) + escape_n(i2) jump(p1, p2, i1, i3) """ # potential aliasing of p1 and p2 means that we cannot kill the @@ -1558,14 +1558,14 @@ p2 = getfield_gc_r(p0, descr=nextdescr) i2 = getfield_gc_i(p2, descr=valuedescr) setfield_gc(p0, NULL, descr=nextdescr) - escape(i2) + escape_n(i2) jump(p0, i1) """ expected = """ [p0, i1] setfield_raw(i1, i1, descr=valuedescr) setfield_gc(p0, NULL, descr=nextdescr) - escape(i1) + escape_n(i1) jump(p0, i1) """ self.optimize_loop(ops, expected) @@ -1574,7 +1574,7 @@ ops = """ [p1, i1, i2] setfield_gc(p1, i1, descr=valuedescr) - escape() + escape_n() setfield_gc(p1, i2, descr=valuedescr) jump(p1, i1, i2) """ @@ -1691,20 +1691,20 @@ p3 = getarrayitem_gc_r(p1, 1, descr=arraydescr2) p4 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) p5 = getarrayitem_gc_r(p1, 1, descr=arraydescr2) - escape(p2) - escape(p3) - escape(p4) - escape(p5) + escape_n(p2) + escape_n(p3) + escape_n(p4) + escape_n(p5) jump(p1) """ expected = """ [p1] p2 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) p3 = getarrayitem_gc_r(p1, 1, descr=arraydescr2) - escape(p2) - escape(p3) - escape(p2) - escape(p3) + escape_n(p2) + escape_n(p3) + escape_n(p2) + escape_n(p3) jump(p1) """ self.optimize_loop(ops, expected) @@ -1714,13 +1714,13 @@ [p1, p2] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) p3 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) - escape(p3) + escape_n(p3) jump(p1, p3) """ expected = """ [p1, p2] setarrayitem_gc(p1, 0, p2, descr=arraydescr2) - escape(p2) + escape_n(p2) jump(p1, p2) """ self.optimize_loop(ops, expected) @@ -1733,8 +1733,8 @@ setarrayitem_gc(p1, i1, p3, descr=arraydescr2) p4 = getarrayitem_gc(p1, 0, descr=arraydescr2) p5 = getarrayitem_gc(p1, i1, descr=arraydescr2) - escape(p4) - escape(p5) + escape_n(p4) + escape_n(p5) jump(p1, p2, p3, i1) """ expected = """ @@ -1742,8 +1742,8 @@ setarrayitem_gc(p1, 0, p2, descr=arraydescr2) setarrayitem_gc(p1, i1, p3, descr=arraydescr2) p4 = getarrayitem_gc(p1, 0, descr=arraydescr2) - escape(p4) - escape(p3) + escape_n(p4) + escape_n(p3) jump(p1, p2, p3, i1) """ self.optimize_loop(ops, expected) @@ -1757,9 +1757,9 @@ p5 = getarrayitem_gc_r(p1, i1, descr=arraydescr2) p6 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) p7 = getarrayitem_gc_r(p1, 1, descr=arraydescr2) - escape(p5) - escape(p6) - escape(p7) + escape_n(p5) + escape_n(p6) + escape_n(p7) jump(p1, p2, p3, p4, i1) """ expected = """ @@ -1768,9 +1768,9 @@ setarrayitem_gc(p1, 0, p3, descr=arraydescr2) setarrayitem_gc(p1, 1, p4, descr=arraydescr2) p5 = getarrayitem_gc_r(p1, i1, descr=arraydescr2) - escape(p5) - escape(p3) - escape(p4) + escape_n(p5) + escape_n(p3) + escape_n(p4) jump(p1, p2, p3, p4, i1) """ self.optimize_loop(ops, expected) @@ -1781,17 +1781,17 @@ p3 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) i4 = getfield_gc_pure_i(ConstPtr(myptr), descr=valuedescr) p5 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) - escape(p3) - escape(i4) - escape(p5) + escape_n(p3) + escape_n(i4) + escape_n(p5) jump(p1, p2) """ expected = """ [p1, p2] p3 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) - escape(p3) - escape(5) - escape(p3) + escape_n(p3) + escape_n(5) + escape_n(p3) jump(p1, p2) """ self.optimize_loop(ops, expected) @@ -1803,16 +1803,16 @@ setarrayitem_gc(p2, 1, p4, descr=arraydescr2) p5 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) p6 = getarrayitem_gc_r(p2, 1, descr=arraydescr2) - escape(p5) - escape(p6) + escape_n(p5) + escape_n(p6) jump(p1, p2, p3, p4, i1) """ expected = """ [p1, p2, p3, p4, i1] setarrayitem_gc(p1, 0, p3, descr=arraydescr2) setarrayitem_gc(p2, 1, p4, descr=arraydescr2) - escape(p3) - escape(p4) + escape_n(p3) + escape_n(p4) jump(p1, p2, p3, p4, i1) """ self.optimize_loop(ops, expected) @@ -1864,19 +1864,19 @@ [i0, p1] p4 = getfield_gc_r(p1, descr=nextdescr) guard_nonnull(p4) [] - escape(p4) + escape_n(p4) # p2 = new_with_vtable(ConstClass(node_vtable)) - p3 = escape() + p3 = escape_r() setfield_gc(p2, p3, descr=nextdescr) jump(i0, p2) """ expected = """ [i0, p4] guard_nonnull(p4) [] - escape(p4) + escape_n(p4) # - p3 = escape() + p3 = escape_r() jump(i0, p3) """ py.test.skip("XXX") @@ -1888,19 +1888,19 @@ [i0, p1] p4 = getarrayitem_gc(p1, 0, descr=arraydescr2) guard_nonnull(p4) [] - escape(p4) + escape_n(p4) # p2 = new_array(1, descr=arraydescr2) - p3 = escape() + p3 = escape_r() setarrayitem_gc(p2, 0, p3, descr=arraydescr2) jump(i0, p2) """ expected = """ [i0, p4] guard_nonnull(p4) [] - escape(p4) + escape_n(p4) # - p3 = escape() + p3 = escape_r() jump(i0, p3) """ py.test.skip("XXX") @@ -1922,7 +1922,7 @@ p1a = new_with_vtable(ConstClass(node_vtable2)) p2a = new_with_vtable(ConstClass(node_vtable)) p3a = new_with_vtable(ConstClass(node_vtable)) - escape(p3a) + escape_n(p3a) setfield_gc(p1a, p2a, descr=nextdescr) setfield_gc(p1a, p3a, descr=otherdescr) jump(p1a) @@ -1933,7 +1933,7 @@ guard_class(p3, ConstClass(node_vtable)) [] setfield_gc(p3, p2, descr=otherdescr) p3a = new_with_vtable(ConstClass(node_vtable)) - escape(p3a) + escape_n(p3a) p2a = new_with_vtable(ConstClass(node_vtable)) jump(p2a, p3a) """ @@ -1955,7 +1955,7 @@ p2a = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p3, p2a, descr=otherdescr) p3a = new_with_vtable(ConstClass(node_vtable)) - escape(p3a) + escape_n(p3a) setfield_gc(p1a, p2a, descr=nextdescr) setfield_gc(p1a, p3a, descr=otherdescr) jump(p1a) @@ -1967,7 +1967,7 @@ p2a = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p3, p2a, descr=otherdescr) p3a = new_with_vtable(ConstClass(node_vtable)) - escape(p3a) + escape_n(p3a) jump(p2a, p3a) """ py.test.skip("XXX") @@ -1992,7 +1992,7 @@ guard_class(p1, ConstClass(node_vtable2)) [] # p2 = new_with_vtable(ConstClass(node_vtable)) - escape(p2) # prevent it from staying Virtual + escape_n(p2) # prevent it from staying Virtual jump(p2) """ py.test.raises(InvalidLoop, self.optimize_loop, @@ -2128,8 +2128,8 @@ i4 = int_add(i2, 1) i4b = int_is_true(i4) guard_true(i4b) [] - escape(i3) - escape(i4) + escape_n(i3) + escape_n(i4) guard_true(i1) [] guard_true(i2) [] jump(p1, p2) @@ -2140,8 +2140,8 @@ i3 = int_add(i1, 1) i3b = int_is_true(i3) guard_true(i3b) [] - escape(i3) - escape(i3) + escape_n(i3) + escape_n(i3) guard_true(i1) [] jump(p1, p2) """ @@ -2178,8 +2178,8 @@ guard_no_overflow() [] i4b = int_is_true(i4) guard_true(i4b) [] - escape(i3) - escape(i4) + escape_n(i3) + escape_n(i4) jump(i1) """ expected = """ @@ -2188,8 +2188,8 @@ guard_no_overflow() [] i3b = int_is_true(i3) guard_true(i3b) [] - escape(i3) - escape(i3) + escape_n(i3) + escape_n(i3) jump(i1) """ self.optimize_loop(ops, expected) @@ -2295,12 +2295,12 @@ ops = """ [f0] f1 = float_mul(f0, 1.0) - f2 = escape(f1) + f2 = escape_f(f1) jump(f2) """ expected = """ [f0] - f2 = escape(f0) + f2 = escape_f(f0) jump(f2) """ self.optimize_loop(ops, expected) @@ -2308,12 +2308,12 @@ ops = """ [f0] f1 = float_mul(1.0, f0) - f2 = escape(f1) + f2 = escape_f(f1) jump(f2) """ expected = """ [f0] - f2 = escape(f0) + f2 = escape_f(f0) jump(f2) """ self.optimize_loop(ops, expected) @@ -2322,13 +2322,13 @@ ops = """ [f0] f1 = float_mul(f0, -1.0) - f2 = escape(f1) + f2 = escape_f(f1) jump(f2) """ expected = """ [f0] f1 = float_neg(f0) - f2 = escape(f1) + f2 = escape_f(f1) jump(f2) """ self.optimize_loop(ops, expected) @@ -2336,13 +2336,13 @@ ops = """ [f0] f1 = float_mul(-1.0, f0) - f2 = escape(f1) + f2 = escape_f(f1) jump(f2) """ expected = """ [f0] f1 = float_neg(f0) - f2 = escape(f1) + f2 = escape_f(f1) jump(f2) """ self.optimize_loop(ops, expected) @@ -2354,14 +2354,14 @@ f2 = float_neg(f1) f3 = float_neg(f2) f4 = float_neg(f3) - escape(f4) + escape_n(f4) jump(f4) """ expected = """ [f0] # The backend removes this dead op. f1 = float_neg(f0) - escape(f0) + escape_n(f0) jump(f0) """ self.optimize_loop(ops, expected) @@ -2373,7 +2373,7 @@ f2 = float_truediv(f1, 3.0) f3 = float_truediv(f2, -0.25) f4 = float_truediv(f3, 0.0) - f5 = escape(f4) + f5 = escape_f(f4) jump(f5) """ @@ -2383,7 +2383,7 @@ f2 = float_truediv(f1, 3.0) f3 = float_mul(f2, -4.0) f4 = float_truediv(f3, 0.0) - f5 = escape(f4) + f5 = escape_f(f4) jump(f5) """ self.optimize_loop(ops, expected) @@ -2770,16 +2770,16 @@ i1 = getfield_gc_i(p1, descr=valuedescr) i2 = call_i(i1, descr=nonwritedescr) i3 = getfield_gc_i(p1, descr=valuedescr) - escape(i1) - escape(i3) + escape_n(i1) + escape_n(i3) jump(p1, p2) """ expected = """ [p1, p2] i1 = getfield_gc_i(p1, descr=valuedescr) i2 = call_i(i1, descr=nonwritedescr) - escape(i1) - escape(i1) + escape_n(i1) + escape_n(i1) jump(p1, p2) """ self.optimize_loop(ops, expected) @@ -2792,10 +2792,10 @@ i3 = call_i(i1, descr=writeadescr) i4 = getfield_gc_i(p1, descr=adescr) i5 = getfield_gc_i(p1, descr=bdescr) - escape(i1) - escape(i2) - escape(i4) - escape(i5) + escape_n(i1) + escape_n(i2) + escape_n(i4) + escape_n(i5) jump(p1, p2) """ expected = """ @@ -2804,10 +2804,10 @@ i2 = getfield_gc_i(p1, descr=bdescr) i3 = call_i(i1, descr=writeadescr) i4 = getfield_gc_i(p1, descr=adescr) - escape(i1) - escape(i2) - escape(i4) - escape(i2) + escape_n(i1) + escape_n(i2) + escape_n(i4) + escape_n(i2) jump(p1, p2) """ self.optimize_loop(ops, expected) @@ -2820,10 +2820,10 @@ i3 = call_i(i1, descr=writeadescr) p5 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) p6 = getarrayitem_gc_r(p2, 1, descr=arraydescr2) - escape(p3) - escape(p4) - escape(p5) - escape(p6) + escape_n(p3) + escape_n(p4) + escape_n(p5) + escape_n(p6) jump(p1, p2, i1) """ expected = """ @@ -2831,10 +2831,10 @@ p3 = getarrayitem_gc_r(p1, 0, descr=arraydescr2) p4 = getarrayitem_gc_r(p2, 1, descr=arraydescr2) i3 = call_i(i1, descr=writeadescr) - escape(p3) - escape(p4) - escape(p3) - escape(p4) + escape_n(p3) + escape_n(p4) + escape_n(p3) + escape_n(p4) jump(p1, p2, i1) """ self.optimize_loop(ops, expected) @@ -2849,12 +2849,12 @@ p5 = getarrayitem_gc_r(p2, 0, descr=arraydescr2) p6 = getarrayitem_gc_r(p2, 1, descr=arraydescr2) i4 = getarrayitem_gc_i(p1, 1, descr=arraydescr) - escape(p3) - escape(p4) - escape(p5) - escape(p6) - escape(i2) - escape(i4) + escape_n(p3) + escape_n(p4) + escape_n(p5) + escape_n(p6) + escape_n(i2) + escape_n(i4) jump(p1, p2, i1) """ expected = """ @@ -2864,12 +2864,12 @@ i2 = getarrayitem_gc_i(p1, 1, descr=arraydescr) i3 = call_i(i1, descr=writearraydescr) i4 = getarrayitem_gc_i(p1, 1, descr=arraydescr) - escape(p3) - escape(p4) - escape(p3) - escape(p4) - escape(i2) - escape(i4) + escape_n(p3) + escape_n(p4) + escape_n(p3) + escape_n(p4) + escape_n(i2) + escape_n(i4) jump(p1, p2, i1) """ self.optimize_loop(ops, expected) @@ -2964,16 +2964,16 @@ call_pure_results = {tuple(arg_consts): ConstInt(42)} ops = ''' [i0, i1, i2] - escape(i1) - escape(i2) + escape_n(i1) + escape_n(i2) i3 = call_pure_i(123456, 4, 5, 6, descr=plaincalldescr) i4 = call_pure_i(123456, 4, i0, 6, descr=plaincalldescr) jump(i0, i3, i4) ''' expected = ''' [i0, i1, i2] - escape(i1) - escape(i2) + escape_n(i1) + escape_n(i2) i4 = call_i(123456, 4, i0, 6, descr=plaincalldescr) jump(i0, 42, i4) ''' @@ -2997,7 +2997,7 @@ ops = """ [p1] p2 = virtual_ref(p1, 5) - escape(p2) + escape_n(p2) virtual_ref_finish(p2, p1) jump(p1) """ @@ -3007,7 +3007,7 @@ p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable)) setfield_gc(p2, NULL, descr=virtualforceddescr) setfield_gc(p2, p0, descr=virtualtokendescr) - escape(p2) + escape_n(p2) setfield_gc(p2, p1, descr=virtualforceddescr) setfield_gc(p2, NULL, descr=virtualtokendescr) jump(p1) @@ -3146,7 +3146,7 @@ [i1] p1 = new_with_vtable(ConstClass(node_vtable)) p2 = virtual_ref(p1, 7) - escape(p2) + escape_n(p2) virtual_ref_finish(p2, p1) call_may_force_n(i1, descr=mayforcevirtdescr) guard_not_forced() [] @@ -3158,7 +3158,7 @@ p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable)) setfield_gc(p2, NULL, descr=virtualforceddescr) setfield_gc(p2, p3, descr=virtualtokendescr) - escape(p2) + escape_n(p2) p1 = new_with_vtable(ConstClass(node_vtable)) setfield_gc(p2, p1, descr=virtualforceddescr) setfield_gc(p2, NULL, descr=virtualtokendescr) @@ -3172,7 +3172,7 @@ ops = """ [i1, p1] p2 = virtual_ref(p1, 23) - escape(p2) + escape_n(p2) virtual_ref_finish(p2, p1) call_may_force_n(i1, descr=mayforcevirtdescr) guard_not_forced() [i1] @@ -3184,7 +3184,7 @@ p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable)) setfield_gc(p2, NULL, descr=virtualforceddescr) setfield_gc(p2, p3, descr=virtualtokendescr) - escape(p2) + escape_n(p2) setfield_gc(p2, p1, descr=virtualforceddescr) setfield_gc(p2, NULL, descr=virtualtokendescr) call_may_force_n(i1, descr=mayforcevirtdescr) @@ -4235,12 +4235,12 @@ p1 = same_as_r(s"ab") p2 = same_as_r(s"cde") p3 = call_r(0, p1, p2, descr=strconcatdescr) - escape(p3) + escape_n(p3) jump() """ expected = """ [] - escape(s"abcde") + escape_n(s"abcde") jump() """ self.optimize_strunicode_loop(ops, expected) @@ -4329,7 +4329,7 @@ [p1, i1, i2, i3] p2 = call_r(0, p1, i1, i2, descr=strslicedescr) i4 = strgetitem(p2, i3) - escape(i4) + escape_n(i4) jump(p1, i1, i2, i3) """ expected = """ @@ -4337,7 +4337,7 @@ i6 = int_sub(i2, i1) # killed by the backend i5 = int_add(i1, i3) i4 = strgetitem(p1, i5) - escape(i4) + escape_n(i4) jump(p1, i1, i2, i3) """ self.optimize_strunicode_loop(ops, expected) @@ -4350,12 +4350,12 @@ strsetitem(p1, 1, i4) p2 = call_r(0, p1, 1, 2, descr=strslicedescr) i5 = strgetitem(p2, 0) - escape(i5) + escape_n(i5) jump(i3, i4) """ expected = """ [i3, i4] - escape(i4) + escape_n(i4) jump(i3, i4) """ self.optimize_strunicode_loop(ops, expected) @@ -4416,7 +4416,7 @@ ops = """ [p1, p2] i0 = call_i(0, p1, p2, descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1, p2) """ self.optimize_strunicode_loop_extradescrs(ops, ops) @@ -4426,7 +4426,7 @@ [p1, p2, p3] p4 = call_r(0, p1, p2, descr=strconcatdescr) i0 = call_i(0, p3, p4, descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1, p2, p3) """ expected = """ @@ -4438,7 +4438,7 @@ copystrcontent(p1, p4, 0, 0, i1) copystrcontent(p2, p4, 0, i1, i2) i0 = call_i(0, p3, p4, descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1, p2, p3) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4448,14 +4448,14 @@ [p1, i1, i2, p3] p4 = call_r(0, p1, i1, i2, descr=strslicedescr) i0 = call_i(0, p4, p3, descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1, i1, i2, p3) """ expected = """ [p1, i1, i2, p3] i3 = int_sub(i2, i1) i0 = call_i(0, p1, i1, i3, p3, descr=streq_slice_checknull_descr) - escape(i0) + escape_n(i0) jump(p1, i1, i2, p3) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4465,14 +4465,14 @@ [p1, i1, i2, p3] p4 = call_r(0, p1, i1, i2, descr=strslicedescr) i0 = call_i(0, p3, p4, descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1, i1, i2, p3) """ expected = """ [p1, i1, i2, p3] i4 = int_sub(i2, i1) i0 = call_i(0, p1, i1, i4, p3, descr=streq_slice_checknull_descr) - escape(i0) + escape_n(i0) jump(p1, i1, i2, p3) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4483,7 +4483,7 @@ guard_nonnull(p3) [] p4 = call_r(0, p1, i1, i2, descr=strslicedescr) i0 = call_i(0, p3, p4, descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1, i1, i2, p3) """ expected = """ @@ -4491,7 +4491,7 @@ guard_nonnull(p3) [] i4 = int_sub(i2, i1) i0 = call_i(0, p1, i1, i4, p3, descr=streq_slice_nonnull_descr) - escape(i0) + escape_n(i0) jump(p1, i1, i2, p3) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4501,14 +4501,14 @@ [p1, i1, i2] p3 = call_r(0, p1, i1, i2, descr=strslicedescr) i0 = call_i(0, p3, s"x", descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1, i1, i2) """ expected = """ [p1, i1, i2] i3 = int_sub(i2, i1) i0 = call_i(0, p1, i1, i3, 120, descr=streq_slice_char_descr) - escape(i0) + escape_n(i0) jump(p1, i1, i2) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4520,14 +4520,14 @@ p5 = newstr(1) strsetitem(p5, 0, i3) i0 = call_i(0, p5, p4, descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1, i1, i2, i3) """ expected = """ [p1, i1, i2, i3] i4 = int_sub(i2, i1) i0 = call_i(0, p1, i1, i4, i3, descr=streq_slice_char_descr) - escape(i0) + escape_n(i0) jump(p1, i1, i2, i3) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4536,13 +4536,13 @@ ops = """ [p1] i0 = call_i(0, p1, NULL, descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1) """ expected = """ [p1] i0 = ptr_eq(p1, NULL) - escape(i0) + escape_n(i0) jump(p1) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4551,13 +4551,13 @@ ops = """ [p1] i0 = call_i(0, NULL, p1, descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1) """ expected = """ [p1] i0 = ptr_eq(p1, NULL) - escape(i0) + escape_n(i0) jump(p1) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4567,14 +4567,14 @@ [p1] guard_nonnull(p1) [] i0 = call_i(0, p1, s"hello world", descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1) """ expected = """ [p1] guard_nonnull(p1) [] i0 = call_i(0, p1, s"hello world", descr=streq_nonnull_descr) - escape(i0) + escape_n(i0) jump(p1) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4584,7 +4584,7 @@ [p1] guard_nonnull(p1) [] i0 = call_i(0, p1, s"", descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1) """ expected = """ @@ -4592,7 +4592,7 @@ guard_nonnull(p1) [] i1 = strlen(p1) i0 = int_eq(i1, 0) - escape(i0) + escape_n(i0) jump(p1) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4602,14 +4602,14 @@ [p1] guard_nonnull(p1) [] i0 = call_i(0, p1, s"x", descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1) """ expected = """ [p1] guard_nonnull(p1) [] i0 = call_i(0, p1, 120, descr=streq_nonnull_char_descr) - escape(i0) + escape_n(i0) jump(p1) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4619,7 +4619,7 @@ [p1, p2] p4 = call_r(0, p1, p2, descr=strconcatdescr) i0 = call_i(0, s"hello world", p4, descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1, p2) """ expected = """ @@ -4631,7 +4631,7 @@ copystrcontent(p1, p4, 0, 0, i1) copystrcontent(p2, p4, 0, i1, i2) i0 = call_i(0, s"hello world", p4, descr=streq_nonnull_descr) - escape(i0) + escape_n(i0) jump(p1, p2) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4641,12 +4641,12 @@ [i1] p1 = newstr(0) i0 = call_i(0, p1, s"", descr=strequaldescr) - escape(i0) + escape_n(i0) jump(i1) """ expected = """ [i1] - escape(1) + escape_n(1) jump(i1) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4657,13 +4657,13 @@ p1 = newstr(1) strsetitem(p1, 0, i1) i0 = call_i(0, p1, s"x", descr=strequaldescr) - escape(i0) + escape_n(i0) jump(i1) """ expected = """ [i1] i0 = int_eq(i1, 120) # ord('x') - escape(i0) + escape_n(i0) jump(i1) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4675,7 +4675,7 @@ strsetitem(p1, 0, i1) strsetitem(p1, 1, i2) i0 = call_i(0, p1, s"xy", descr=strequaldescr) - escape(i0) + escape_n(i0) jump(i1, i2) """ expected = """ @@ -4684,7 +4684,7 @@ strsetitem(p1, 0, i1) strsetitem(p1, 1, i2) i0 = call_i(0, p1, s"xy", descr=streq_lengthok_descr) - escape(i0) + escape_n(i0) jump(i1, i2) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4693,13 +4693,13 @@ ops = """ [p1] i0 = call_i(0, s"x", p1, descr=strequaldescr) - escape(i0) + escape_n(i0) jump(p1) """ expected = """ [p1] i0 = call_i(0, p1, 120, descr=streq_checknull_char_descr) - escape(i0) + escape_n(i0) jump(p1) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4710,12 +4710,12 @@ p1 = newstr(1) strsetitem(p1, 0, i1) i0 = call_i(0, s"xy", p1, descr=strequaldescr) - escape(i0) + escape_n(i0) jump(i1) """ expected = """ [i1] - escape(0) + escape_n(0) jump(i1) """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4724,12 +4724,12 @@ ops = """ [] p0 = call_r(0, "xy", descr=s2u_descr) # string -> unicode - escape(p0) + escape_n(p0) jump() """ expected = """ [] - escape(u"xy") + escape_n(u"xy") jump() """ self.optimize_strunicode_loop_extradescrs(ops, expected) @@ -4738,7 +4738,7 @@ ops = """ [p0] p1 = call_r(0, p0, descr=s2u_descr) # string -> unicode - escape(p1) + escape_n(p1) jump(p1) """ self.optimize_strunicode_loop_extradescrs(ops, ops) @@ -4753,13 +4753,13 @@ i2 = strgetitem(p0, i0) i3 = int_eq(i1, i2) guard_true(i3) [] - escape(i2) + escape_n(i2) jump(p0, i0) """ expected = """ [p0, i0] i1 = strgetitem(p0, i0) - escape(i1) + escape_n(i1) jump(p0, i0) """ self.optimize_strunicode_loop(ops, expected) @@ -4788,7 +4788,7 @@ [p0, i0] i1 = int_add(i0, 1) p1 = call_r(0, p0, i0, i1, descr=strslicedescr) - escape(p1) + escape_n(p1) jump(p0, i1) """ expected = """ @@ -4797,7 +4797,7 @@ p1 = newstr(1) i2 = strgetitem(p0, i0) strsetitem(p1, 0, i2) - escape(p1) + escape_n(p1) jump(p0, i1) """ self.optimize_strunicode_loop(ops, expected) @@ -4841,7 +4841,7 @@ ops = """ [i0] p0 = newstr(i0) - escape(p0) + escape_n(p0) i1 = strlen(p0) i2 = int_add(i1, 1) jump(i2) @@ -4849,7 +4849,7 @@ expected = """ [i0] p0 = newstr(i0) - escape(p0) + escape_n(p0) i1 = int_add(i0, 1) jump(i1) """ @@ -5009,8 +5009,8 @@ [i0, i1] p0 = new(descr=ssize) p1 = new(descr=ssize) - escape(p0) - escape(p1) + escape_n(p0) + escape_n(p1) setfield_gc(p0, i0, descr=adescr) setfield_gc(p1, i1, descr=adescr) i2 = getfield_gc_i(p0, descr=adescr) @@ -5019,9 +5019,9 @@ expected = """ [i0, i1] p0 = new(descr=ssize) - escape(p0) + escape_n(p0) p1 = new(descr=ssize) - escape(p1) + escape_n(p1) setfield_gc(p0, i0, descr=adescr) setfield_gc(p1, i1, descr=adescr) jump(i0, i0) @@ -5192,14 +5192,14 @@ p1 = newstr(1) strsetitem(p1, 0, i0) p2 = newstr(1) - escape(p2) + escape_n(p2) copystrcontent(p1, p2, 0, 0, 1) finish() """ expected = """ [i0] p2 = newstr(1) - escape(p2) + escape_n(p2) strsetitem(p2, 0, i0) finish() """ diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py --- a/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizeopt.py @@ -1,14 +1,15 @@ import py from rpython.rlib.objectmodel import instantiate from rpython.jit.metainterp import compile, resume -from rpython.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt, TreeLoop +from rpython.jit.metainterp.history import AbstractDescr, ConstInt, TreeLoop from rpython.jit.metainterp.optimize import InvalidLoop from rpython.jit.metainterp.optimizeopt import build_opt_chain from rpython.jit.metainterp.optimizeopt.test.test_util import ( LLtypeMixin, BaseTest, convert_old_style_to_targets) from rpython.jit.metainterp.optimizeopt.test.test_optimizebasic import \ FakeMetaInterpStaticData -from rpython.jit.metainterp.resoperation import rop, opname, oparity +from rpython.jit.metainterp.resoperation import rop, opname, oparity,\ + InputArgInt def test_build_opt_chain(): @@ -134,10 +135,10 @@ def test_simple(self): ops = """ [] - f = escape() + f = escape_f() f0 = float_sub(f, 1.0) guard_value(f0, 0.0) [f0] - escape(f) + escape_n(f) jump() """ self.optimize_loop(ops, ops) @@ -178,9 +179,9 @@ self.optimize_loop(ops, expected) def test_constfold_all(self): - from rpython.jit.metainterp.executor import execute_nonspec + from rpython.jit.metainterp.executor import _execute_nonspec import random - for opnum in range(rop.INT_ADD, rop.SAME_AS+1): + for opnum in range(rop.INT_ADD, rop.SAME_AS_I+1): try: op = opname[opnum] except KeyError: @@ -193,15 +194,14 @@ ops = """ [] i1 = %s(%s) - escape(i1) + escape_n(i1) jump() """ % (op.lower(), ', '.join(map(str, args))) - argboxes = [BoxInt(a) for a in args] - expected_value = execute_nonspec(self.cpu, None, opnum, - argboxes).getint() + argboxes = [InputArgInt(a) for a in args] + expected_value = _execute_nonspec(self.cpu, None, opnum, argboxes) expected = """ [] - escape(%d) + escape_n(%d) jump() """ % expected_value self.optimize_loop(ops, expected) diff --git a/rpython/jit/metainterp/optimizeopt/test/test_util.py b/rpython/jit/metainterp/optimizeopt/test/test_util.py --- a/rpython/jit/metainterp/optimizeopt/test/test_util.py +++ b/rpython/jit/metainterp/optimizeopt/test/test_util.py @@ -18,7 +18,7 @@ from rpython.jit.metainterp.counter import DeterministicJitCounter from rpython.config.translationoption import get_combined_translation_config from rpython.jit.metainterp.resoperation import rop, ResOperation, InputArgRef -from rpython.jit.metainterp.optimizeopt.unroll import Inliner + def test_sort_descrs(): class PseudoDescr(AbstractDescr): @@ -343,9 +343,9 @@ op.setfailargs(boxes) def __eq__(self, other): return type(self) is type(other) # xxx obscure - def clone_if_mutable(self): + def clone_if_mutable(self, memo): res = Storage(self.metainterp_sd, self.original_greenkey) - self.copy_all_attributes_into(res) + self.copy_all_attributes_into(res, memo) return res def _sortboxes(boxes): @@ -367,7 +367,7 @@ def add_guard_future_condition(self, res): # invent a GUARD_FUTURE_CONDITION to not have to change all tests if res.operations[-1].getopnum() == rop.JUMP: - guard = ResOperation(rop.GUARD_FUTURE_CONDITION, [], None, descr=self.invent_fail_descr(None, -1, [])) + guard = ResOperation(rop.GUARD_FUTURE_CONDITION, [], descr=self.invent_fail_descr(None, -1, [])) res.operations.insert(-1, guard) def invent_fail_descr(self, model, opnum, fail_args): @@ -414,7 +414,10 @@ jump_args = jumpop.getarglist()[:] operations = operations[:-1] - cloned_operations = [op.clone() for op in operations] + memo = compile.Memo() + cloned_operations = [op.clone(memo) for op in operations] + for op in cloned_operations: + op.is_source_op = True preamble = TreeLoop('preamble') preamble.inputargs = inputargs @@ -427,11 +430,10 @@ assert preamble.operations[-1].getopnum() == rop.LABEL - inliner = Inliner(inputargs, jump_args) loop.operations = [preamble.operations[-1]] + \ - [inliner.inline_op(op, clone=False) for op in cloned_operations] + \ - [ResOperation(rop.JUMP, [inliner.inline_arg(a) for a in jump_args], - None, descr=token)] + cloned_operations + \ + [ResOperation(rop.JUMP, [memo.get(a, a) for a in jump_args], + descr=token)] #[inliner.inline_op(jumpop)] assert loop.operations[-1].getopnum() == rop.JUMP assert loop.operations[0].getopnum() == rop.LABEL diff --git a/rpython/jit/metainterp/optimizeopt/unroll.py b/rpython/jit/metainterp/optimizeopt/unroll.py --- a/rpython/jit/metainterp/optimizeopt/unroll.py +++ b/rpython/jit/metainterp/optimizeopt/unroll.py @@ -1,8 +1,7 @@ import sys -from rpython.jit.metainterp.compile import ResumeGuardDescr +from rpython.jit.metainterp.compile import Memo from rpython.jit.metainterp.history import TargetToken, JitCellToken, Const -from rpython.jit.metainterp.inliner import Inliner from rpython.jit.metainterp.optimize import InvalidLoop from rpython.jit.metainterp.optimizeopt.generalize import KillHugeIntBounds from rpython.jit.metainterp.optimizeopt.optimizer import Optimizer, Optimization @@ -115,7 +114,7 @@ if start_label and self.jump_to_start_label(start_label, stop_label): # Initial label matches, jump to it - jumpop = ResOperation(rop.JUMP, stop_label.getarglist(), None, + jumpop = ResOperation(rop.JUMP, stop_label.getarglist(), descr=start_label.getdescr()) if self.short: # Construct our short preamble @@ -318,9 +317,10 @@ 'end of this bridge does not do that.') args[short_inputargs[i]] = jmp_to_short_args[i] - self.short_inliner = Inliner(short_inputargs, jmp_to_short_args) - self._inline_short_preamble(self.short, self.short_inliner, - patchguardop, self.short_boxes.assumed_classes) + self.memo = Memo(short_inputargs, jmp_to_short_args) + self._inline_short_preamble(self.short, self.memo, + patchguardop, + self.short_boxes.assumed_classes) # Import boxes produced in the preamble but used in the loop newoperations = self.optimizer.get_newoperations() @@ -341,7 +341,7 @@ jumpop.initarglist(jumpargs) self.optimizer.send_extra_operation(jumpop) - self.short.append(ResOperation(rop.JUMP, short_jumpargs, None, descr=jumpop.getdescr())) + self.short.append(ResOperation(rop.JUMP, short_jumpargs, descr=jumpop.getdescr())) # Verify that the virtual state at the end of the loop is one # that is compatible with the virtual state at the start of the loop @@ -397,21 +397,20 @@ else: newargs[i] = a.clonebox() boxmap[a] = newargs[i] - inliner = Inliner(short_inputargs, newargs) + memo = Memo(short_inputargs, newargs) target_token.assumed_classes = {} for i in range(len(short)): op = short[i] - newop = inliner.inline_op(op) - if op.result and op.result in self.short_boxes.assumed_classes: - target_token.assumed_classes[newop.result] = self.short_boxes.assumed_classes[op.result] + newop = op.clone(memo) + if op.type != 'v' and op in self.short_boxes.assumed_classes: + target_token.assumed_classes[newop] = self.short_boxes.assumed_classes[op] short[i] = newop # Forget the values to allow them to be freed for box in short[0].getarglist(): box.forget_value() for op in short: - if op.result: - op.result.forget_value() + op.forget_value() target_token.short_preamble = self.short target_token.exported_state = None @@ -492,7 +491,7 @@ def _import_op(self, op, inputargs, short_jumpargs, jumpargs): - self.boxes_created_this_iteration[op.result] = None + self.boxes_created_this_iteration[op] = None args = op.getarglist() if op.is_guard(): args = args + op.getfailargs() @@ -551,7 +550,7 @@ args = target.virtual_state.make_inputargs(values, self.optimizer, keyboxes=True) short_inputargs = target.short_preamble[0].getarglist() - inliner = Inliner(short_inputargs, args) + memo = Memo(short_inputargs, args) for guard in extra_guards: if guard.is_guard(): @@ -561,7 +560,7 @@ try: # NB: the short_preamble ends with a jump - self._inline_short_preamble(target.short_preamble, inliner, patchguardop, target.assumed_classes) + self._inline_short_preamble(target.short_preamble, memo, patchguardop, target.assumed_classes) except InvalidLoop: #debug_print("Inlining failed unexpectedly", # "jumping to preamble instead") diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py --- a/rpython/jit/metainterp/resoperation.py +++ b/rpython/jit/metainterp/resoperation.py @@ -242,6 +242,9 @@ def returns_bool_result(self): return self._cls_has_bool_result + def forget_value(self): + pass + # =================== # Top of the hierachy @@ -358,6 +361,9 @@ getvalue = getref_base + def forget_value(self): + self._resref = lltype.nullptr(llmemory.GCREF.TO) + def setref_base(self, refval): self._resref = refval @@ -626,7 +632,7 @@ 'INT_INVERT/1/i', 'INT_FORCE_GE_ZERO/1/i', # - 'SAME_AS/1/rfi', # gets a Const or a Box, turns it into another Box + 'SAME_AS/1/ifr', # gets a Const or a Box, turns it into another Box 'CAST_PTR_TO_INT/1/i', 'CAST_INT_TO_PTR/1/r', # diff --git a/rpython/jit/tool/oparser.py b/rpython/jit/tool/oparser.py --- a/rpython/jit/tool/oparser.py +++ b/rpython/jit/tool/oparser.py @@ -14,9 +14,6 @@ class ESCAPE_OP(N_aryOp, ResOpWithDescr): - OPNUM = -123 - - type = 'i' is_source_op = True def getopnum(self): @@ -25,14 +22,38 @@ def getopname(self): return 'escape' - def clone(self): - op = ESCAPE_OP() - op.initarglist(self.getarglist()[:]) + def clone(self, memo): + op = self.__class__() + op.initarglist([memo.get(arg, arg) for arg in self.getarglist()]) + memo.set(self, op) return op +class ESCAPE_OP_I(ESCAPE_OP): + type = 'i' + OPNUM = -123 + +class ESCAPE_OP_F(ESCAPE_OP): + type = 'f' + OPNUM = -124 + +class ESCAPE_OP_N(ESCAPE_OP): + type = 'v' + OPNUM = -125 + +class ESCAPE_OP_R(ESCAPE_OP): + type = 'r' + OPNUM = -126 + +ALL_ESCAPE_OPS = { + ESCAPE_OP_I.OPNUM: ESCAPE_OP_I, + ESCAPE_OP_F.OPNUM: ESCAPE_OP_F, + ESCAPE_OP_N.OPNUM: ESCAPE_OP_N, + ESCAPE_OP_R.OPNUM: ESCAPE_OP_R +} + class FORCE_SPILL(UnaryOp, PlainResOp): - OPNUM = -124 + OPNUM = -127 is_source_op = True def getopnum(self): @@ -224,8 +245,14 @@ try: opnum = getattr(rop, opname.upper()) except AttributeError: - if opname == 'escape': - opnum = ESCAPE_OP.OPNUM + if opname == 'escape_i': + opnum = ESCAPE_OP_I.OPNUM + elif opname == 'escape_f': + opnum = ESCAPE_OP_F.OPNUM + elif opname == 'escape_n': + opnum = ESCAPE_OP_N.OPNUM + elif opname == 'escape_r': + opnum = ESCAPE_OP_R.OPNUM elif opname == 'force_spill': opnum = FORCE_SPILL.OPNUM else: @@ -268,8 +295,8 @@ return opnum, args, descr, fail_args def create_op(self, opnum, args, descr): - if opnum == ESCAPE_OP.OPNUM: - op = ESCAPE_OP() + if opnum in ALL_ESCAPE_OPS: + op = ALL_ESCAPE_OPS[opnum]() op.initarglist(args) assert descr is None return op From noreply at buildbot.pypy.org Wed Dec 3 20:30:18 2014 From: noreply at buildbot.pypy.org (rguillebert) Date: Wed, 3 Dec 2014 20:30:18 +0100 (CET) Subject: [pypy-commit] extradoc extradoc: First WIP for the Scipy India talk Message-ID: <20141203193018.986481D34B6@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: extradoc Changeset: r5473:6790ce64ab6c Date: 2014-12-03 17:40 +0100 http://bitbucket.org/pypy/extradoc/changeset/6790ce64ab6c/ Log: First WIP for the Scipy India talk diff --git a/talk/scipyindia2014/talk.rst b/talk/scipyindia2014/talk.rst new file mode 100644 --- /dev/null +++ b/talk/scipyindia2014/talk.rst @@ -0,0 +1,79 @@ +============================= +PyPy and the scientific stack +============================= + +Introduction +------------ + +* PyPy contributor + +* Hired to work on NumPyPy + +* Interested in library compatibility + +* @rguillebert on twitter, feel free to send me questions + +* Software consultant + +* Feel free to interrupt me + +PyPy +---- + +* PyPy is an implementation of the Python language + +* Speed is one of its main advantages + +* Compatibility is very important to us + +Speed +----- + +* XXX : Insert speed.pypy.org screenshot + +Python +------ + +* Python is a great language + +* Very dynamic + +* Easy to introspect (pdb is just another Python module) + +* Considered slow + +How to get performance out of Python code ? +------------------------------------------- + +* Rewrite your code in C + +* Rewrite your code in Cython + +* Rewrite your code in some subset/dialect of Python like Numba + +* Just write Python and use PyPy, pay only the cost of what you use + +PyPy And C +---------- + +* PyPy is pretty good at interacting with C code with cffi + +* C extensions written using the Python C API can work, but they're slow and support is incomplete + +* We have ideas to help with that in some use cases + +Python C API +------------ + +* Leaks way too many implementation details (refcounting, PyObject structure fields) + +* Makes it hard to improve Python while supporting 100% of the API + +* Should we have a new C API ? + +NumPyPy +------- + +* ~80% of the numpy tests are passing + +* XXX From noreply at buildbot.pypy.org Wed Dec 3 21:05:30 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Wed, 3 Dec 2014 21:05:30 +0100 (CET) Subject: [pypy-commit] pypy default: simplify setslice with no shape Message-ID: <20141203200530.0E3CC1D350A@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74797:e2e286fb7245 Date: 2014-12-03 15:03 -0500 http://bitbucket.org/pypy/pypy/changeset/e2e286fb7245/ Log: simplify setslice with no shape diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -89,17 +89,14 @@ def setslice(space, shape, target, source): if not shape: - # XXX - simplify - target_iter, target_state = target.create_iter(shape) - source_iter, source_state = source.create_iter(shape) dtype = target.dtype - val = source_iter.getitem(source_state) + val = source.getitem(source.start) if dtype.is_str_or_unicode(): val = dtype.coerce(space, val) else: val = val.convert_to(space, dtype) - target_iter.setitem(target_state, val) - return target + target.setitem(target.start, val) + return target return _setslice(space, shape, target, source) def _setslice(space, shape, target, source): From noreply at buildbot.pypy.org Wed Dec 3 23:11:31 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Wed, 3 Dec 2014 23:11:31 +0100 (CET) Subject: [pypy-commit] pypy default: avoid tracking an index in setslice, update/enable its test_zjit Message-ID: <20141203221131.30B631C07E8@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74798:f1b314da580e Date: 2014-12-03 17:01 -0500 http://bitbucket.org/pypy/pypy/changeset/f1b314da580e/ Log: avoid tracking an index in setslice, update/enable its test_zjit diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -104,6 +104,7 @@ # array implementations, not arrays target_iter, target_state = target.create_iter(shape) source_iter, source_state = source.create_iter(shape) + source_iter.track_index = False dtype = target.dtype shapelen = len(shape) while not target_iter.done(target_state): diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -479,20 +479,27 @@ a = |30| b = |10| b[1] = 5.5 - c = b + b - a[0:30:3] = c + a[0:30:3] = b a -> 3 """ def test_setslice(self): result = self.run("setslice") - assert result == 11.0 - py.test.skip("don't run for now") + assert result == 5.5 self.check_trace_count(1) - self.check_simple_loop({'raw_load': 2, 'float_add': 1, - 'raw_store': 1, 'int_add': 2, - 'int_eq': 1, 'guard_false': 1, 'jump': 1, - 'arraylen_gc': 1}) + self.check_simple_loop({ + 'getarrayitem_gc': 1, + 'guard_false': 1, + 'guard_not_invalidated': 1, + 'guard_true': 1, + 'int_add': 4, + 'int_ge': 1, + 'int_lt': 1, + 'jump': 1, + 'raw_load': 1, + 'raw_store': 1, + 'setarrayitem_gc': 1, + }) def define_virtual_slice(): return """ From noreply at buildbot.pypy.org Wed Dec 3 23:37:52 2014 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 3 Dec 2014 23:37:52 +0100 (CET) Subject: [pypy-commit] pypy.org extradoc: update the values Message-ID: <20141203223752.444E21D2C37@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: extradoc Changeset: r556:90302869d491 Date: 2014-12-03 23:38 +0100 http://bitbucket.org/pypy/pypy.org/changeset/90302869d491/ Log: update the values diff --git a/don1.html b/don1.html --- a/don1.html +++ b/don1.html @@ -9,13 +9,13 @@ - $58082 of $105000 (55.3%) + $58367 of $105000 (55.6%)
diff --git a/don3.html b/don3.html --- a/don3.html +++ b/don3.html @@ -9,13 +9,13 @@ - $50904 of $60000 (84.8%) + $51099 of $60000 (85.2%)
diff --git a/don4.html b/don4.html --- a/don4.html +++ b/don4.html @@ -9,7 +9,7 @@ @@ -17,7 +17,7 @@ 2nd call: - $19674 of $80000 (24.6%) + $21455 of $80000 (26.8%)
From noreply at buildbot.pypy.org Thu Dec 4 01:28:19 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 01:28:19 +0100 (CET) Subject: [pypy-commit] pypy default: rename iter.update to iter.indices for clarity Message-ID: <20141204002819.991681C363D@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74799:1287046cabea Date: 2014-12-03 17:38 -0500 http://bitbucket.org/pypy/pypy/changeset/1287046cabea/ Log: rename iter.update to iter.indices for clarity diff --git a/pypy/module/micronumpy/flatiter.py b/pypy/module/micronumpy/flatiter.py --- a/pypy/module/micronumpy/flatiter.py +++ b/pypy/module/micronumpy/flatiter.py @@ -41,8 +41,8 @@ return space.wrap(self.state.index) def descr_coords(self, space): - self.state = self.iter.update(self.state) - return space.newtuple([space.wrap(c) for c in self.state.indices]) + coords = self.iter.indices(self.state) + return space.newtuple([space.wrap(c) for c in coords]) def descr_iter(self): return self diff --git a/pypy/module/micronumpy/iterators.py b/pypy/module/micronumpy/iterators.py --- a/pypy/module/micronumpy/iterators.py +++ b/pypy/module/micronumpy/iterators.py @@ -87,12 +87,12 @@ class IterState(object): - _immutable_fields_ = ['iterator', 'index', 'indices', 'offset'] + _immutable_fields_ = ['iterator', 'index', '_indices', 'offset'] def __init__(self, iterator, index, indices, offset): self.iterator = iterator self.index = index - self.indices = indices + self._indices = indices self.offset = offset @@ -144,7 +144,7 @@ indices = [0] * len(self.shape_m1) else: assert state.iterator is self - indices = state.indices + indices = state._indices for i in xrange(self.ndim_m1, -1, -1): indices[i] = 0 return IterState(self, 0, indices, self.array.start) @@ -155,7 +155,7 @@ index = state.index if self.track_index: index += 1 - indices = state.indices + indices = state._indices offset = state.offset if self.contiguous: offset += self.array.dtype.elsize @@ -184,20 +184,20 @@ return IterState(self, index, None, offset) @jit.unroll_safe - def update(self, state): + def indices(self, state): assert state.iterator is self assert self.track_index + indices = state._indices if not self.contiguous: - return state + return indices current = state.index - indices = state.indices for i in xrange(len(self.shape_m1)): if self.factors[i] != 0: indices[i] = current / self.factors[i] current %= self.factors[i] else: indices[i] = 0 - return IterState(self, state.index, indices, state.offset) + return indices def done(self, state): assert state.iterator is self diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -247,8 +247,8 @@ dtype=dtype) assert not arr_iter.done(arr_state) w_val = arr_iter.getitem(arr_state).convert_to(space, dtype) - out_state = out_iter.update(out_state) - if out_state.indices[axis] == 0: + out_indices = out_iter.indices(out_state) + if out_indices[axis] == 0: if identity is not None: w_val = func(dtype, identity, w_val) else: @@ -380,9 +380,9 @@ while not arr_iter.done(arr_state): nonzero_driver.jit_merge_point(shapelen=shapelen, dims=dims, dtype=dtype) if arr_iter.getitem_bool(arr_state): - arr_state = arr_iter.update(arr_state) + arr_indices = arr_iter.indices(arr_state) for d in dims: - res_iter.setitem(res_state, box(arr_state.indices[d])) + res_iter.setitem(res_state, box(arr_indices[d])) res_state = res_iter.next(res_state) arr_state = arr_iter.next(arr_state) return res diff --git a/pypy/module/micronumpy/test/test_iterators.py b/pypy/module/micronumpy/test/test_iterators.py --- a/pypy/module/micronumpy/test/test_iterators.py +++ b/pypy/module/micronumpy/test/test_iterators.py @@ -31,16 +31,14 @@ s = i.next(s) assert s.offset == 3 assert not i.done(s) - assert s.indices == [0,0] - s = i.update(s) - assert s.indices == [0,3] + assert s._indices == [0,0] + assert i.indices(s) == [0,3] #cause a dimension overflow s = i.next(s) s = i.next(s) assert s.offset == 5 - assert s.indices == [0,3] - s = i.update(s) - assert s.indices == [1,0] + assert s._indices == [0,3] + assert i.indices(s) == [1,0] #Now what happens if the array is transposed? strides[-1] != 1 # therefore layout is non-contiguous @@ -56,12 +54,12 @@ s = i.next(s) assert s.offset == 9 assert not i.done(s) - assert s.indices == [0,3] + assert s._indices == [0,3] #cause a dimension overflow s = i.next(s) s = i.next(s) assert s.offset == 1 - assert s.indices == [1,0] + assert s._indices == [1,0] def test_iterator_goto(self): shape = [3, 5] @@ -74,9 +72,9 @@ assert not i.contiguous s = i.reset() assert s.index == 0 - assert s.indices == [0, 0] + assert s._indices == [0, 0] assert s.offset == a.start s = i.goto(11) assert s.index == 11 - assert s.indices is None + assert s._indices is None assert s.offset == a.start + 5 From noreply at buildbot.pypy.org Thu Dec 4 01:28:20 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 01:28:20 +0100 (CET) Subject: [pypy-commit] pypy default: optimize iterators for single dim arrays Message-ID: <20141204002820.CD6C41C363D@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74800:268850625399 Date: 2014-12-03 18:15 -0500 http://bitbucket.org/pypy/pypy/changeset/268850625399/ Log: optimize iterators for single dim arrays diff --git a/pypy/module/micronumpy/iterators.py b/pypy/module/micronumpy/iterators.py --- a/pypy/module/micronumpy/iterators.py +++ b/pypy/module/micronumpy/iterators.py @@ -159,6 +159,8 @@ offset = state.offset if self.contiguous: offset += self.array.dtype.elsize + elif self.ndim_m1 == 0: + offset += self.strides[0] else: for i in xrange(self.ndim_m1, -1, -1): idx = indices[i] @@ -176,6 +178,8 @@ offset = self.array.start if self.contiguous: offset += index * self.array.dtype.elsize + elif self.ndim_m1 == 0: + offset += index * self.strides[0] else: current = index for i in xrange(len(self.shape_m1)): @@ -188,7 +192,7 @@ assert state.iterator is self assert self.track_index indices = state._indices - if not self.contiguous: + if not (self.contiguous or self.ndim_m1 == 0): return indices current = state.index for i in xrange(len(self.shape_m1)): diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -102,18 +102,15 @@ assert result == 3 + 3 self.check_trace_count(1) self.check_simple_loop({ + 'arraylen_gc': 1, 'float_add': 1, - 'getarrayitem_gc': 1, 'guard_false': 1, 'guard_not_invalidated': 1, - 'guard_true': 1, - 'int_add': 5, + 'int_add': 4, 'int_ge': 1, - 'int_lt': 1, 'jump': 1, 'raw_load': 2, 'raw_store': 1, - 'setarrayitem_gc': 1, }) def define_pow(): @@ -127,24 +124,22 @@ assert result == 3 ** 2 self.check_trace_count(1) self.check_simple_loop({ + 'arraylen_gc': 1, 'call': 1, 'float_add': 1, 'float_eq': 3, 'float_mul': 2, 'float_ne': 1, - 'getarrayitem_gc': 1, 'getarrayitem_raw': 1, # read the errno 'guard_false': 4, 'guard_not_invalidated': 1, - 'guard_true': 3, - 'int_add': 5, + 'guard_true': 2, + 'int_add': 4, 'int_ge': 1, 'int_is_true': 1, - 'int_lt': 1, 'jump': 1, 'raw_load': 2, 'raw_store': 1, - 'setarrayitem_gc': 1, 'setarrayitem_raw': 1, # write the errno }) @@ -162,18 +157,15 @@ self.check_trace_count(2) # extra one for the astype del get_stats().loops[0] # we don't care about it self.check_simple_loop({ + 'arraylen_gc': 1, 'call': 1, - 'getarrayitem_gc': 1, 'guard_false': 1, 'guard_not_invalidated': 1, - 'guard_true': 1, - 'int_add': 5, + 'int_add': 4, 'int_ge': 1, - 'int_lt': 1, 'jump': 1, 'raw_load': 2, 'raw_store': 1, - 'setarrayitem_gc': 1, }) def define_sum(): @@ -390,18 +382,15 @@ assert result == 18 self.check_trace_count(1) self.check_simple_loop({ + 'arraylen_gc': 2, 'float_add': 1, - 'getarrayitem_gc': 2, 'guard_false': 1, 'guard_not_invalidated': 1, - 'guard_true': 2, - 'int_add': 6, + 'int_add': 4, 'int_ge': 1, - 'int_lt': 2, 'jump': 1, 'raw_load': 2, 'raw_store': 1, - 'setarrayitem_gc': 2, }) def define_take(): @@ -488,17 +477,14 @@ assert result == 5.5 self.check_trace_count(1) self.check_simple_loop({ - 'getarrayitem_gc': 1, + 'arraylen_gc': 1, 'guard_false': 1, 'guard_not_invalidated': 1, - 'guard_true': 1, - 'int_add': 4, + 'int_add': 3, 'int_ge': 1, - 'int_lt': 1, 'jump': 1, 'raw_load': 1, 'raw_store': 1, - 'setarrayitem_gc': 1, }) def define_virtual_slice(): @@ -618,12 +604,13 @@ 'getarrayitem_gc_pure': 9, 'getfield_gc_pure': 49, 'guard_class': 4, - 'guard_false': 13, + 'guard_false': 15, 'guard_not_invalidated': 2, 'guard_true': 14, 'int_add': 17, 'int_ge': 4, 'int_is_true': 3, + 'int_is_zero': 2, 'int_le': 5, 'int_lt': 8, 'int_sub': 3, From noreply at buildbot.pypy.org Thu Dec 4 01:28:22 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 01:28:22 +0100 (CET) Subject: [pypy-commit] pypy default: fix test_pypy_c for iterator changes Message-ID: <20141204002822.0E9251C363D@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74801:651d67d1059e Date: 2014-12-03 19:27 -0500 http://bitbucket.org/pypy/pypy/changeset/651d67d1059e/ Log: fix test_pypy_c for iterator changes diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -99,7 +99,7 @@ i128 = int_mul(i117, i59) i129 = int_add(i55, i128) f149 = raw_load(i100, i129, descr=) - p150 = getfield_gc_pure(p123, descr=) + p150 = getfield_gc_pure(p123, descr=) i151 = int_add(i117, 1) setarrayitem_gc(p150, 1, 0, descr=) setarrayitem_gc(p150, 0, 0, descr=) @@ -112,7 +112,7 @@ setfield_gc(p156, p49, descr=) setfield_gc(p156, i55, descr=) setfield_gc(p156, 0, descr=) - setfield_gc(p156, p150, descr=) + setfield_gc(p156, p150, descr=) setfield_gc(p16, p156, descr=) }}} jump(p0, p1, p3, p6, p7, p12, p14, p16, i151, f149, p26, i44, i50, i59, i55, i100, p156, p49, descr=...) @@ -140,7 +140,7 @@ i132 = int_add(i53, i131) guard_not_invalidated(descr=...) raw_store(i103, i132, 42.000000, descr=) - p152 = getfield_gc_pure(p126, descr=) + p152 = getfield_gc_pure(p126, descr=) i153 = int_add(i120, 1) i154 = getfield_raw(#, descr=) setarrayitem_gc(p152, 1, 0, descr=) @@ -152,7 +152,7 @@ setfield_gc(p158, p47, descr=) setfield_gc(p158, i53, descr=) setfield_gc(p158, 0, descr=) - setfield_gc(p158, p152, descr=) + setfield_gc(p158, p152, descr=) setfield_gc(p16, p158, descr=) }}} jump(p0, p1, p3, p6, p7, p12, p14, p16, i153, i42, i48, i57, i53, p47, i103, p158, descr=...) From noreply at buildbot.pypy.org Thu Dec 4 03:03:51 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 03:03:51 +0100 (CET) Subject: [pypy-commit] pypy default: silence pyflakes Message-ID: <20141204020351.704941D2C37@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74802:6bd0b3c411b0 Date: 2014-12-03 19:48 -0500 http://bitbucket.org/pypy/pypy/changeset/6bd0b3c411b0/ Log: silence pyflakes diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py --- a/pypy/module/micronumpy/boxes.py +++ b/pypy/module/micronumpy/boxes.py @@ -167,7 +167,7 @@ if len(args_w) >= 1: for w_arg in args_w: try: - idx = support.index_w(space, w_arg) + support.index_w(space, w_arg) except OperationError: raise oefmt(space.w_TypeError, "an integer is required") raise oefmt(space.w_ValueError, "axes don't match array") From noreply at buildbot.pypy.org Thu Dec 4 03:03:52 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 03:03:52 +0100 (CET) Subject: [pypy-commit] pypy default: move unnecessary additions to base iterator from nditer branches to subclass Message-ID: <20141204020352.D20971D2DD0@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74803:73e3f0512a73 Date: 2014-12-03 21:02 -0500 http://bitbucket.org/pypy/pypy/changeset/73e3f0512a73/ Log: move unnecessary additions to base iterator from nditer branches to subclass diff --git a/pypy/module/micronumpy/iterators.py b/pypy/module/micronumpy/iterators.py --- a/pypy/module/micronumpy/iterators.py +++ b/pypy/module/micronumpy/iterators.py @@ -41,16 +41,6 @@ from pypy.module.micronumpy.base import W_NDimArray from pypy.module.micronumpy.flagsobj import _update_contiguous_flags -class OpFlag(object): - def __init__(self): - self.rw = '' - self.broadcast = True - self.force_contig = False - self.force_align = False - self.native_byte_order = False - self.tmp_copy = '' - self.allocate = False - class PureShapeIter(object): def __init__(self, shape, idx_w): @@ -99,14 +89,12 @@ class ArrayIter(object): _immutable_fields_ = ['contiguous', 'array', 'size', 'ndim_m1', 'shape_m1[*]', 'strides[*]', 'backstrides[*]', 'factors[*]', - 'slice_shape', 'slice_stride', 'slice_backstride', - 'track_index', 'operand_type', 'slice_operand_type'] + 'track_index'] track_index = True @jit.unroll_safe - def __init__(self, array, size, shape, strides, backstrides, op_flags=OpFlag()): - from pypy.module.micronumpy import concrete + def __init__(self, array, size, shape, strides, backstrides): assert len(shape) == len(strides) == len(backstrides) _update_contiguous_flags(array) self.contiguous = (array.flags & NPY.ARRAY_C_CONTIGUOUS and @@ -118,12 +106,6 @@ self.shape_m1 = [s - 1 for s in shape] self.strides = strides self.backstrides = backstrides - self.slice_shape = 1 - self.slice_stride = -1 - if strides: - self.slice_stride = strides[-1] - self.slice_backstride = 1 - self.slice_operand_type = concrete.SliceArray ndim = len(shape) factors = [0] * ndim @@ -133,10 +115,6 @@ else: factors[ndim-i-1] = factors[ndim-i] * shape[ndim-i] self.factors = factors - if op_flags.rw == 'r': - self.operand_type = concrete.ConcreteNonWritableArrayWithBase - else: - self.operand_type = concrete.ConcreteArrayWithBase @jit.unroll_safe def reset(self, state=None): @@ -220,12 +198,6 @@ assert state.iterator is self self.array.setitem(state.offset, elem) - def getoperand(self, st, base): - impl = self.operand_type - res = impl([], self.array.dtype, self.array.order, [], [], - self.array.storage, base) - res.start = st.offset - return res def AxisIter(array, shape, axis, cumulative): strides = array.get_strides() @@ -249,42 +221,3 @@ size /= shape[axis] shape[axis] = backstrides[axis] = 0 return ArrayIter(array, size, shape, array.strides, backstrides) - -class SliceIter(ArrayIter): - ''' - used with external loops, getitem and setitem return a SliceArray - view into the original array - ''' - _immutable_fields_ = ['base', 'slice_shape[*]', 'slice_stride[*]', 'slice_backstride[*]'] - - def __init__(self, array, size, shape, strides, backstrides, slice_shape, - slice_stride, slice_backstride, op_flags, base): - from pypy.module.micronumpy import concrete - ArrayIter.__init__(self, array, size, shape, strides, backstrides, op_flags) - self.slice_shape = slice_shape - self.slice_stride = slice_stride - self.slice_backstride = slice_backstride - self.base = base - if op_flags.rw == 'r': - self.slice_operand_type = concrete.NonWritableSliceArray - else: - self.slice_operand_type = concrete.SliceArray - - def getitem(self, state): - # XXX cannot be called - must return a boxed value - assert False - - def getitem_bool(self, state): - # XXX cannot be called - must return a boxed value - assert False - - def setitem(self, state, elem): - # XXX cannot be called - must return a boxed value - assert False - - def getoperand(self, state, base): - assert state.iterator is self - impl = self.slice_operand_type - arr = impl(state.offset, [self.slice_stride], [self.slice_backstride], - [self.slice_shape], self.array, self.base) - return arr diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py --- a/pypy/module/micronumpy/nditer.py +++ b/pypy/module/micronumpy/nditer.py @@ -6,7 +6,7 @@ from pypy.module.micronumpy import ufuncs, support, concrete from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy.descriptor import decode_w_dtype -from pypy.module.micronumpy.iterators import ArrayIter, SliceIter, OpFlag +from pypy.module.micronumpy.iterators import ArrayIter from pypy.module.micronumpy.strides import (calculate_broadcast_strides, shape_agreement, shape_agreement_multiple) @@ -36,6 +36,16 @@ return ret +class OpFlag(object): + def __init__(self): + self.rw = '' + self.broadcast = True + self.force_contig = False + self.force_align = False + self.native_byte_order = False + self.tmp_copy = '' + self.allocate = False + def parse_op_flag(space, lst): op_flag = OpFlag() for w_item in lst: @@ -142,11 +152,75 @@ raise NotImplementedError('not implemented yet') -def get_iter(space, order, arr, shape, dtype, op_flags): +class OperandIter(ArrayIter): + _immutable_fields_ = ['slice_shape', 'slice_stride', 'slice_backstride', + 'operand_type', 'base'] + + def getitem(self, state): + # XXX cannot be called - must return a boxed value + assert False + + def getitem_bool(self, state): + # XXX cannot be called - must return a boxed value + assert False + + def setitem(self, state, elem): + # XXX cannot be called - must return a boxed value + assert False + + +class ConcreteIter(OperandIter): + def __init__(self, array, size, shape, strides, backstrides, + op_flags, base): + OperandIter.__init__(self, array, size, shape, strides, backstrides) + self.slice_shape = 1 + self.slice_stride = -1 + if strides: + self.slice_stride = strides[-1] + self.slice_backstride = 1 + if op_flags.rw == 'r': + self.operand_type = concrete.ConcreteNonWritableArrayWithBase + else: + self.operand_type = concrete.ConcreteArrayWithBase + self.base = base + + def getoperand(self, state): + assert state.iterator is self + impl = self.operand_type + #assert issubclass(impl, concrete.ConcreteArrayWithBase) + res = impl([], self.array.dtype, self.array.order, [], [], + self.array.storage, self.base) + res.start = state.offset + return res + + +class SliceIter(OperandIter): + def __init__(self, array, size, shape, strides, backstrides, slice_shape, + slice_stride, slice_backstride, op_flags, base): + OperandIter.__init__(self, array, size, shape, strides, backstrides) + self.slice_shape = slice_shape + self.slice_stride = slice_stride + self.slice_backstride = slice_backstride + if op_flags.rw == 'r': + self.operand_type = concrete.NonWritableSliceArray + else: + self.operand_type = concrete.SliceArray + self.base = base + + def getoperand(self, state): + assert state.iterator is self + impl = self.operand_type + #assert issubclass(impl, concrete.SliceArray) + arr = impl(state.offset, [self.slice_stride], [self.slice_backstride], + [self.slice_shape], self.array, self.base) + return arr + + +def get_iter(space, order, arr, shape, dtype, op_flags, base): imp = arr.implementation backward = is_backward(imp, order) if arr.is_scalar(): - return ArrayIter(imp, 1, [], [], [], op_flags=op_flags) + return ConcreteIter(imp, 1, [], [], [], op_flags, base) if (imp.strides[0] < imp.strides[-1] and not backward) or \ (imp.strides[0] > imp.strides[-1] and backward): # flip the strides. Is this always true for multidimension? @@ -161,7 +235,7 @@ backstrides = imp.backstrides r = calculate_broadcast_strides(strides, backstrides, imp.shape, shape, backward) - return ArrayIter(imp, imp.get_size(), shape, r[0], r[1], op_flags=op_flags) + return ConcreteIter(imp, imp.get_size(), shape, r[0], r[1], op_flags, base) def calculate_ndim(op_in, oa_ndim): if oa_ndim >=0: @@ -398,7 +472,7 @@ self.iters = [] for i in range(len(self.seq)): it = get_iter(space, self.order, self.seq[i], self.shape, - self.dtypes[i], self.op_flags[i]) + self.dtypes[i], self.op_flags[i], self) it.contiguous = False self.iters.append((it, it.reset())) @@ -437,7 +511,7 @@ return space.wrap(self) def getitem(self, it, st): - res = it.getoperand(st, self) + res = it.getoperand(st) return W_NDimArray(res) def descr_getitem(self, space, w_idx): From noreply at buildbot.pypy.org Thu Dec 4 03:08:04 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 03:08:04 +0100 (CET) Subject: [pypy-commit] pypy default: cleanup comments Message-ID: <20141204020804.B7F2A1D2C37@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74804:cab353e0b9a5 Date: 2014-12-03 21:08 -0500 http://bitbucket.org/pypy/pypy/changeset/cab353e0b9a5/ Log: cleanup comments diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py --- a/pypy/module/micronumpy/nditer.py +++ b/pypy/module/micronumpy/nditer.py @@ -157,15 +157,15 @@ 'operand_type', 'base'] def getitem(self, state): - # XXX cannot be called - must return a boxed value + # cannot be called - must return a boxed value assert False def getitem_bool(self, state): - # XXX cannot be called - must return a boxed value + # cannot be called - must return a boxed value assert False def setitem(self, state, elem): - # XXX cannot be called - must return a boxed value + # cannot be called - must return a boxed value assert False @@ -187,7 +187,6 @@ def getoperand(self, state): assert state.iterator is self impl = self.operand_type - #assert issubclass(impl, concrete.ConcreteArrayWithBase) res = impl([], self.array.dtype, self.array.order, [], [], self.array.storage, self.base) res.start = state.offset @@ -210,7 +209,6 @@ def getoperand(self, state): assert state.iterator is self impl = self.operand_type - #assert issubclass(impl, concrete.SliceArray) arr = impl(state.offset, [self.slice_stride], [self.slice_backstride], [self.slice_shape], self.array, self.base) return arr From noreply at buildbot.pypy.org Thu Dec 4 05:38:58 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 05:38:58 +0100 (CET) Subject: [pypy-commit] pypy default: optimize call2 when lhs or rhs is a scalar Message-ID: <20141204043858.D59A91C1147@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74805:378bfef11c09 Date: 2014-12-03 23:30 -0500 http://bitbucket.org/pypy/pypy/changeset/378bfef11c09/ Log: optimize call2 when lhs or rhs is a scalar diff --git a/pypy/module/micronumpy/flatiter.py b/pypy/module/micronumpy/flatiter.py --- a/pypy/module/micronumpy/flatiter.py +++ b/pypy/module/micronumpy/flatiter.py @@ -22,6 +22,9 @@ def get_shape(self): return self.shape + def get_size(self): + return self.base().get_size() + def create_iter(self, shape=None, backward_broadcast=False): assert isinstance(self.base(), W_NDimArray) return self.base().create_iter() diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -42,23 +42,38 @@ # TODO handle __array_priorities__ and maybe flip the order + if w_lhs.get_size() == 1: + w_left = w_lhs.get_scalar_value().convert_to(space, calc_dtype) + left_iter = left_state = None + else: + w_left = None + left_iter, left_state = w_lhs.create_iter(shape) + left_iter.track_index = False + + if w_rhs.get_size() == 1: + w_right = w_rhs.get_scalar_value().convert_to(space, calc_dtype) + right_iter = right_state = None + else: + w_right = None + right_iter, right_state = w_rhs.create_iter(shape) + right_iter.track_index = False + if out is None: out = W_NDimArray.from_shape(space, shape, res_dtype, w_instance=lhs_for_subtype) - left_iter, left_state = w_lhs.create_iter(shape) - right_iter, right_state = w_rhs.create_iter(shape) out_iter, out_state = out.create_iter(shape) - left_iter.track_index = right_iter.track_index = False shapelen = len(shape) while not out_iter.done(out_state): call2_driver.jit_merge_point(shapelen=shapelen, func=func, calc_dtype=calc_dtype, res_dtype=res_dtype) - w_left = left_iter.getitem(left_state).convert_to(space, calc_dtype) - w_right = right_iter.getitem(right_state).convert_to(space, calc_dtype) + if left_iter: + w_left = left_iter.getitem(left_state).convert_to(space, calc_dtype) + left_state = left_iter.next(left_state) + if right_iter: + w_right = right_iter.getitem(right_state).convert_to(space, calc_dtype) + right_state = right_iter.next(right_state) out_iter.setitem(out_state, func(calc_dtype, w_left, w_right).convert_to( space, res_dtype)) - left_state = left_iter.next(left_state) - right_state = right_iter.next(right_state) out_state = out_iter.next(out_state) return out @@ -68,11 +83,12 @@ reds='auto') def call1(space, shape, func, calc_dtype, res_dtype, w_obj, out): + obj_iter, obj_state = w_obj.create_iter(shape) + obj_iter.track_index = False + if out is None: out = W_NDimArray.from_shape(space, shape, res_dtype, w_instance=w_obj) - obj_iter, obj_state = w_obj.create_iter(shape) out_iter, out_state = out.create_iter(shape) - obj_iter.track_index = False shapelen = len(shape) while not out_iter.done(out_state): call1_driver.jit_merge_point(shapelen=shapelen, func=func, diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -102,14 +102,13 @@ assert result == 3 + 3 self.check_trace_count(1) self.check_simple_loop({ - 'arraylen_gc': 1, 'float_add': 1, 'guard_false': 1, 'guard_not_invalidated': 1, - 'int_add': 4, + 'int_add': 3, 'int_ge': 1, 'jump': 1, - 'raw_load': 2, + 'raw_load': 1, 'raw_store': 1, }) @@ -124,21 +123,18 @@ assert result == 3 ** 2 self.check_trace_count(1) self.check_simple_loop({ - 'arraylen_gc': 1, 'call': 1, - 'float_add': 1, - 'float_eq': 3, + 'float_eq': 2, 'float_mul': 2, - 'float_ne': 1, 'getarrayitem_raw': 1, # read the errno - 'guard_false': 4, + 'guard_false': 2, 'guard_not_invalidated': 1, 'guard_true': 2, - 'int_add': 4, + 'int_add': 3, 'int_ge': 1, 'int_is_true': 1, 'jump': 1, - 'raw_load': 2, + 'raw_load': 1, 'raw_store': 1, 'setarrayitem_raw': 1, # write the errno }) @@ -157,14 +153,13 @@ self.check_trace_count(2) # extra one for the astype del get_stats().loops[0] # we don't care about it self.check_simple_loop({ - 'arraylen_gc': 1, 'call': 1, 'guard_false': 1, 'guard_not_invalidated': 1, - 'int_add': 4, + 'int_add': 3, 'int_ge': 1, 'jump': 1, - 'raw_load': 2, + 'raw_load': 1, 'raw_store': 1, }) From noreply at buildbot.pypy.org Thu Dec 4 05:55:30 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 05:55:30 +0100 (CET) Subject: [pypy-commit] pypy default: enable test_multidim in test_zjit Message-ID: <20141204045530.15ACC1D2859@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74806:5ae2c3c20777 Date: 2014-12-03 23:54 -0500 http://bitbucket.org/pypy/pypy/changeset/5ae2c3c20777/ Log: enable test_multidim in test_zjit diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -420,13 +420,19 @@ def test_multidim(self): result = self.run('multidim') assert result == 8 - py.test.skip("don't run for now") # int_add might be 1 here if we try slightly harder with # reusing indexes or some optimization - self.check_simple_loop({'float_add': 1, 'raw_load': 2, - 'guard_false': 1, 'int_add': 1, 'int_ge': 1, - 'jump': 1, 'raw_store': 1, - 'arraylen_gc': 1}) + self.check_trace_count(1) + self.check_simple_loop({ + 'float_add': 1, + 'guard_false': 1, + 'guard_not_invalidated': 1, + 'int_add': 4, + 'int_ge': 1, + 'jump': 1, + 'raw_load': 2, + 'raw_store': 1, + }) def define_multidim_slice(): return """ From noreply at buildbot.pypy.org Thu Dec 4 06:20:12 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 06:20:12 +0100 (CET) Subject: [pypy-commit] pypy default: enable test_multidim_slice in test_zjit Message-ID: <20141204052012.8E8701D2859@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74807:5f2acc45e585 Date: 2014-12-04 00:20 -0500 http://bitbucket.org/pypy/pypy/changeset/5f2acc45e585/ Log: enable test_multidim_slice in test_zjit diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -445,10 +445,47 @@ def test_multidim_slice(self): result = self.run('multidim_slice') assert result == 12 - py.test.skip("improve") # XXX the bridge here is scary. Hopefully jit-targets will fix that, # otherwise it looks kind of good - self.check_simple_loop({}) + self.check_trace_count(2) + self.check_simple_loop({ + 'float_add': 1, + 'getarrayitem_gc': 2, + 'guard_false': 1, + 'guard_not_invalidated': 1, + 'guard_true': 2, + 'int_add': 6, + 'int_ge': 1, + 'int_lt': 2, + 'jump': 1, + 'raw_load': 2, + 'raw_store': 1, + 'setarrayitem_gc': 2, + }) + self.check_resops({ + 'float_add': 3, + 'getarrayitem_gc': 7, + 'getarrayitem_gc_pure': 14, + 'getfield_gc_pure': 69, + 'guard_class': 5, + 'guard_false': 20, + 'guard_nonnull': 6, + 'guard_nonnull_class': 1, + 'guard_not_invalidated': 3, + 'guard_true': 16, + 'guard_value': 2, + 'int_add': 24, + 'int_ge': 4, + 'int_is_true': 6, + 'int_is_zero': 4, + 'int_le': 5, + 'int_lt': 7, + 'int_sub': 2, + 'jump': 2, + 'raw_load': 5, + 'raw_store': 3, + 'setarrayitem_gc': 8, + }) def define_broadcast(): return """ From noreply at buildbot.pypy.org Thu Dec 4 06:36:47 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 06:36:47 +0100 (CET) Subject: [pypy-commit] pypy default: enable test_broadcast too Message-ID: <20141204053647.1C2AA1D29E9@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74808:d1a536a138a3 Date: 2014-12-04 00:36 -0500 http://bitbucket.org/pypy/pypy/changeset/d1a536a138a3/ Log: enable test_broadcast too diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -498,8 +498,42 @@ def test_broadcast(self): result = self.run("broadcast") assert result == 10 - py.test.skip("improve") - self.check_simple_loop({}) + self.check_trace_count(2) + self.check_simple_loop({ + 'float_add': 1, + 'getarrayitem_gc': 1, + 'guard_false': 1, + 'guard_not_invalidated': 1, + 'guard_true': 1, + 'int_add': 5, + 'int_ge': 1, + 'int_lt': 1, + 'jump': 1, + 'raw_load': 2, + 'raw_store': 1, + 'setarrayitem_gc': 1, + }) + self.check_resops({ + 'float_add': 2, + 'getarrayitem_gc': 2, + 'getarrayitem_gc_pure': 2, + 'getfield_gc_pure': 36, + 'guard_class': 3, + 'guard_false': 7, + 'guard_nonnull': 2, + 'guard_not_invalidated': 2, + 'guard_true': 8, + 'int_add': 11, + 'int_ge': 2, + 'int_is_true': 3, + 'int_is_zero': 1, + 'int_le': 1, + 'int_lt': 2, + 'jump': 1, + 'raw_load': 4, + 'raw_store': 2, + 'setarrayitem_gc': 2, + }) def define_setslice(): return """ From noreply at buildbot.pypy.org Thu Dec 4 08:03:16 2014 From: noreply at buildbot.pypy.org (rguillebert) Date: Thu, 4 Dec 2014 08:03:16 +0100 (CET) Subject: [pypy-commit] extradoc extradoc: Progress Message-ID: <20141204070316.5B4C61C100F@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: extradoc Changeset: r5474:70b9b4be4e0d Date: 2014-12-04 02:13 +0100 http://bitbucket.org/pypy/extradoc/changeset/70b9b4be4e0d/ Log: Progress diff --git a/talk/scipyindia2014/talk.rst b/talk/scipyindia2014/talk.rst --- a/talk/scipyindia2014/talk.rst +++ b/talk/scipyindia2014/talk.rst @@ -26,11 +26,6 @@ * Compatibility is very important to us -Speed ------ - -* XXX : Insert speed.pypy.org screenshot - Python ------ @@ -42,6 +37,16 @@ * Considered slow +Speed +----- + +* XXX : Insert speed.pypy.org screenshot + +Demo +---- + +* Real-time edge detection + How to get performance out of Python code ? ------------------------------------------- @@ -58,6 +63,12 @@ * PyPy is pretty good at interacting with C code with cffi +* With CFFI you can call C code from Python and expose Python functions to C + + - this means that you can create your own C API in pure python ! + +* It is now possible to embed PyPy in a C application (uWSGI) + * C extensions written using the Python C API can work, but they're slow and support is incomplete * We have ideas to help with that in some use cases From noreply at buildbot.pypy.org Thu Dec 4 08:03:17 2014 From: noreply at buildbot.pypy.org (rguillebert) Date: Thu, 4 Dec 2014 08:03:17 +0100 (CET) Subject: [pypy-commit] extradoc extradoc: Add the rst2beamer boilerplate Message-ID: <20141204070317.B7D3F1C100F@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: extradoc Changeset: r5475:f56bf45a654e Date: 2014-12-04 02:25 +0100 http://bitbucket.org/pypy/extradoc/changeset/f56bf45a654e/ Log: Add the rst2beamer boilerplate diff --git a/talk/scipyindia2014/Makefile b/talk/scipyindia2014/Makefile new file mode 100644 --- /dev/null +++ b/talk/scipyindia2014/Makefile @@ -0,0 +1,18 @@ +# you can find rst2beamer.py here: +# https://bitbucket.org/antocuni/env/raw/default/bin/rst2beamer.py + +# WARNING: to work, it needs this patch for docutils +# https://sourceforge.net/tracker/?func=detail&atid=422032&aid=1459707&group_id=38414 + +talk.pdf: talk.rst author.latex stylesheet.latex + python `which rst2beamer.py` --stylesheet=stylesheet.latex --documentoptions=14pt talk.rst talk.latex || exit + #/home/antocuni/.virtualenvs/rst2beamer/bin/python `which rst2beamer.py` --stylesheet=stylesheet.latex --documentoptions=14pt talk.rst talk.latex || exit + sed 's/\\date{}/\\input{author.latex}/' -i talk.latex || exit + #sed 's/\\maketitle/\\input{title.latex}/' -i talk.latex || exit + pdflatex talk.latex || exit + +view: talk.pdf + evince talk.pdf & + +xpdf: talk.pdf + xpdf talk.pdf & diff --git a/talk/scipyindia2014/author.latex b/talk/scipyindia2014/author.latex new file mode 100644 --- /dev/null +++ b/talk/scipyindia2014/author.latex @@ -0,0 +1,9 @@ +\definecolor{rrblitbackground}{rgb}{0.0, 0.0, 0.0} + +\title[PyPy and the scientific stack]{PyPy and the scientific stack} +\author[rguillebert] +{Romain Guillebert\\ +\includegraphics[width=80px]{../img/py-web-new.png}} + +\institute{Scipy India 2014} +\date{December 7th, 2014} diff --git a/talk/scipyindia2014/beamerdefs.txt b/talk/scipyindia2014/beamerdefs.txt new file mode 100644 --- /dev/null +++ b/talk/scipyindia2014/beamerdefs.txt @@ -0,0 +1,108 @@ +.. colors +.. =========================== + +.. role:: green +.. role:: red + + +.. general useful commands +.. =========================== + +.. |pause| raw:: latex + + \pause + +.. |small| raw:: latex + + {\small + +.. |end_small| raw:: latex + + } + +.. |scriptsize| raw:: latex + + {\scriptsize + +.. |end_scriptsize| raw:: latex + + } + +.. |strike<| raw:: latex + + \sout{ + +.. closed bracket +.. =========================== + +.. |>| raw:: latex + + } + + +.. example block +.. =========================== + +.. |example<| raw:: latex + + \begin{exampleblock}{ + + +.. |end_example| raw:: latex + + \end{exampleblock} + + + +.. alert block +.. =========================== + +.. |alert<| raw:: latex + + \begin{alertblock}{ + + +.. |end_alert| raw:: latex + + \end{alertblock} + + + +.. columns +.. =========================== + +.. |column1| raw:: latex + + \begin{columns} + \begin{column}{0.45\textwidth} + +.. |column2| raw:: latex + + \end{column} + \begin{column}{0.45\textwidth} + + +.. |end_columns| raw:: latex + + \end{column} + \end{columns} + + + +.. |snake| image:: ../../img/py-web-new.png + :scale: 15% + + + +.. nested blocks +.. =========================== + +.. |nested| raw:: latex + + \begin{columns} + \begin{column}{0.85\textwidth} + +.. |end_nested| raw:: latex + + \end{column} + \end{columns} diff --git a/talk/scipyindia2014/stylesheet.latex b/talk/scipyindia2014/stylesheet.latex new file mode 100644 --- /dev/null +++ b/talk/scipyindia2014/stylesheet.latex @@ -0,0 +1,9 @@ +\setbeamercovered{transparent} +\setbeamertemplate{navigation symbols}{} + +\definecolor{darkgreen}{rgb}{0, 0.5, 0.0} +\newcommand{\docutilsrolegreen}[1]{\color{darkgreen}#1\normalcolor} +\newcommand{\docutilsrolered}[1]{\color{red}#1\normalcolor} + +\newcommand{\green}[1]{\color{darkgreen}#1\normalcolor} +\newcommand{\red}[1]{\color{red}#1\normalcolor} diff --git a/talk/scipyindia2014/talk.rst b/talk/scipyindia2014/talk.rst --- a/talk/scipyindia2014/talk.rst +++ b/talk/scipyindia2014/talk.rst @@ -65,7 +65,7 @@ * With CFFI you can call C code from Python and expose Python functions to C - - this means that you can create your own C API in pure python ! + - This means you can create your own C API in pure python ! * It is now possible to embed PyPy in a C application (uWSGI) From noreply at buildbot.pypy.org Thu Dec 4 08:03:18 2014 From: noreply at buildbot.pypy.org (rguillebert) Date: Thu, 4 Dec 2014 08:03:18 +0100 (CET) Subject: [pypy-commit] extradoc extradoc: Progress Message-ID: <20141204070318.D627A1C100F@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: extradoc Changeset: r5476:dc90c5848fd0 Date: 2014-12-04 07:28 +0530 http://bitbucket.org/pypy/extradoc/changeset/dc90c5848fd0/ Log: Progress diff --git a/talk/scipyindia2014/talk.rst b/talk/scipyindia2014/talk.rst --- a/talk/scipyindia2014/talk.rst +++ b/talk/scipyindia2014/talk.rst @@ -56,16 +56,25 @@ * Rewrite your code in some subset/dialect of Python like Numba -* Just write Python and use PyPy, pay only the cost of what you use +* Just write Python and use PyPy, only pay the cost of what you use -PyPy And C ----------- +PyPy and C (1/2) +---------------- -* PyPy is pretty good at interacting with C code with cffi +* PyPy is pretty good at interacting with C code now, thanks to CFFI + +* CFFI is the easiest tool to I've used so far + +* Very fast on PyPy, fast enough on CPython + +* Used by NumPyPy * With CFFI you can call C code from Python and expose Python functions to C - - This means you can create your own C API in pure python ! + - This means you can create your own C API in pure Python ! + +PyPy and C (2/2) +---------------- * It is now possible to embed PyPy in a C application (uWSGI) From noreply at buildbot.pypy.org Thu Dec 4 08:13:50 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 08:13:50 +0100 (CET) Subject: [pypy-commit] pypy default: test any/all in test_zjit Message-ID: <20141204071350.BE3901C07BB@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74809:0961d3cfbdde Date: 2014-12-04 02:09 -0500 http://bitbucket.org/pypy/pypy/changeset/0961d3cfbdde/ Log: test any/all in test_zjit diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -277,21 +277,45 @@ def define_any(): return """ - a = [0,0,0,0,0,0,0,0,0,0,0] - a[8] = -12 - b = a + a - any(b) + a = [0,0,0,0,0,0,0,1,0,0,0] + any(a) """ def test_any(self): result = self.run("any") assert result == 1 - py.test.skip("don't run for now") - self.check_simple_loop({"raw_load": 2, "float_add": 1, - "int_and": 1, "int_add": 1, - 'cast_float_to_int': 1, - "int_ge": 1, "jump": 1, - "guard_false": 2, 'arraylen_gc': 1}) + self.check_trace_count(1) + self.check_simple_loop({ + 'cast_float_to_int': 1, + 'guard_false': 2, + 'guard_not_invalidated': 1, + 'int_add': 2, + 'int_and': 1, + 'int_ge': 1, + 'jump': 1, + 'raw_load': 1, + }) + + def define_all(): + return """ + a = [1,1,1,1,1,1,1,1] + all(a) + """ + + def test_all(self): + result = self.run("all") + assert result == 1 + self.check_simple_loop({ + 'cast_float_to_int': 1, + 'guard_false': 1, + 'guard_not_invalidated': 1, + 'guard_true': 1, + 'int_add': 2, + 'int_and': 1, + 'int_ge': 1, + 'jump': 1, + 'raw_load': 1, + }) def define_already_forced(): return """ From noreply at buildbot.pypy.org Thu Dec 4 08:13:52 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 08:13:52 +0100 (CET) Subject: [pypy-commit] pypy default: whitespace Message-ID: <20141204071352.09F031C07BB@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74810:092797de8785 Date: 2014-12-04 02:13 -0500 http://bitbucket.org/pypy/pypy/changeset/092797de8785/ Log: whitespace diff --git a/pypy/module/micronumpy/descriptor.py b/pypy/module/micronumpy/descriptor.py --- a/pypy/module/micronumpy/descriptor.py +++ b/pypy/module/micronumpy/descriptor.py @@ -286,7 +286,6 @@ def descr_hash(self, space): return space.wrap(self._compute_hash(space, 0x345678)) - def descr_str(self, space): if self.fields: return space.str(self.descr_get_descr(space)) diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -392,6 +392,7 @@ t5 = dtype([('x', ' Author: Romain Guillebert Branch: extradoc Changeset: r5477:b636f7bce759 Date: 2014-12-04 14:18 +0530 http://bitbucket.org/pypy/extradoc/changeset/b636f7bce759/ Log: Add new topics diff --git a/talk/scipyindia2014/talk.rst b/talk/scipyindia2014/talk.rst --- a/talk/scipyindia2014/talk.rst +++ b/talk/scipyindia2014/talk.rst @@ -96,4 +96,15 @@ * ~80% of the numpy tests are passing -* XXX +* Most of numpy is there + +* XXX is missing + +NumPyPy performance +------------------- + +PyMetabiosis +------------ + +JitPy +----- From noreply at buildbot.pypy.org Thu Dec 4 13:18:14 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 13:18:14 +0100 (CET) Subject: [pypy-commit] creflect default: clean-ups, small stuff Message-ID: <20141204121814.1F9A01C1147@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r144:aab3d6122236 Date: 2014-12-04 12:15 +0100 http://bitbucket.org/cffi/creflect/changeset/aab3d6122236/ Log: clean-ups, small stuff diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -4,7 +4,6 @@ setup( ext_modules=[ Extension(name = 'zeffir', - sources=['zeffir/zeffir.c', - 'creflect/creflect_cdecl.c'], + sources=['zeffir/zeffir.c'] ) ]) diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -99,7 +99,7 @@ static _crx_type_t *zef_get_void_type(_crx_builder_t *cb) { - return _zef_primitive(cb, -1, "void", CT_VOID | CT_IS_OPAQUE); + return _zef_primitive(cb, -1, "void", CT_VOID); } static _crx_type_t *zef_get_char_type(_crx_builder_t *cb) @@ -285,7 +285,7 @@ static _crx_type_t *zef_get_unknown_type(_crx_builder_t *cb, const char *name) { - abort(); + return _zef_primitive(cb, -1, name, CT_UNKNOWN); } static void zef_complete(_crx_builder_t *cb, _crx_type_t *t, diff --git a/zeffir/ctype.c b/zeffir/ctype.c --- a/zeffir/ctype.c +++ b/zeffir/ctype.c @@ -8,13 +8,13 @@ #define CT_ARRAY 32 /* array */ #define CT_STRUCT 64 /* struct */ #define CT_UNION 128 /* union */ -#define CT_FUNCTIONPTR 256 /* pointer to function */ +#define CT_UNKNOWN 256 /* unknown type */ #define CT_VOID 512 /* void */ /* other flags that may also be set in addition to the base flag: */ #define CT_CAST_ANYTHING 1024 /* 'char *' and 'void *' only */ #define CT_PRIMITIVE_FITS_LONG 2048 -#define CT_IS_OPAQUE 4096 +//#define CT_IS_OPAQUE 4096 /* == (ct_size < 0) */ #define CT_IS_ENUM 8192 #define CT_IS_PTR_TO_OWNED 16384 #define CT_IS_LONGDOUBLE 65536 diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -86,6 +86,8 @@ lib = lib_create(path); Py_DECREF(path); + if (lib == NULL) + return NULL; if (load_creflect_main(self, lib) < 0) { Py_DECREF(lib); @@ -108,22 +110,53 @@ return Py_None; } +static CTypeDescrObject *_ffi_type(ZefFFIObject *ffi, PyObject *arg) +{ + /* Returns the CTypeDescrObject from the user-supplied 'arg'. + Does not return a new reference! + */ + if (PyString_Check(arg)) { + PyObject *x = PyDict_GetItem(ffi->types_dict, arg); + if (x != NULL && CTypeDescr_Check(x)) + return (CTypeDescrObject *)x; + + CTypeDescrObject *ct = parse_c_decl(ffi, PyString_AS_STRING(arg)); + if (ct == NULL) + return NULL; + + x = (PyObject *)ct; + if (PyDict_SetItem(ffi->types_dict, arg, x) < 0) + ct = NULL; + Py_DECREF(x); + return ct; + } + else if (CTypeDescr_Check(arg)) { + return (CTypeDescrObject *)arg; + } + else { + PyErr_SetString(PyExc_TypeError, "expected a string or a CType object"); + return NULL; + } +} + +static PyObject *ffi_sizeof(ZefFFIObject *self, PyObject *arg) +{ + CTypeDescrObject *ct = _ffi_type(self, arg); + if (ct == NULL) + return NULL; + + return PyInt_FromSsize_t(ct->ct_size); +} + static PyObject *ffi_typeof(ZefFFIObject *self, PyObject *arg) { if (!PyString_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "XXX"); + PyErr_SetString(PyExc_TypeError, "expected a string"); return NULL; } - PyObject *x = PyDict_GetItem(self->types_dict, arg); - if (x != NULL) { - Py_INCREF(x); - return x; - } - - x = (PyObject *)parse_c_decl(self, PyString_AS_STRING(arg)); - if (x != NULL) - PyDict_SetItem(self->types_dict, arg, x); + PyObject *x = (PyObject *)_ffi_type(self, arg); + Py_XINCREF(x); return x; } @@ -131,6 +164,7 @@ {"close_library", ffi_close_library, METH_VARARGS | METH_STATIC}, {"load_library", (PyCFunction)ffi_load_library, METH_VARARGS | METH_KEYWORDS}, + {"sizeof", (PyCFunction)ffi_sizeof, METH_O}, {"typeof", (PyCFunction)ffi_typeof, METH_O}, {NULL} }; diff --git a/zeffir/test/function.crx b/zeffir/test/function.crx --- a/zeffir/test/function.crx +++ b/zeffir/test/function.crx @@ -1,11 +1,11 @@ +int simple_function(int x) +{ + return x + 1; +} + + // CREFLECT: start int simple_function(int); // CREFLECT: end - - -int simple_function(int x) -{ - return x + 1; -} diff --git a/zeffir/test/test_ctype.py b/zeffir/test/test_ctype.py --- a/zeffir/test/test_ctype.py +++ b/zeffir/test/test_ctype.py @@ -10,6 +10,8 @@ def test_typeof_char(): ffi = support.new_ffi() assert repr(ffi.typeof("char")) == "" + assert ffi.sizeof("char") == 1 + assert ffi.sizeof(ffi.typeof("char")) == 1 def test_typeof_bool(): ffi = support.new_ffi() From noreply at buildbot.pypy.org Thu Dec 4 13:18:15 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 13:18:15 +0100 (CET) Subject: [pypy-commit] creflect default: Finding the closest integer type matching the size: move that logic out Message-ID: <20141204121815.3C68B1C1147@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r145:e7243eb19cf3 Date: 2014-12-04 13:15 +0100 http://bitbucket.org/cffi/creflect/changeset/e7243eb19cf3/ Log: Finding the closest integer type matching the size: move that logic out of creflect_debug_print.c, because it is generally useful diff --git a/creflect/creflect.h b/creflect/creflect.h --- a/creflect/creflect.h +++ b/creflect/creflect.h @@ -77,8 +77,16 @@ #undef _CRX_SELF -#define _CRX_INT_TYPE(cb, expr, guessname) \ - _crx_int_type(cb, expr > 0, sizeof(expr), expr == 1, guessname) +enum { + _crx_sc_char = 1, + _crx_sc_short = 2, + _crx_sc_int = 3, + _crx_sc_long = 4, + _crx_sc_long_long = 5, +}; + +#define _CRX_INT_TYPE(cb, expr, sizeclass) \ + _crx_int_type(cb, expr > 0, sizeof(expr), expr == 1, sizeclass) #define _CRX_INT_CONST(cb, expr, vp, pn) \ _crx_int_const(cb, vp, pn, \ @@ -102,14 +110,28 @@ __attribute__((unused)) static _crx_type_t *_crx_int_type(_crx_builder_t *cb, int expr_positive, size_t size_of_expr, int expr_equal_one, - const char *guessname) + int sizeclass) { + if (size_of_expr == 1 && expr_equal_one) + return cb->get_bool_type(cb); + + static size_t all_sizes[] = { 0, sizeof(char), sizeof(short), sizeof(int), + sizeof(long), sizeof(long long), (size_t)-1 }; + while (all_sizes[sizeclass] != size_of_expr) { + if (all_sizes[sizeclass] > size_of_expr) + sizeclass--; + else + sizeclass++; + } + if (sizeclass < 1) sizeclass = 1; + if (sizeclass > 5) sizeclass = 5; + + static const char *all_names[] = { NULL, "char", "short", "int", + "long", "long long" }; if (!expr_positive) - return cb->get_signed_type(cb, size_of_expr, guessname); - else if (size_of_expr == 1 && expr_equal_one) - return cb->get_bool_type(cb); + return cb->get_signed_type(cb, size_of_expr, all_names[sizeclass]); else - return cb->get_unsigned_type(cb, size_of_expr, guessname); + return cb->get_unsigned_type(cb, size_of_expr, all_names[sizeclass]); } __attribute__((unused)) diff --git a/creflect/creflect_debug_print.c b/creflect/creflect_debug_print.c --- a/creflect/creflect_debug_print.c +++ b/creflect/creflect_debug_print.c @@ -67,63 +67,52 @@ return newtype("_Bool"); } +static void badsize(const char *g, size_t sz) +{ + printf("type '%s' has incorrect size specification: %zd\n", g, sz); + abort(); +} + static _crx_type_t *tst_get_signed_type(_crx_builder_t *cb, size_t sz, const char *g) { - int skip = 0; - if (sizeof(long) == sizeof(long long)) - if (strcmp(g, "long long") == 0) - skip = 4; - if (sizeof(int) == sizeof(long)) - if (strcmp(g, "long") == 0 || strcmp(g, "long long") == 0) - skip = 3; +#define TT(in_name, out_name) \ + if (strcmp(g, #in_name) == 0) { \ + if (sz != sizeof(out_name)) badsize(g, sz); \ + return newtype(#out_name); \ + } -#define TT(name) if (--skip && sz == sizeof(name)) { return newtype(#name); } - TT(signed char); - TT(short); - TT(int); - TT(long); - TT(long long); + TT(char, signed char) + TT(short, short) + TT(int, int) + TT(long, long) + TT(long long, long long) - printf("cannot find signed type with %zd bytes\n", sz); + printf("cannot find signed type '%s'\n", g); abort(); } static _crx_type_t *tst_get_unsigned_type(_crx_builder_t *cb, size_t sz, const char *g) { - int skip = 0; - if (sizeof(long) == sizeof(long long)) - if (strcmp(g, "long long") == 0) - skip = 4; - if (sizeof(int) == sizeof(long)) - if (strcmp(g, "long") == 0 || strcmp(g, "long long") == 0) - skip = 3; + TT(char, unsigned char) + TT(short, unsigned short) + TT(int, unsigned int) + TT(long, unsigned long) + TT(long long, unsigned long long) - TT(unsigned char); - TT(unsigned short); - TT(unsigned int); - TT(unsigned long); - TT(unsigned long long); - - printf("cannot find unsigned type with %zd bytes\n", sz); + printf("cannot find unsigned type '%s'\n", g); abort(); } static _crx_type_t *tst_get_float_type(_crx_builder_t *cb, size_t sz, const char *g) { - int skip = 0; - if (sizeof(double) == sizeof(long double)) - if (strcmp(g, "long double") == 0) - skip = 2; + TT(float, float) + TT(double, double) + TT(long double, long double) - TT(float); - TT(double); - TT(long double); -#undef TT - - printf("cannot find float type with %zd bytes\n", sz); + printf("cannot find float type '%s'\n", g); abort(); } diff --git a/creflect/model.py b/creflect/model.py --- a/creflect/model.py +++ b/creflect/model.py @@ -134,6 +134,17 @@ def is_float_type(self): return self.ALL_PRIMITIVE_TYPES[self.name] == 'f' + def get_simplified_integer_type(self): + assert self.is_integer_type() + name = self.name + if name.startswith('unsigned '): + name = name[9:] + elif name.startswith('signed '): + name = name[7:] + if name == '_Bool': + name = 'char' + return name + def inspect_type(self, block, inspect, qualifiers): if isinstance(inspect, TypeInspector): star_p1 = inspect.fetch_star_p1() @@ -157,10 +168,9 @@ if not (qualifiers & CRX_CONST): block.writeline("%s = -1;%s" % (star_p1, comment3)) if self.is_integer_type(): - hint = self.name.split() - if hint[0] in ('signed', 'unsigned'): - hint = hint[1:] - expr = '_CRX_INT_TYPE(cb, %s, "%s")' % (star_p1, " ".join(hint)) + hint = self.get_simplified_integer_type() + hint = hint.replace(' ', '_') + expr = '_CRX_INT_TYPE(cb, %s, _crx_sc_%s)' % (star_p1, hint) elif self.is_char_type(): errmsg = "numeric type '%s' is not a char" % ( inspect.get_comment_type(0, False),) @@ -189,12 +199,16 @@ inspect.varname, qualtype.get_c_name())) block.writeline("(void)p1;") - if self.is_signed_type(): + if self.name == '_Bool': + expr = 'cb->get_bool_type(cb)' + elif self.is_signed_type(): + hint = self.get_simplified_integer_type() expr = 'cb->get_signed_type(cb, sizeof(%s), "%s")' % ( - self.name, self.name) + self.name, hint) elif self.is_unsigned_type(): + hint = self.get_simplified_integer_type() expr = 'cb->get_unsigned_type(cb, sizeof(%s), "%s")' % ( - self.name, self.name) + self.name, hint) elif self.is_char_type(): expr = 'cb->get_char_type(cb)' elif self.is_float_type(): diff --git a/creflect/test/codegen/003.c b/creflect/test/codegen/003.c --- a/creflect/test/codegen/003.c +++ b/creflect/test/codegen/003.c @@ -11,7 +11,7 @@ p1 = (void *)b; (void)(*p1 << 1); /* check that 'num_t' is an integer type */ *p1 = -1; /* check that 'num_t' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, *p1, "int"); + t1 = _CRX_INT_TYPE(cb, *p1, _crx_sc_int); cb->define_type(cb, "num_t", t1, 0); #expect TYPEDEF num_t = int } diff --git a/creflect/test/codegen/003b.c b/creflect/test/codegen/003b.c --- a/creflect/test/codegen/003b.c +++ b/creflect/test/codegen/003b.c @@ -11,7 +11,7 @@ p1 = (void *)b; (void)(*p1 << 1); /* check that 'num_t' is an integer type */ *p1 = -1; /* check that 'num_t' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, *p1, "long"); + t1 = _CRX_INT_TYPE(cb, *p1, _crx_sc_long); cb->define_type(cb, "num_t", t1, 0); #expect TYPEDEF num_t = long } diff --git a/creflect/test/codegen/003c.c b/creflect/test/codegen/003c.c --- a/creflect/test/codegen/003c.c +++ b/creflect/test/codegen/003c.c @@ -11,7 +11,7 @@ p1 = (void *)b; (void)(*p1 << 1); /* check that 'num_t' is an integer type */ *p1 = -1; /* check that 'num_t' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, *p1, "long long"); + t1 = _CRX_INT_TYPE(cb, *p1, _crx_sc_long_long); cb->define_type(cb, "num_t", t1, 0); #expect TYPEDEF num_t = long long } diff --git a/creflect/test/codegen/003d.c b/creflect/test/codegen/003d.c --- a/creflect/test/codegen/003d.c +++ b/creflect/test/codegen/003d.c @@ -11,7 +11,7 @@ p1 = (void *)b; (void)(*p1 << 1); /* check that 'num_t' is an integer type */ *p1 = -1; /* check that 'num_t' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, *p1, "char"); + t1 = _CRX_INT_TYPE(cb, *p1, _crx_sc_char); cb->define_type(cb, "num_t", t1, 0); #expect TYPEDEF num_t = signed char } diff --git a/creflect/test/codegen/003f.c b/creflect/test/codegen/003f.c --- a/creflect/test/codegen/003f.c +++ b/creflect/test/codegen/003f.c @@ -11,7 +11,7 @@ p1 = (void *)b; (void)(*p1 << 1); /* check that 'num_t' is an integer type */ *p1 = -1; /* check that 'num_t' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, *p1, "long long"); + t1 = _CRX_INT_TYPE(cb, *p1, _crx_sc_long_long); cb->define_type(cb, "num_t", t1, 0); #expect TYPEDEF num_t = unsigned long long } diff --git a/creflect/test/codegen/003h.c b/creflect/test/codegen/003h.c --- a/creflect/test/codegen/003h.c +++ b/creflect/test/codegen/003h.c @@ -15,7 +15,7 @@ p1 = (void *)b; (void)(*p1 << 1); /* check that 'num_t' is an integer type */ *p1 = -1; /* check that 'num_t' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, *p1, "long long"); + t1 = _CRX_INT_TYPE(cb, *p1, _crx_sc_long_long); cb->define_type(cb, "num_t", t1, 0); #expect TYPEDEF num_t = int } diff --git a/creflect/test/codegen/003i.c b/creflect/test/codegen/003i.c --- a/creflect/test/codegen/003i.c +++ b/creflect/test/codegen/003i.c @@ -11,7 +11,7 @@ p1 = (void *)b; (void)(*p1 << 1); /* check that 'num_t' is an integer type */ *p1 = -1; /* check that 'num_t' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, *p1, "char"); + t1 = _CRX_INT_TYPE(cb, *p1, _crx_sc_char); cb->define_type(cb, "num_t", t1, 0); #expect TYPEDEF num_t = signed char } diff --git a/creflect/test/codegen/004.c b/creflect/test/codegen/004.c --- a/creflect/test/codegen/004.c +++ b/creflect/test/codegen/004.c @@ -13,7 +13,7 @@ *p1 = (void *)b; /* check that 'num_t' is a pointer type */ (void)(**p1 << 1); /* check that '*num_t' is an integer type */ **p1 = -1; /* check that '*num_t' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, **p1, "int"); + t1 = _CRX_INT_TYPE(cb, **p1, _crx_sc_int); t2 = cb->get_pointer_type(cb, t1, 0); cb->define_type(cb, "num_t", t2, 0); #expect TYPEDEF num_t = PTR int diff --git a/creflect/test/codegen/004b.c b/creflect/test/codegen/004b.c --- a/creflect/test/codegen/004b.c +++ b/creflect/test/codegen/004b.c @@ -15,7 +15,7 @@ **p1 = (void *)b; /* check that '*num_t' is a pointer type */ (void)(***p1 << 1); /* check that '**num_t' is an integer type */ ***p1 = -1; /* check that '**num_t' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, ***p1, "int"); + t1 = _CRX_INT_TYPE(cb, ***p1, _crx_sc_int); t2 = cb->get_pointer_type(cb, t1, 0); t3 = cb->get_pointer_type(cb, t2, 0); cb->define_type(cb, "num_t", t3, 0); diff --git a/creflect/test/codegen/005.c b/creflect/test/codegen/005.c --- a/creflect/test/codegen/005.c +++ b/creflect/test/codegen/005.c @@ -15,7 +15,7 @@ } (void)(**p1 << 1); /* check that 'foo_t[]' is an integer type */ **p1 = -1; /* check that 'foo_t[]' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, **p1, "int"); + t1 = _CRX_INT_TYPE(cb, **p1, _crx_sc_int); t2 = cb->get_array_type(cb, t1, sizeof(*p1) / sizeof(**p1)); cb->define_type(cb, "foo_t", t2, 0); #expect TYPEDEF foo_t = ARRAY[27] int diff --git a/creflect/test/codegen/005b.c b/creflect/test/codegen/005b.c --- a/creflect/test/codegen/005b.c +++ b/creflect/test/codegen/005b.c @@ -17,7 +17,7 @@ **p1 = (void *)b; /* check that 'foo_t[]' is a pointer type */ (void)(***p1 << 1); /* check that '*foo_t[]' is an integer type */ ***p1 = -1; /* check that '*foo_t[]' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, ***p1, "int"); + t1 = _CRX_INT_TYPE(cb, ***p1, _crx_sc_int); t2 = cb->get_pointer_type(cb, t1, 0); t3 = cb->get_array_type(cb, t2, sizeof(*p1) / sizeof(**p1)); cb->define_type(cb, "foo_t", t3, 0); diff --git a/creflect/test/codegen/005c.c b/creflect/test/codegen/005c.c --- a/creflect/test/codegen/005c.c +++ b/creflect/test/codegen/005c.c @@ -17,7 +17,7 @@ } (void)(***p1 << 1); /* check that '(*foo_t)[]' is an integer type */ ***p1 = -1; /* check that '(*foo_t)[]' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, ***p1, "int"); + t1 = _CRX_INT_TYPE(cb, ***p1, _crx_sc_int); t2 = cb->get_array_type(cb, t1, sizeof(**p1) / sizeof(***p1)); t3 = cb->get_pointer_type(cb, t2, 0); cb->define_type(cb, "foo_t", t3, 0); diff --git a/creflect/test/codegen/005d.c b/creflect/test/codegen/005d.c --- a/creflect/test/codegen/005d.c +++ b/creflect/test/codegen/005d.c @@ -37,7 +37,7 @@ *********p1 = (void *)b; /* check that '*(***foo_t[][])[][]' is a pointer type */ (void)(**********p1 << 1); /* check that '**(***foo_t[][])[][]' is an integer type */ **********p1 = -1; /* check that '**(***foo_t[][])[][]' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, **********p1, "int"); + t1 = _CRX_INT_TYPE(cb, **********p1, _crx_sc_int); t2 = cb->get_pointer_type(cb, t1, 0); t3 = cb->get_pointer_type(cb, t2, 0); t4 = cb->get_array_type(cb, t3, sizeof(*******p1) / sizeof(********p1)); diff --git a/creflect/test/codegen/006.c b/creflect/test/codegen/006.c --- a/creflect/test/codegen/006.c +++ b/creflect/test/codegen/006.c @@ -11,7 +11,7 @@ memset(b, -1, sizeof(b)); p1 = (void *)b; (void)(*p1 << 1); /* check that 'num_t' is an integer type */ - t1 = _CRX_INT_TYPE(cb, *p1, "int"); + t1 = _CRX_INT_TYPE(cb, *p1, _crx_sc_int); cb->define_type(cb, "num_t", t1, _CRX_CONST); #expect TYPEDEF num_t = CONST unsigned int } diff --git a/creflect/test/codegen/006b.c b/creflect/test/codegen/006b.c --- a/creflect/test/codegen/006b.c +++ b/creflect/test/codegen/006b.c @@ -17,7 +17,7 @@ } (void)(**p1 << 1); /* check that '*num_t' is an integer type */ **p1 = -1; /* check that '*num_t' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, **p1, "int"); + t1 = _CRX_INT_TYPE(cb, **p1, _crx_sc_int); t2 = cb->get_pointer_type(cb, t1, 0); cb->define_type(cb, "num_t", t2, _CRX_CONST); #expect TYPEDEF num_t = CONST PTR int diff --git a/creflect/test/codegen/006c.c b/creflect/test/codegen/006c.c --- a/creflect/test/codegen/006c.c +++ b/creflect/test/codegen/006c.c @@ -21,7 +21,7 @@ } (void)(***p1 << 1); /* check that '(*foo_t)[]' is an integer type */ ***p1 = -1; /* check that '(*foo_t)[]' is not declared 'const' */ - t1 = _CRX_INT_TYPE(cb, ***p1, "int"); + t1 = _CRX_INT_TYPE(cb, ***p1, _crx_sc_int); t2 = cb->get_array_type(cb, t1, sizeof(**p1) / sizeof(***p1)); t3 = cb->get_pointer_type(cb, t2, 0); cb->define_type(cb, "foo_t", t3, _CRX_CONST); diff --git a/creflect/test/codegen/func-001b.c b/creflect/test/codegen/func-001b.c --- a/creflect/test/codegen/func-001b.c +++ b/creflect/test/codegen/func-001b.c @@ -41,7 +41,7 @@ _crx_qual_type a2[2]; _crx_qual_type a3[2]; { - t1 = cb->get_unsigned_type(cb, sizeof(unsigned int), "unsigned int"); + t1 = cb->get_unsigned_type(cb, sizeof(unsigned int), "int"); t2 = cb->get_signed_type(cb, sizeof(long), "long"); a1[0].type = t2; a1[0].qualifiers = 0; diff --git a/creflect/test/codegen/struct-001.c b/creflect/test/codegen/struct-001.c --- a/creflect/test/codegen/struct-001.c +++ b/creflect/test/codegen/struct-001.c @@ -17,7 +17,7 @@ p1 = (void *)(((char *)b) - o); (void)(p1->aa << 1); /* check that 'struct foo_s::aa' is an integer type */ p1->aa = -1; /* check that 'struct foo_s::aa' is not declared 'const' */ - t2 = _CRX_INT_TYPE(cb, p1->aa, "int"); + t2 = _CRX_INT_TYPE(cb, p1->aa, _crx_sc_int); d1[0].name = "aa"; d1[0].type = t2; d1[0].qualifiers = 0; @@ -32,7 +32,7 @@ p1 = (void *)(((char *)b) - o); (void)(p1->bb << 1); /* check that 'struct foo_s::bb' is an integer type */ p1->bb = -1; /* check that 'struct foo_s::bb' is not declared 'const' */ - t3 = _CRX_INT_TYPE(cb, p1->bb, "int"); + t3 = _CRX_INT_TYPE(cb, p1->bb, _crx_sc_int); d1[1].name = "bb"; d1[1].type = t3; d1[1].qualifiers = 0; diff --git a/creflect/test/codegen/struct-001b.c b/creflect/test/codegen/struct-001b.c --- a/creflect/test/codegen/struct-001b.c +++ b/creflect/test/codegen/struct-001b.c @@ -16,7 +16,7 @@ memset(b, -1, sizeof(b)); p1 = (void *)(((char *)b) - o); (void)(p1->aa << 1); /* check that 'struct foo_s::aa' is an integer type */ - t2 = _CRX_INT_TYPE(cb, p1->aa, "int"); + t2 = _CRX_INT_TYPE(cb, p1->aa, _crx_sc_int); d1[0].name = "aa"; d1[0].type = t2; d1[0].qualifiers = _CRX_CONST; diff --git a/creflect/test/codegen/struct-003.c b/creflect/test/codegen/struct-003.c --- a/creflect/test/codegen/struct-003.c +++ b/creflect/test/codegen/struct-003.c @@ -18,7 +18,7 @@ p1->aa = (void *)b; /* check that 'struct foo_s::aa' is a pointer type */ (void)(*p1->aa << 1); /* check that '*struct foo_s::aa' is an integer type */ *p1->aa = -1; /* check that '*struct foo_s::aa' is not declared 'const' */ - t2 = _CRX_INT_TYPE(cb, *p1->aa, "int"); + t2 = _CRX_INT_TYPE(cb, *p1->aa, _crx_sc_int); t3 = cb->get_pointer_type(cb, t2, 0); d1[0].name = "aa"; d1[0].type = t3; diff --git a/creflect/test/codegen/struct-004.c b/creflect/test/codegen/struct-004.c --- a/creflect/test/codegen/struct-004.c +++ b/creflect/test/codegen/struct-004.c @@ -20,7 +20,7 @@ } (void)(*p1->aa << 1); /* check that 'struct foo_s::aa[]' is an integer type */ *p1->aa = -1; /* check that 'struct foo_s::aa[]' is not declared 'const' */ - t2 = _CRX_INT_TYPE(cb, *p1->aa, "int"); + t2 = _CRX_INT_TYPE(cb, *p1->aa, _crx_sc_int); t3 = cb->get_array_type(cb, t2, sizeof(p1->aa) / sizeof(*p1->aa)); d1[0].name = "aa"; d1[0].type = t3; diff --git a/creflect/test/codegen/struct-005.c b/creflect/test/codegen/struct-005.c --- a/creflect/test/codegen/struct-005.c +++ b/creflect/test/codegen/struct-005.c @@ -14,7 +14,7 @@ p1 = (void *)(((char *)b) - o); (void)(p1->aa << 1); /* check that 'foo_t::aa' is an integer type */ p1->aa = -1; /* check that 'foo_t::aa' is not declared 'const' */ - t2 = _CRX_INT_TYPE(cb, p1->aa, "int"); + t2 = _CRX_INT_TYPE(cb, p1->aa, _crx_sc_int); d1[0].name = "aa"; d1[0].type = t2; d1[0].qualifiers = 0; diff --git a/creflect/test/codegen/struct-005b.c b/creflect/test/codegen/struct-005b.c --- a/creflect/test/codegen/struct-005b.c +++ b/creflect/test/codegen/struct-005b.c @@ -14,7 +14,7 @@ p1 = (void *)(((char *)b) - o); (void)(p1->aa << 1); /* check that '*foo_p::aa' is an integer type */ p1->aa = -1; /* check that '*foo_p::aa' is not declared 'const' */ - t2 = _CRX_INT_TYPE(cb, p1->aa, "int"); + t2 = _CRX_INT_TYPE(cb, p1->aa, _crx_sc_int); d1[0].name = "aa"; d1[0].type = t2; d1[0].qualifiers = 0; From noreply at buildbot.pypy.org Thu Dec 4 13:18:16 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 13:18:16 +0100 (CET) Subject: [pypy-commit] creflect default: type definitions Message-ID: <20141204121816.4F5DC1C1147@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r146:910d0436c9ff Date: 2014-12-04 13:18 +0100 http://bitbucket.org/cffi/creflect/changeset/910d0436c9ff/ Log: type definitions diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -20,9 +20,6 @@ PyObject *result; char *p; - if (PyErr_Occurred()) - return NULL; - base_name_len = (ct != NULL ? strlen(ct->ct_name) : 0); extra_name_len = strlen(extra_text); result = PyString_FromStringAndSize(NULL, base_name_len + extra_name_len); @@ -72,6 +69,9 @@ static _crx_type_t *_zef_primitive(_crx_builder_t *cb, Py_ssize_t size, const char *name, int flags) { + if (PyErr_Occurred()) + return NULL; + PyObject *name_obj; CTypeDescrObject *ct; @@ -165,6 +165,9 @@ static _crx_type_t *zef_get_pointer_type(_crx_builder_t *cb, _crx_type_t *totype, int toquals) { + if (PyErr_Occurred()) + return NULL; + const char *extra; PyObject *name_obj; CTypeDescrObject *ct; @@ -205,6 +208,9 @@ static _crx_type_t *zef_get_array_type(_crx_builder_t *cb, _crx_type_t *ctitem, size_t len) { + if (PyErr_Occurred()) + return NULL; + CTypeDescrObject *ct; PyObject *name_obj; char extra_text[32]; @@ -304,7 +310,11 @@ static void zef_define_type(_crx_builder_t *cb, const char *name, _crx_type_t *type, int quals) { - abort(); + if (PyErr_Occurred()) + return; + + PyObject *types_dict = ((zeffir_builder_t *)cb)->types_dict; + PyDict_SetItemString(types_dict, name, (PyObject *)type); } static void zef_define_var(_crx_builder_t *cb, const char *name, @@ -317,6 +327,9 @@ _crx_type_t *ret, _crx_qual_type args[], int nargs, _crx_trampoline0_fn trampl, void *directcall) { + if (PyErr_Occurred()) + return; + PyObject *l_dict = ((zeffir_builder_t *)cb)->l_dict; PyObject *l_libname_obj = ((zeffir_builder_t *)cb)->lib->l_libname_obj; @@ -333,6 +346,9 @@ static void zef_define_num_const(_crx_builder_t *cb, const char *name, _crx_type_t *ct, _crx_num_const_t *value) { + if (PyErr_Occurred()) + return; + PyObject *l_dict = ((zeffir_builder_t *)cb)->l_dict; assert(ct->ct_flags & CT_PRIMITIVE_ANY); diff --git a/zeffir/test/ctype.crx b/zeffir/test/ctype.crx new file mode 100644 --- /dev/null +++ b/zeffir/test/ctype.crx @@ -0,0 +1,9 @@ +typedef long long foo_t; + + + +// CREFLECT: start + +typedef int foo_t; + +// CREFLECT: end diff --git a/zeffir/test/test_ctype.py b/zeffir/test/test_ctype.py --- a/zeffir/test/test_ctype.py +++ b/zeffir/test/test_ctype.py @@ -65,3 +65,11 @@ assert repr(ffi.typeof("int [ ]")) == "" assert repr(ffi.typeof("int * [ ]")) == "" assert repr(ffi.typeof("int ( * ) [ ]")) == "" + +def test_simple_typedef(): + ffi, lib = support.compile_and_open('ctype') + assert ffi.sizeof("foo_t") == ffi.sizeof("long long") + if ffi.sizeof("long") == ffi.sizeof("long long"): + assert repr(ffi.typeof("foo_t")) == "" + else: + assert repr(ffi.typeof("foo_t")) == "" From noreply at buildbot.pypy.org Thu Dec 4 13:21:50 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 13:21:50 +0100 (CET) Subject: [pypy-commit] creflect default: a test Message-ID: <20141204122150.58F581C1147@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r147:6b080d10e199 Date: 2014-12-04 13:22 +0100 http://bitbucket.org/cffi/creflect/changeset/6b080d10e199/ Log: a test diff --git a/creflect/test/codegen/003j.c b/creflect/test/codegen/003j.c new file mode 100644 --- /dev/null +++ b/creflect/test/codegen/003j.c @@ -0,0 +1,18 @@ +typedef _Bool num_t; + +# ____________________________________________________________ + +void test003j(_crx_builder_t *cb) +{ + _crx_type_t *t1; + { + num_t *p1; + char b[sizeof(*p1)]; + p1 = (void *)b; + (void)(*p1 << 1); /* check that 'num_t' is an integer type */ + *p1 = -1; /* check that 'num_t' is not declared 'const' */ + t1 = _CRX_INT_TYPE(cb, *p1, _crx_sc_char); + cb->define_type(cb, "num_t", t1, 0); +#expect TYPEDEF num_t = _Bool + } +} From noreply at buildbot.pypy.org Thu Dec 4 13:28:21 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 13:28:21 +0100 (CET) Subject: [pypy-commit] creflect default: guess the float types, like we do the integer types Message-ID: <20141204122821.B57111C1147@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r148:3471b7c2e683 Date: 2014-12-04 13:28 +0100 http://bitbucket.org/cffi/creflect/changeset/3471b7c2e683/ Log: guess the float types, like we do the integer types diff --git a/creflect/creflect.h b/creflect/creflect.h --- a/creflect/creflect.h +++ b/creflect/creflect.h @@ -83,13 +83,20 @@ _crx_sc_int = 3, _crx_sc_long = 4, _crx_sc_long_long = 5, + + _crx_sc_float = 1, + _crx_sc_double = 2, + _crx_sc_long_double = 3, }; #define _CRX_INT_TYPE(cb, expr, sizeclass) \ _crx_int_type(cb, expr > 0, sizeof(expr), expr == 1, sizeclass) -#define _CRX_INT_CONST(cb, expr, vp, pn) \ - _crx_int_const(cb, vp, pn, \ +#define _CRX_FLOAT_TYPE(cb, expr, sizeclass) \ + _crx_float_type(cb, sizeof(expr), sizeclass) + +#define _CRX_INT_CONST(cb, expr, vp, pn) \ + _crx_int_const(cb, vp, pn, \ "integer constant '" #expr "' is too large", \ !(((expr) * 0 + 4) << (sizeof(int)*8-2)), \ !(((expr) * 0L + 4L) << (sizeof(long)*8-2)), \ @@ -98,9 +105,9 @@ (expr) == (long long)(expr), \ (unsigned long long)(expr)) -#define _CRX_CHAR_CONST(cb, expr, vp) \ - _crx_char_const(cb, vp, \ - "char constant '" #expr "' is too large", \ +#define _CRX_CHAR_CONST(cb, expr, vp) \ + _crx_char_const(cb, vp, \ + "char constant '" #expr "' is too large", \ (expr) == (signed char)(expr) || (expr) == (unsigned char)(expr), \ (char)(expr)) @@ -135,6 +142,25 @@ } __attribute__((unused)) +static _crx_type_t *_crx_float_type(_crx_builder_t *cb, size_t size_of_expr, + int sizeclass) +{ + static size_t all_sizes[] = { 0, sizeof(float), sizeof(double), + sizeof(long double), (size_t)-1 }; + while (all_sizes[sizeclass] != size_of_expr) { + if (all_sizes[sizeclass] > size_of_expr) + sizeclass--; + else + sizeclass++; + } + if (sizeclass < 1) sizeclass = 1; + if (sizeclass > 3) sizeclass = 3; + + static const char *all_names[] = { NULL, "float", "double", "long double" }; + return cb->get_float_type(cb, size_of_expr, all_names[sizeclass]); +} + +__attribute__((unused)) static _crx_type_t *_crx_int_const(_crx_builder_t *cb, _crx_num_const_t *vp, int preference_number, const char *toobig, diff --git a/creflect/model.py b/creflect/model.py --- a/creflect/model.py +++ b/creflect/model.py @@ -186,8 +186,8 @@ block.writeline(' cb->error(cb, "%s");' % (errmsg,)) block.writeline(" return;") block.writeline("}") - expr = 'cb->get_float_type(cb, sizeof(%s), "%s")' % ( - star_p1, self.name) + hint = self.name.replace(' ', '_') + expr = '_CRX_FLOAT_TYPE(cb, %s, _crx_sc_%s)' % (star_p1, hint) else: raise AssertionError else: diff --git a/creflect/test/codegen/003g.c b/creflect/test/codegen/003g.c --- a/creflect/test/codegen/003g.c +++ b/creflect/test/codegen/003g.c @@ -16,7 +16,7 @@ cb->error(cb, "numeric type 'num_t' is an integer, not a float"); return; } - t1 = cb->get_float_type(cb, sizeof(*p1), "double"); + t1 = _CRX_FLOAT_TYPE(cb, *p1, _crx_sc_double); cb->define_type(cb, "num_t", t1, 0); #expect TYPEDEF num_t = double } diff --git a/creflect/test/codegen/003k.c b/creflect/test/codegen/003k.c new file mode 100644 --- /dev/null +++ b/creflect/test/codegen/003k.c @@ -0,0 +1,27 @@ +typedef double num_t; + +# ____________________________________________________________ + +#define num_t float + +# ____________________________________________________________ + +void test003k(_crx_builder_t *cb) +{ + _crx_type_t *t1; + { + num_t *p1; + char b[sizeof(*p1)]; + memset(b, 0, sizeof(b)); + p1 = (void *)b; + (void)(*p1 / 2.0); /* check that 'num_t' is a numeric type */ + *p1 = -1; /* check that 'num_t' is not declared 'const' */ + if ((1 + *p1 * 0) / 2 == 0) { + cb->error(cb, "numeric type 'num_t' is an integer, not a float"); + return; + } + t1 = _CRX_FLOAT_TYPE(cb, *p1, _crx_sc_double); + cb->define_type(cb, "num_t", t1, 0); +#expect TYPEDEF num_t = float + } +} From noreply at buildbot.pypy.org Thu Dec 4 13:30:59 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 13:30:59 +0100 (CET) Subject: [pypy-commit] creflect default: add passing tests Message-ID: <20141204123059.1DA911C1147@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r149:bee544ef3a06 Date: 2014-12-04 13:31 +0100 http://bitbucket.org/cffi/creflect/changeset/bee544ef3a06/ Log: add passing tests diff --git a/zeffir/test/ctype.crx b/zeffir/test/ctype.crx --- a/zeffir/test/ctype.crx +++ b/zeffir/test/ctype.crx @@ -1,9 +1,14 @@ typedef long long foo_t; - +typedef char rfoo_t; +typedef long double bar_t; +typedef float rbar_t; // CREFLECT: start typedef int foo_t; +typedef long long rfoo_t; +typedef float bar_t; +typedef long double rbar_t; // CREFLECT: end diff --git a/zeffir/test/test_ctype.py b/zeffir/test/test_ctype.py --- a/zeffir/test/test_ctype.py +++ b/zeffir/test/test_ctype.py @@ -73,3 +73,15 @@ assert repr(ffi.typeof("foo_t")) == "" else: assert repr(ffi.typeof("foo_t")) == "" + # + assert ffi.sizeof("rfoo_t") == ffi.sizeof("char") + assert repr(ffi.typeof("rfoo_t")) == "" + # + assert ffi.sizeof("bar_t") == ffi.sizeof("long double") + if ffi.sizeof("long double") == ffi.sizeof("double"): + assert repr(ffi.typeof("bar_t")) == "" + else: + assert repr(ffi.typeof("bar_t")) == "" + # + assert ffi.sizeof("rbar_t") == ffi.sizeof("float") + assert repr(ffi.typeof("rbar_t")) == "" From noreply at buildbot.pypy.org Thu Dec 4 19:12:48 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 19:12:48 +0100 (CET) Subject: [pypy-commit] creflect default: unknown types Message-ID: <20141204181248.EA8261C07BB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r150:121223620cdd Date: 2014-12-04 16:08 +0100 http://bitbucket.org/cffi/creflect/changeset/121223620cdd/ Log: unknown types diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -134,7 +134,7 @@ return (CTypeDescrObject *)arg; } else { - PyErr_SetString(PyExc_TypeError, "expected a string or a CType object"); + PyErr_SetString(PyExc_TypeError, "expected a string or a ctype object"); return NULL; } } @@ -145,6 +145,11 @@ if (ct == NULL) return NULL; + if (ct->ct_size < 0) { + PyErr_Format(PyExc_ValueError, "don't know the size of ctype '%s': " + "incomplete type", ct->ct_name); + return NULL; + } return PyInt_FromSsize_t(ct->ct_size); } diff --git a/zeffir/test/ctype.crx b/zeffir/test/ctype.crx --- a/zeffir/test/ctype.crx +++ b/zeffir/test/ctype.crx @@ -11,4 +11,6 @@ typedef float bar_t; typedef long double rbar_t; +typedef ... unknown_t; + // CREFLECT: end diff --git a/zeffir/test/test_ctype.py b/zeffir/test/test_ctype.py --- a/zeffir/test/test_ctype.py +++ b/zeffir/test/test_ctype.py @@ -1,3 +1,4 @@ +import py import support @@ -85,3 +86,8 @@ # assert ffi.sizeof("rbar_t") == ffi.sizeof("float") assert repr(ffi.typeof("rbar_t")) == "" + +def test_unknown_type(): + ffi, lib = support.compile_and_open('ctype') + assert repr(ffi.typeof("unknown_t")) == "" + py.test.raises(ValueError, ffi.sizeof, "unknown_t") From noreply at buildbot.pypy.org Thu Dec 4 19:12:50 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 19:12:50 +0100 (CET) Subject: [pypy-commit] creflect default: progress Message-ID: <20141204181250.4E04B1C07BB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r151:558efbc52db3 Date: 2014-12-04 17:49 +0100 http://bitbucket.org/cffi/creflect/changeset/558efbc52db3/ Log: progress diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -286,7 +286,20 @@ static _crx_qual_type zef_get_user_type(_crx_builder_t *cb, const char *name) { - abort(); + PyObject *name_obj; + _crx_qual_type result = { NULL, 0 }; + + if (PyErr_Occurred()) + return result; + + name_obj = combine_type_name(cb, NULL, name); + if (name_obj == NULL) + return result; + + result.type = get_cached_type(cb, name_obj); + if (result.type == NULL) + PyErr_Format(ZefError, "undefined type: '%s'", name); + return result; } static _crx_type_t *zef_get_unknown_type(_crx_builder_t *cb, const char *name) @@ -363,7 +376,8 @@ static void zef_error(_crx_builder_t *cb, const char *msg) { - abort(); + if (!PyErr_Occurred()) + PyErr_SetString(ZefError, msg); } static int load_creflect_main(ZefFFIObject *ffi, ZefLibObject *lib) @@ -463,6 +477,25 @@ _crx_qual_type result; const char *err = creflect_decl_parser(&builder.cb, str, &result); + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(ZefError)) { + PyObject *exc, *val, *tb, *ps; + PyErr_Fetch(&exc, &val, &tb); + ps = PyObject_Str(val); + if (ps != NULL && PyString_Check(ps)) { + PyErr_Format(exc, "at pos %zd: %s", + (size_t)(err - str), PyString_AS_STRING(ps)); + Py_XDECREF(tb); + Py_XDECREF(val); + Py_XDECREF(exc); + } + else { + PyErr_Restore(exc, val, tb); + } + Py_XDECREF(ps); + } + return NULL; + } if (err != NULL) abort(); diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -146,7 +146,7 @@ return NULL; if (ct->ct_size < 0) { - PyErr_Format(PyExc_ValueError, "don't know the size of ctype '%s': " + PyErr_Format(ZefError, "don't know the size of ctype '%s': " "incomplete type", ct->ct_name); return NULL; } diff --git a/zeffir/test/test_ctype.py b/zeffir/test/test_ctype.py --- a/zeffir/test/test_ctype.py +++ b/zeffir/test/test_ctype.py @@ -90,4 +90,15 @@ def test_unknown_type(): ffi, lib = support.compile_and_open('ctype') assert repr(ffi.typeof("unknown_t")) == "" - py.test.raises(ValueError, ffi.sizeof, "unknown_t") + py.test.raises(ffi.error, ffi.sizeof, "unknown_t") + py.test.raises(ffi.error, ffi.sizeof, " unknown_t ") + assert ffi.sizeof("unknown_t*") == ffi.sizeof("void *") + +def test_undefined_type(): + ffi = support.new_ffi() + py.test.raises(ffi.error, ffi.typeof, "abcdef_missing_t") + +def test_parse_error(): + ffi = support.new_ffi() + e = py.test.raises(ffi.error, ffi.typeof, "int int") + assert str(e.value) == "at pos 4: unexpected symbol" diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c --- a/zeffir/zeffir.c +++ b/zeffir/zeffir.c @@ -53,4 +53,7 @@ Py_INCREF(ZefError); if (PyModule_AddObject(m, "error", ZefError) < 0) return; + + if (PyDict_SetItemString(ZefFFI_Type.tp_dict, "error", ZefError) < 0) + return; } From noreply at buildbot.pypy.org Thu Dec 4 19:14:50 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 19:14:50 +0100 (CET) Subject: [pypy-commit] pypy default: enable axissum test_zjit Message-ID: <20141204181450.09D5C1C07BB@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74811:39760476cedc Date: 2014-12-04 12:16 -0500 http://bitbucket.org/pypy/pypy/changeset/39760476cedc/ Log: enable axissum test_zjit diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -188,18 +188,48 @@ def test_axissum(self): result = self.run("axissum") assert result == 30 - py.test.skip("don't run for now") # XXX note - the bridge here is fairly crucial and yet it's pretty # bogus. We need to improve the situation somehow. - self.check_simple_loop({'raw_load': 2, - 'raw_store': 1, - 'arraylen_gc': 2, - 'guard_true': 1, - 'int_lt': 1, - 'jump': 1, - 'float_add': 1, - 'int_add': 3, - }) + self.check_trace_count(2) + self.check_simple_loop({ + 'float_add': 1, + 'getarrayitem_gc': 2, + 'guard_false': 2, + 'guard_not_invalidated': 1, + 'guard_true': 1, + 'int_add': 5, + 'int_ge': 1, + 'int_is_zero': 1, + 'int_lt': 1, + 'jump': 1, + 'raw_load': 2, + 'raw_store': 1, + 'setarrayitem_gc': 1, + }) + self.check_resops({ + 'float_add': 2, + 'getarrayitem_gc': 5, + 'getarrayitem_gc_pure': 7, + 'getfield_gc_pure': 56, + 'guard_class': 3, + 'guard_false': 11, + 'guard_nonnull': 8, + 'guard_nonnull_class': 3, + 'guard_not_invalidated': 2, + 'guard_true': 12, + 'guard_value': 4, + 'int_add': 17, + 'int_ge': 4, + 'int_is_true': 4, + 'int_is_zero': 4, + 'int_le': 2, + 'int_lt': 3, + 'int_sub': 1, + 'jump': 2, + 'raw_load': 4, + 'raw_store': 2, + 'setarrayitem_gc': 4, + }) def define_reduce(): return """ From noreply at buildbot.pypy.org Thu Dec 4 19:14:51 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 19:14:51 +0100 (CET) Subject: [pypy-commit] pypy default: avoid tracking an iterator index in axis_reduce Message-ID: <20141204181451.4FF6F1C07BB@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74812:e9c67f6fba33 Date: 2014-12-04 12:23 -0500 http://bitbucket.org/pypy/pypy/changeset/e9c67f6fba33/ Log: avoid tracking an iterator index in axis_reduce diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -239,10 +239,9 @@ state = x_state return out -axis_reduce__driver = jit.JitDriver(name='numpy_axis_reduce', - greens=['shapelen', - 'func', 'dtype'], - reds='auto') +axis_reduce_driver = jit.JitDriver(name='numpy_axis_reduce', + greens=['shapelen', 'func', 'dtype'], + reds='auto') def do_axis_reduce(space, shape, func, arr, dtype, axis, out, identity, cumulative, temp): @@ -255,14 +254,16 @@ temp_iter = out_iter # hack temp_state = out_state arr_iter, arr_state = arr.create_iter() + arr_iter.track_index = False if identity is not None: identity = identity.convert_to(space, dtype) shapelen = len(shape) while not out_iter.done(out_state): - axis_reduce__driver.jit_merge_point(shapelen=shapelen, func=func, - dtype=dtype) - assert not arr_iter.done(arr_state) + axis_reduce_driver.jit_merge_point(shapelen=shapelen, func=func, + dtype=dtype) w_val = arr_iter.getitem(arr_state).convert_to(space, dtype) + arr_state = arr_iter.next(arr_state) + out_indices = out_iter.indices(out_state) if out_indices[axis] == 0: if identity is not None: @@ -270,6 +271,7 @@ else: cur = temp_iter.getitem(temp_state) w_val = func(dtype, cur, w_val) + out_iter.setitem(out_state, w_val) out_state = out_iter.next(out_state) if cumulative: @@ -277,7 +279,6 @@ temp_state = temp_iter.next(temp_state) else: temp_state = out_state - arr_state = arr_iter.next(arr_state) return out diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -197,7 +197,7 @@ 'guard_false': 2, 'guard_not_invalidated': 1, 'guard_true': 1, - 'int_add': 5, + 'int_add': 4, 'int_ge': 1, 'int_is_zero': 1, 'int_lt': 1, @@ -212,13 +212,13 @@ 'getarrayitem_gc_pure': 7, 'getfield_gc_pure': 56, 'guard_class': 3, - 'guard_false': 11, - 'guard_nonnull': 8, + 'guard_false': 12, + 'guard_nonnull': 11, 'guard_nonnull_class': 3, 'guard_not_invalidated': 2, - 'guard_true': 12, - 'guard_value': 4, - 'int_add': 17, + 'guard_true': 10, + 'guard_value': 5, + 'int_add': 13, 'int_ge': 4, 'int_is_true': 4, 'int_is_zero': 4, From noreply at buildbot.pypy.org Thu Dec 4 19:14:52 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 19:14:52 +0100 (CET) Subject: [pypy-commit] pypy default: enable sum/prod test_zjits Message-ID: <20141204181452.7D5081C07BB@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74813:624d6b4b60ce Date: 2014-12-04 12:31 -0500 http://bitbucket.org/pypy/pypy/changeset/624d6b4b60ce/ Log: enable sum/prod test_zjits diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -166,17 +166,22 @@ def define_sum(): return """ a = |30| - b = a + a - sum(b) + sum(a) """ def test_sum(self): result = self.run("sum") - assert result == 2 * sum(range(30)) - py.test.skip("don't run for now") - self.check_simple_loop({"raw_load": 2, "float_add": 2, - "int_add": 1, "int_ge": 1, "guard_false": 1, - "jump": 1, 'arraylen_gc': 1}) + assert result == sum(range(30)) + self.check_trace_count(1) + self.check_simple_loop({ + 'float_add': 1, + 'guard_false': 1, + 'guard_not_invalidated': 1, + 'int_add': 2, + 'int_ge': 1, + 'jump': 1, + 'raw_load': 1, + }) def define_axissum(): return """ @@ -260,8 +265,7 @@ def define_prod(): return """ a = |30| - b = a + a - prod(b) + prod(a) """ def test_prod(self): @@ -270,11 +274,16 @@ for i in range(30): expected *= i * 2 assert result == expected - py.test.skip("don't run for now") - self.check_simple_loop({"raw_load": 2, "float_add": 1, - "float_mul": 1, "int_add": 1, - "int_ge": 1, "guard_false": 1, "jump": 1, - 'arraylen_gc': 1}) + self.check_trace_count(1) + self.check_simple_loop({ + 'float_mul': 1, + 'guard_false': 1, + 'guard_not_invalidated': 1, + 'int_add': 2, + 'int_ge': 1, + 'jump': 1, + 'raw_load': 1, + }) def define_max(): return """ From noreply at buildbot.pypy.org Thu Dec 4 19:14:53 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 19:14:53 +0100 (CET) Subject: [pypy-commit] pypy default: enable min/max in test_zjit Message-ID: <20141204181453.C7BE61C07BB@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74814:ac1f001ff1c0 Date: 2014-12-04 13:13 -0500 http://bitbucket.org/pypy/pypy/changeset/ac1f001ff1c0/ Log: enable min/max in test_zjit diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -289,30 +289,62 @@ return """ a = |30| a[13] = 128 - b = a + a - max(b) + max(a) """ def test_max(self): result = self.run("max") - assert result == 256 - py.test.skip("not there yet, getting though") - self.check_simple_loop({"raw_load": 2, "float_add": 1, - "float_mul": 1, "int_add": 1, - "int_lt": 1, "guard_true": 1, "jump": 1}) + assert result == 128 + self.check_trace_count(3) + self.check_simple_loop({ + 'float_ge': 1, + 'float_ne': 1, + 'guard_false': 3, + 'guard_not_invalidated': 1, + 'int_add': 2, + 'int_ge': 1, + 'jump': 1, + 'raw_load': 1, + }) + self.check_resops({ + 'float_ge': 2, + 'float_ne': 2, + 'getfield_gc_pure': 34, + 'guard_class': 1, + 'guard_false': 8, + 'guard_nonnull': 2, + 'guard_nonnull_class': 2, + 'guard_not_invalidated': 2, + 'guard_true': 7, + 'guard_value': 2, + 'int_add': 8, + 'int_ge': 4, + 'int_is_true': 3, + 'jump': 3, + 'raw_load': 2, + }) + + def define_min(): + return """ + a = |30| + a[13] = -128 + min(a) + """ def test_min(self): - py.test.skip("broken, investigate") - result = self.run(""" - a = |30| - a[15] = -12 - b = a + a - min(b) - """) - assert result == -24 - self.check_simple_loop({"raw_load": 2, "float_add": 1, - "float_mul": 1, "int_add": 1, - "int_lt": 1, "guard_true": 1, "jump": 1}) + result = self.run("min") + assert result == -128 + self.check_trace_count(1) + self.check_simple_loop({ + 'float_le': 1, + 'guard_false': 1, + 'guard_not_invalidated': 1, + 'guard_true': 1, + 'int_add': 2, + 'int_ge': 1, + 'jump': 1, + 'raw_load': 1, + }) def define_any(): return """ From noreply at buildbot.pypy.org Thu Dec 4 19:21:49 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 19:21:49 +0100 (CET) Subject: [pypy-commit] cffi default: Merged in podshumok/cffi/podshumok/add-source_extnsion-param-to-verifier-1417477338819 (pull request #54) Message-ID: <20141204182149.AC7F41C100F@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1584:c5c87b3b1c00 Date: 2014-12-04 19:22 +0100 http://bitbucket.org/cffi/cffi/changeset/c5c87b3b1c00/ Log: Merged in podshumok/cffi/podshumok/add-source_extnsion-param-to- verifier-1417477338819 (pull request #54) add source_extnsion param to Verifier diff --git a/cffi/verifier.py b/cffi/verifier.py --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -16,7 +16,8 @@ class Verifier(object): def __init__(self, ffi, preamble, tmpdir=None, modulename=None, - ext_package=None, tag='', force_generic_engine=False, **kwds): + ext_package=None, tag='', force_generic_engine=False, + source_extension='.c', **kwds): self.ffi = ffi self.preamble = preamble if not modulename: @@ -43,7 +44,7 @@ k1, k2) suffix = _get_so_suffixes()[0] self.tmpdir = tmpdir or os.environ.get('CFFI_TMPDIR') or _caller_dir_pycache() - self.sourcefilename = os.path.join(self.tmpdir, modulename + '.c') + self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension) self.modulefilename = os.path.join(self.tmpdir, modulename + suffix) self.ext_package = ext_package self._has_source = False From noreply at buildbot.pypy.org Thu Dec 4 19:22:20 2014 From: noreply at buildbot.pypy.org (podshumok) Date: Thu, 4 Dec 2014 19:22:20 +0100 (CET) Subject: [pypy-commit] cffi podshumok/add-source_extnsion-param-to-verifier-1417477338819: add source_extnsion param to Verifier Message-ID: <20141204182220.629E71C100F@cobra.cs.uni-duesseldorf.de> Author: podshumok Branch: podshumok/add-source_extnsion-param-to-verifier-1417477338819 Changeset: r1583:d82365905c32 Date: 2014-12-01 23:42 +0000 http://bitbucket.org/cffi/cffi/changeset/d82365905c32/ Log: add source_extnsion param to Verifier diff --git a/cffi/verifier.py b/cffi/verifier.py --- a/cffi/verifier.py +++ b/cffi/verifier.py @@ -16,7 +16,8 @@ class Verifier(object): def __init__(self, ffi, preamble, tmpdir=None, modulename=None, - ext_package=None, tag='', force_generic_engine=False, **kwds): + ext_package=None, tag='', force_generic_engine=False, + source_extension='.c', **kwds): self.ffi = ffi self.preamble = preamble if not modulename: @@ -43,7 +44,7 @@ k1, k2) suffix = _get_so_suffixes()[0] self.tmpdir = tmpdir or os.environ.get('CFFI_TMPDIR') or _caller_dir_pycache() - self.sourcefilename = os.path.join(self.tmpdir, modulename + '.c') + self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension) self.modulefilename = os.path.join(self.tmpdir, modulename + suffix) self.ext_package = ext_package self._has_source = False From noreply at buildbot.pypy.org Thu Dec 4 19:27:09 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 19:27:09 +0100 (CET) Subject: [pypy-commit] cffi default: Document c5c87b3b1c00 Message-ID: <20141204182709.DE1B31D3605@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1585:2b86c5dc1331 Date: 2014-12-04 19:27 +0100 http://bitbucket.org/cffi/cffi/changeset/2b86c5dc1331/ Log: Document c5c87b3b1c00 diff --git a/doc/source/index.rst b/doc/source/index.rst --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -667,6 +667,15 @@ check. Be sure to have other means of clearing the ``tmpdir`` whenever you change your sources. +.. versionadded:: 0.8.7 + You can give C++ source code in ``ffi.verify()``:: + + ext = ffi.verify(r''' + extern "C" { + int somefunc(int somearg) { return real_cpp_func(somearg); } + } + ''', source_extension='.cpp', extra_compile_args=['-std=c++11']) + This function returns a "library" object that gets closed when it goes out of scope. Make sure you keep the library object around as long as needed. From noreply at buildbot.pypy.org Thu Dec 4 22:41:23 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 22:41:23 +0100 (CET) Subject: [pypy-commit] pypy default: add test_pypy_c for flatiter next Message-ID: <20141204214123.8DAAE1D28F0@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74815:d62d6a8c4809 Date: 2014-12-04 15:00 -0500 http://bitbucket.org/pypy/pypy/changeset/d62d6a8c4809/ Log: add test_pypy_c for flatiter next diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -78,6 +78,46 @@ jump(p0, p1, p3, p6, p7, p12, p14, f86, p18, i87, i62, p41, i58, p47, i40, i64, i70, descr=...) """) + def test_array_flatiter_next(self): + def main(): + import _numpypy.multiarray as np + arr = np.zeros((1024, 16)) + 42 + ai = arr.flat + i = 0 + while i < arr.size: + a = next(ai) + i += 1 + return a + log = self.run(main, []) + assert log.result == 42.0 + loop, = log.loops_by_filename(self.filepath) + assert loop.match(""" + i86 = int_lt(i79, i45) + guard_true(i86, descr=...) + guard_not_invalidated(descr=...) + i87 = getfield_gc_pure(p85, descr=) + i88 = int_ge(i87, i59) + guard_false(i88, descr=...) + i89 = getfield_gc_pure(p85, descr=) + f90 = raw_load(i67, i89, descr=) + i91 = int_add(i87, 1) + p92 = getfield_gc_pure(p85, descr=) + i93 = int_add(i89, i76) + i94 = int_add(i79, 1) + i95 = getfield_raw(#, descr=) + i96 = int_lt(i95, 0) + guard_false(i96, descr=...) + p97 = new_with_vtable(#) + {{{ + setfield_gc(p97, p56, descr=) + setfield_gc(p97, p92, descr=) + setfield_gc(p97, i91, descr=) + setfield_gc(p97, i93, descr=) + setfield_gc(p16, p97, descr=) + }}} + jump(p0, p1, p3, p6, p12, p14, p16, i94, f90, p26, i45, p97, i59, p56, i67, i76, descr=...) + """) + def test_array_flatiter_getitem_single(self): def main(): import _numpypy.multiarray as np From noreply at buildbot.pypy.org Thu Dec 4 22:41:24 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 22:41:24 +0100 (CET) Subject: [pypy-commit] pypy default: support mutate flag to iterator next/reset Message-ID: <20141204214124.D6D6D1D28F0@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74816:e920a686f245 Date: 2014-12-04 14:32 -0500 http://bitbucket.org/pypy/pypy/changeset/e920a686f245/ Log: support mutate flag to iterator next/reset diff --git a/pypy/module/micronumpy/iterators.py b/pypy/module/micronumpy/iterators.py --- a/pypy/module/micronumpy/iterators.py +++ b/pypy/module/micronumpy/iterators.py @@ -77,7 +77,7 @@ class IterState(object): - _immutable_fields_ = ['iterator', 'index', '_indices', 'offset'] + _immutable_fields_ = ['iterator', '_indices'] def __init__(self, iterator, index, indices, offset): self.iterator = iterator @@ -117,7 +117,8 @@ self.factors = factors @jit.unroll_safe - def reset(self, state=None): + def reset(self, state=None, mutate=False): + index = 0 if state is None: indices = [0] * len(self.shape_m1) else: @@ -125,10 +126,14 @@ indices = state._indices for i in xrange(self.ndim_m1, -1, -1): indices[i] = 0 - return IterState(self, 0, indices, self.array.start) + offset = self.array.start + if not mutate: + return IterState(self, index, indices, offset) + state.index = index + state.offset = offset @jit.unroll_safe - def next(self, state): + def next(self, state, mutate=False): assert state.iterator is self index = state.index if self.track_index: @@ -149,7 +154,10 @@ else: indices[i] = 0 offset -= self.backstrides[i] - return IterState(self, index, indices, offset) + if not mutate: + return IterState(self, index, indices, offset) + state.index = index + state.offset = offset @jit.unroll_safe def goto(self, index): diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -215,7 +215,8 @@ 'float_add': 2, 'getarrayitem_gc': 5, 'getarrayitem_gc_pure': 7, - 'getfield_gc_pure': 56, + 'getfield_gc': 5, + 'getfield_gc_pure': 51, 'guard_class': 3, 'guard_false': 12, 'guard_nonnull': 11, @@ -309,7 +310,8 @@ self.check_resops({ 'float_ge': 2, 'float_ne': 2, - 'getfield_gc_pure': 34, + 'getfield_gc': 4, + 'getfield_gc_pure': 30, 'guard_class': 1, 'guard_false': 8, 'guard_nonnull': 2, @@ -561,7 +563,8 @@ 'float_add': 3, 'getarrayitem_gc': 7, 'getarrayitem_gc_pure': 14, - 'getfield_gc_pure': 69, + 'getfield_gc': 6, + 'getfield_gc_pure': 63, 'guard_class': 5, 'guard_false': 20, 'guard_nonnull': 6, @@ -612,7 +615,8 @@ 'float_add': 2, 'getarrayitem_gc': 2, 'getarrayitem_gc_pure': 2, - 'getfield_gc_pure': 36, + 'getfield_gc': 6, + 'getfield_gc_pure': 30, 'guard_class': 3, 'guard_false': 7, 'guard_nonnull': 2, @@ -769,7 +773,8 @@ 'float_mul': 2, 'getarrayitem_gc': 4, 'getarrayitem_gc_pure': 9, - 'getfield_gc_pure': 49, + 'getfield_gc': 7, + 'getfield_gc_pure': 42, 'guard_class': 4, 'guard_false': 15, 'guard_not_invalidated': 2, From noreply at buildbot.pypy.org Thu Dec 4 22:41:26 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 22:41:26 +0100 (CET) Subject: [pypy-commit] pypy default: use mutating iterator state in flatiter Message-ID: <20141204214126.09ACD1D28F0@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74817:cdcc29b5a5eb Date: 2014-12-04 15:00 -0500 http://bitbucket.org/pypy/pypy/changeset/cdcc29b5a5eb/ Log: use mutating iterator state in flatiter diff --git a/pypy/module/micronumpy/flatiter.py b/pypy/module/micronumpy/flatiter.py --- a/pypy/module/micronumpy/flatiter.py +++ b/pypy/module/micronumpy/flatiter.py @@ -57,7 +57,7 @@ if self.iter.done(self.state): raise OperationError(space.w_StopIteration, space.w_None) w_res = self.iter.getitem(self.state) - self.state = self.iter.next(self.state) + self.iter.next(self.state, mutate=True) return w_res def descr_getitem(self, space, w_idx): @@ -74,7 +74,7 @@ base.get_order(), w_instance=base) return loop.flatiter_getitem(res, self.iter, state, step) finally: - self.state = self.iter.reset(self.state) + self.iter.reset(self.state, mutate=True) def descr_setitem(self, space, w_idx, w_value): if not (space.isinstance_w(w_idx, space.w_int) or @@ -94,7 +94,7 @@ arr = convert_to_array(space, w_value) loop.flatiter_setitem(space, dtype, arr, self.iter, state, step, length) finally: - self.state = self.iter.reset(self.state) + self.iter.reset(self.state, mutate=True) W_FlatIterator.typedef = TypeDef("numpy.flatiter", diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -95,27 +95,18 @@ i86 = int_lt(i79, i45) guard_true(i86, descr=...) guard_not_invalidated(descr=...) - i87 = getfield_gc_pure(p85, descr=) i88 = int_ge(i87, i59) guard_false(i88, descr=...) - i89 = getfield_gc_pure(p85, descr=) f90 = raw_load(i67, i89, descr=) i91 = int_add(i87, 1) - p92 = getfield_gc_pure(p85, descr=) i93 = int_add(i89, i76) i94 = int_add(i79, 1) i95 = getfield_raw(#, descr=) + setfield_gc(p97, i91, descr=) + setfield_gc(p97, i93, descr=) i96 = int_lt(i95, 0) guard_false(i96, descr=...) - p97 = new_with_vtable(#) - {{{ - setfield_gc(p97, p56, descr=) - setfield_gc(p97, p92, descr=) - setfield_gc(p97, i91, descr=) - setfield_gc(p97, i93, descr=) - setfield_gc(p16, p97, descr=) - }}} - jump(p0, p1, p3, p6, p12, p14, p16, i94, f90, p26, i45, p97, i59, p56, i67, i76, descr=...) + jump(p0, p1, p3, p6, p12, p14, p16, i94, f90, p26, i45, i91, i59, p97, p96, i67, i93, i76, descr=...) """) def test_array_flatiter_getitem_single(self): @@ -139,23 +130,15 @@ i128 = int_mul(i117, i59) i129 = int_add(i55, i128) f149 = raw_load(i100, i129, descr=) - p150 = getfield_gc_pure(p123, descr=) i151 = int_add(i117, 1) setarrayitem_gc(p150, 1, 0, descr=) setarrayitem_gc(p150, 0, 0, descr=) + setfield_gc(p156, i55, descr=) guard_not_invalidated(descr=...) i154 = getfield_raw(#, descr=) i155 = int_lt(i154, 0) guard_false(i155, descr=...) - p156 = new_with_vtable(...) - {{{ - setfield_gc(p156, p49, descr=) - setfield_gc(p156, i55, descr=) - setfield_gc(p156, 0, descr=) - setfield_gc(p156, p150, descr=) - setfield_gc(p16, p156, descr=) - }}} - jump(p0, p1, p3, p6, p7, p12, p14, p16, i151, f149, p26, i44, i50, i59, i55, i100, p156, p49, descr=...) + jump(p0, p1, p3, p6, p7, p12, p14, p16, i151, f149, p26, i44, i50, i59, i55, i100, p150, p156, descr=...) """) def test_array_flatiter_setitem_single(self): @@ -180,20 +163,12 @@ i132 = int_add(i53, i131) guard_not_invalidated(descr=...) raw_store(i103, i132, 42.000000, descr=) - p152 = getfield_gc_pure(p126, descr=) i153 = int_add(i120, 1) i154 = getfield_raw(#, descr=) setarrayitem_gc(p152, 1, 0, descr=) setarrayitem_gc(p152, 0, 0, descr=) + setfield_gc(p158, i53, descr=) i157 = int_lt(i154, 0) guard_false(i157, descr=...) - p158 = new_with_vtable(...) - {{{ - setfield_gc(p158, p47, descr=) - setfield_gc(p158, i53, descr=) - setfield_gc(p158, 0, descr=) - setfield_gc(p158, p152, descr=) - setfield_gc(p16, p158, descr=) - }}} - jump(p0, p1, p3, p6, p7, p12, p14, p16, i153, i42, i48, i57, i53, p47, i103, p158, descr=...) + jump(p0, p1, p3, p6, p7, p12, p14, p16, i153, i42, i48, i57, i53, p47, i103, p152, p158, descr=...) """) From noreply at buildbot.pypy.org Thu Dec 4 22:45:27 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 22:45:27 +0100 (CET) Subject: [pypy-commit] creflect default: Accept (and ignore) variable names after "long" (they were already Message-ID: <20141204214527.B1F731D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r152:f9f839119f6e Date: 2014-12-04 22:42 +0100 http://bitbucket.org/cffi/creflect/changeset/f9f839119f6e/ Log: Accept (and ignore) variable names after "long" (they were already accepted after "int") diff --git a/creflect/creflect_cdecl.c b/creflect/creflect_cdecl.c --- a/creflect/creflect_cdecl.c +++ b/creflect/creflect_cdecl.c @@ -444,7 +444,6 @@ case TOK_VOID: case TOK__BOOL: case TOK_FLOAT: - case TOK_IDENTIFIER: case TOK_STRUCT: case TOK_UNION: parse_error(tok, "invalid combination of types"); diff --git a/creflect/test/test_c_decl_parser.py b/creflect/test/test_c_decl_parser.py --- a/creflect/test/test_c_decl_parser.py +++ b/creflect/test/test_c_decl_parser.py @@ -43,6 +43,8 @@ parse("unsigned int", "unsigned int") parse("long", "long") parse("long int", "long") + parse("long int a", "long") + parse("long a", "long") parse("short int", "short") parse("long long int", "long long") parse("unsigned long long *", "PTR unsigned long long") @@ -82,7 +84,7 @@ parse_error("long char", "invalid combination of types", 5) parse_error("short char", "invalid combination of types", 6) parse_error("signed void", "invalid combination of types", 7) - parse_error("unsigned foobar_t", "invalid combination of types", 9) + parse_error("unsigned struct", "invalid combination of types", 9) # parse_error("", "identifier expected", 0) parse_error("]", "identifier expected", 0) From noreply at buildbot.pypy.org Thu Dec 4 22:45:28 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 22:45:28 +0100 (CET) Subject: [pypy-commit] creflect default: function types Message-ID: <20141204214528.D506A1D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r153:bfdb3cb4b9b4 Date: 2014-12-04 22:45 +0100 http://bitbucket.org/cffi/creflect/changeset/bfdb3cb4b9b4/ Log: function types diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -10,32 +10,38 @@ PyObject *types_dict; } zeffir_builder_t; -static PyObject *combine_type_name(_crx_builder_t *cb, CTypeDescrObject *ct, - const char *extra_text) +static PyObject *combine_type_name_l(CTypeDescrObject *ct, + size_t extra_text_len) { - /* Build a PyString with the name given by combining 'ct' and 'extra_text'. - 'ct' can be NULL. If an error occurs (or has already occurred), - returns NULL. */ - size_t base_name_len, extra_name_len; + size_t base_name_len; PyObject *result; char *p; - base_name_len = (ct != NULL ? strlen(ct->ct_name) : 0); - extra_name_len = strlen(extra_text); - result = PyString_FromStringAndSize(NULL, base_name_len + extra_name_len); + base_name_len = strlen(ct->ct_name); + result = PyString_FromStringAndSize(NULL, base_name_len + extra_text_len); if (result == NULL) return NULL; p = PyString_AS_STRING(result); - if (ct != NULL) { - memcpy(p, ct->ct_name, ct->ct_name_position); + memcpy(p, ct->ct_name, ct->ct_name_position); + p += ct->ct_name_position; + p += extra_text_len; + memcpy(p, ct->ct_name + ct->ct_name_position, + base_name_len - ct->ct_name_position); + return result; +} + +static PyObject *combine_type_name(CTypeDescrObject *ct, const char *extra_text) +{ + /* Build a PyString with the name given by combining 'ct' and 'extra_text'. + 'ct' can be NULL. If an error occurs returns NULL. */ + size_t extra_text_len = strlen(extra_text); + PyObject *result = combine_type_name_l(ct, extra_text_len); + + if (result != NULL) { + char *p = PyString_AS_STRING(result); p += ct->ct_name_position; - } - memcpy(p, extra_text, extra_name_len); - if (ct != NULL) { - p += extra_name_len; - memcpy(p, ct->ct_name + ct->ct_name_position, - base_name_len - ct->ct_name_position); + memcpy(p, extra_text, extra_text_len); } return result; } @@ -75,7 +81,7 @@ PyObject *name_obj; CTypeDescrObject *ct; - name_obj = combine_type_name(cb, NULL, name); + name_obj = PyString_FromString(name); if (name_obj == NULL) return NULL; @@ -151,7 +157,63 @@ _crx_qual_type args[], int nargs, _crx_trampoline1_fn trampl) { - abort(); + if (PyErr_Occurred()) + return NULL; + + PyObject *name_obj; + CTypeDescrObject *ct; + size_t extra_len; + + if (nargs == 0) { + name_obj = combine_type_name(ret, "(void)"); + if (name_obj == NULL) + return NULL; + } + else { + char *p; + int i; + extra_len = 1 + 1; /* "(" ")" */ + extra_len += (nargs - 1) * 2; /* ", " */ + for (i = 0; i < nargs; i++) { + extra_len += strlen(args[i].type->ct_name); + } + name_obj = combine_type_name_l(ret, extra_len); + if (name_obj == NULL) + return NULL; + p = PyString_AS_STRING(name_obj); + p += ret->ct_name_position; + *p++ = '('; + for (i = 0; i < nargs; i++) { + size_t len = strlen(args[i].type->ct_name); + if (i > 0) { + *p++ = ','; + *p++ = ' '; + } + memcpy(p, args[i].type->ct_name, len); + p += len; + } + *p++ = ')'; + assert(p - PyString_AS_STRING(name_obj) - ret->ct_name_position + == extra_len); + } + + ct = get_cached_type(cb, name_obj); + if (ct && (ct->ct_flags == CT_FUNCTION)) + goto done; + + ct = ctypedescr_new(name_obj, ret->ct_name_position); + if (ct == NULL) + goto done; + + ct->ct_size = -1; + ct->ct_flags = CT_FUNCTION; + /* XXX more... */ + + put_cached_type(cb, name_obj, ct); + + done: + Py_DECREF(name_obj); + return ct; } static _crx_type_t *zef_get_ellipsis_function_type(_crx_builder_t *cb, @@ -172,12 +234,12 @@ PyObject *name_obj; CTypeDescrObject *ct; - if (totype->ct_flags & CT_ARRAY) + if (totype->ct_flags & (CT_ARRAY | CT_FUNCTION)) extra = "(*)"; else extra = " *"; - name_obj = combine_type_name(cb, totype, extra); + name_obj = combine_type_name(totype, extra); if (name_obj == NULL) return NULL; @@ -228,7 +290,7 @@ else sprintf(extra_text, "[%zd]", length); - name_obj = combine_type_name(cb, ctitem, extra_text); + name_obj = combine_type_name(ctitem, extra_text); if (name_obj == NULL) return NULL; @@ -292,7 +354,7 @@ if (PyErr_Occurred()) return result; - name_obj = combine_type_name(cb, NULL, name); + name_obj = PyString_FromString(name); if (name_obj == NULL) return result; diff --git a/zeffir/ctype.c b/zeffir/ctype.c --- a/zeffir/ctype.c +++ b/zeffir/ctype.c @@ -10,11 +10,11 @@ #define CT_UNION 128 /* union */ #define CT_UNKNOWN 256 /* unknown type */ #define CT_VOID 512 /* void */ +#define CT_FUNCTION 1024 /* function */ /* other flags that may also be set in addition to the base flag: */ -#define CT_CAST_ANYTHING 1024 /* 'char *' and 'void *' only */ -#define CT_PRIMITIVE_FITS_LONG 2048 -//#define CT_IS_OPAQUE 4096 /* == (ct_size < 0) */ +#define CT_CAST_ANYTHING 2048 /* 'char *' and 'void *' only */ +#define CT_PRIMITIVE_FITS_LONG 4096 #define CT_IS_ENUM 8192 #define CT_IS_PTR_TO_OWNED 16384 #define CT_IS_LONGDOUBLE 65536 diff --git a/zeffir/test/test_ctype.py b/zeffir/test/test_ctype.py --- a/zeffir/test/test_ctype.py +++ b/zeffir/test/test_ctype.py @@ -67,6 +67,13 @@ assert repr(ffi.typeof("int * [ ]")) == "" assert repr(ffi.typeof("int ( * ) [ ]")) == "" +def test_typeof_function(): + ffi = support.new_ffi() + assert repr(ffi.typeof("int()")) == "" + assert repr(ffi.typeof("int*(void*)")) == "" + assert repr(ffi.typeof("int(long a,short b)"))=="" + assert repr(ffi.typeof("int(*)(long)"))=="" + def test_simple_typedef(): ffi, lib = support.compile_and_open('ctype') assert ffi.sizeof("foo_t") == ffi.sizeof("long long") From noreply at buildbot.pypy.org Thu Dec 4 22:49:23 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 22:49:23 +0100 (CET) Subject: [pypy-commit] creflect default: functions with '...' Message-ID: <20141204214923.483A41D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r154:47c327664396 Date: 2014-12-04 22:49 +0100 http://bitbucket.org/cffi/creflect/changeset/47c327664396/ Log: functions with '...' diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -153,9 +153,9 @@ return _zef_primitive(cb, sz, name, flags); } -static _crx_type_t *zef_get_function_type(_crx_builder_t *cb, _crx_type_t *ret, - _crx_qual_type args[], int nargs, - _crx_trampoline1_fn trampl) +static _crx_type_t *_zef_function(_crx_builder_t *cb, _crx_type_t *ret, + _crx_qual_type args[], int nargs, + int dotdotdot) { if (PyErr_Occurred()) return NULL; @@ -163,8 +163,9 @@ PyObject *name_obj; CTypeDescrObject *ct; size_t extra_len; + int nargsall = nargs + dotdotdot; - if (nargs == 0) { + if (nargsall == 0) { name_obj = combine_type_name(ret, "(void)"); if (name_obj == NULL) return NULL; @@ -173,10 +174,12 @@ char *p; int i; extra_len = 1 + 1; /* "(" ")" */ - extra_len += (nargs - 1) * 2; /* ", " */ + extra_len += (nargsall - 1) * 2; /* ", " */ for (i = 0; i < nargs; i++) { extra_len += strlen(args[i].type->ct_name); } + if (dotdotdot) + extra_len += 3; /* "..." */ name_obj = combine_type_name_l(ret, extra_len); if (name_obj == NULL) return NULL; @@ -192,6 +195,14 @@ memcpy(p, args[i].type->ct_name, len); p += len; } + if (dotdotdot) { + if (nargs > 0) { + *p++ = ','; + *p++ = ' '; + } + memcpy(p, "...", 3); + p += 3; + } *p++ = ')'; assert(p - PyString_AS_STRING(name_obj) - ret->ct_name_position == extra_len); @@ -216,12 +227,19 @@ return ct; } +static _crx_type_t *zef_get_function_type(_crx_builder_t *cb, _crx_type_t *ret, + _crx_qual_type args[], int nargs, + _crx_trampoline1_fn trampl) +{ + return _zef_function(cb, ret, args, nargs, 0); +} + static _crx_type_t *zef_get_ellipsis_function_type(_crx_builder_t *cb, _crx_type_t *ret, _crx_qual_type args[], int nargs) { - abort(); + return _zef_function(cb, ret, args, nargs, 1); } static _crx_type_t *zef_get_pointer_type(_crx_builder_t *cb, diff --git a/zeffir/test/test_ctype.py b/zeffir/test/test_ctype.py --- a/zeffir/test/test_ctype.py +++ b/zeffir/test/test_ctype.py @@ -74,6 +74,11 @@ assert repr(ffi.typeof("int(long a,short b)"))=="" assert repr(ffi.typeof("int(*)(long)"))=="" +def test_typedef_function_dotdotdot(): + ffi = support.new_ffi() + assert repr(ffi.typeof("int(...)")) == "" + assert repr(ffi.typeof("int*(void*,...)")) == "" + def test_simple_typedef(): ffi, lib = support.compile_and_open('ctype') assert ffi.sizeof("foo_t") == ffi.sizeof("long long") From noreply at buildbot.pypy.org Thu Dec 4 23:01:19 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 23:01:19 +0100 (CET) Subject: [pypy-commit] pypy default: add a test_pypy_c for array.any() Message-ID: <20141204220119.A03CF1D2B03@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74818:ff4204895657 Date: 2014-12-04 17:00 -0500 http://bitbucket.org/pypy/pypy/changeset/ff4204895657/ Log: add a test_pypy_c for array.any() diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -3,6 +3,30 @@ class TestMicroNumPy(BaseTestPyPyC): + def test_array_any(self): + def main(): + import _numpypy.multiarray as np + arr = np.array([False] * 1500) + return arr.any() + log = self.run(main, []) + assert log.result == False + assert len(log.loops) == 1 + loop = log._filter(log.loops[0]) + assert loop.match(""" + i33 = raw_load(i9, i29, descr=) + guard_false(i33, descr=...) + guard_not_invalidated(descr=...) + i34 = getarrayitem_raw(#, 1, descr=) + guard_value(i34, 0, descr=...) + i35 = getarrayitem_raw(#, 0, descr=) + i36 = int_add(i24, 1) + i37 = int_add(i29, i28) + i38 = int_ge(i36, i30) + guard_false(i38, descr=...) + guard_value(i35, 1, descr=...) + jump(p0, p25, i36, i37, i9, i28, i30, descr=...) + """) + def test_array_getitem_basic(self): def main(): import _numpypy.multiarray as np From noreply at buildbot.pypy.org Thu Dec 4 23:09:13 2014 From: noreply at buildbot.pypy.org (arigo) Date: Thu, 4 Dec 2014 23:09:13 +0100 (CET) Subject: [pypy-commit] creflect default: tweaks Message-ID: <20141204220913.0E0701C07BB@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r155:7c6a10d45a9d Date: 2014-12-04 22:59 +0100 http://bitbucket.org/cffi/creflect/changeset/7c6a10d45a9d/ Log: tweaks diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -563,11 +563,11 @@ PyErr_Fetch(&exc, &val, &tb); ps = PyObject_Str(val); if (ps != NULL && PyString_Check(ps)) { - PyErr_Format(exc, "at pos %zd: %s", - (size_t)(err - str), PyString_AS_STRING(ps)); Py_XDECREF(tb); Py_XDECREF(val); Py_XDECREF(exc); + PyErr_Format(exc, "at pos %zd: %s", + (size_t)(err - str), PyString_AS_STRING(ps)); } else { PyErr_Restore(exc, val, tb); @@ -576,8 +576,7 @@ } return NULL; } - if (err != NULL) - abort(); + assert(err == NULL); /* else, zef_error() must have been called */ Py_INCREF(result.type); return result.type; diff --git a/zeffir/lib_obj.c b/zeffir/lib_obj.c --- a/zeffir/lib_obj.c +++ b/zeffir/lib_obj.c @@ -43,6 +43,12 @@ return x; } +static int lib_setattr(ZefLibObject *lib, PyObject *name, PyObject *val) +{ + PyErr_SetString(PyExc_AttributeError, "Lib object is read-only"); + return -1; +} + static PyObject *lib_dir(PyObject *lib, PyObject *noarg) { return PyDict_Keys(((ZefLibObject *)lib)->l_dict); @@ -71,7 +77,7 @@ 0, /* tp_call */ 0, /* tp_str */ (getattrofunc)lib_getattr, /* tp_getattro */ - 0, /* tp_setattro */ + (setattrofunc)lib_setattr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ @@ -88,7 +94,7 @@ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ - offsetof(ZefLibObject, l_dict), /* tp_dictoffset */ + offsetof(ZefLibObject, l_dict), /* tp_dictoffset */ }; static void lib_dlerror(ZefLibObject *lib) diff --git a/zeffir/test/test_basic.py b/zeffir/test/test_basic.py --- a/zeffir/test/test_basic.py +++ b/zeffir/test/test_basic.py @@ -14,6 +14,8 @@ ffi, lib = support.compile_and_open('basic') assert lib.forty_two == 42 assert type(lib.forty_two) is int + py.test.raises(AttributeError, setattr, lib, 'forty_two', 43) + py.test.raises(AttributeError, delattr, lib, 'forty_two') def test_dir(): ffi, lib = support.compile_and_open('basic') @@ -21,7 +23,10 @@ def test_no_special_attribute(): ffi, lib = support.compile_and_open('basic') - py.test.raises(AttributeError, getattr, lib, '__class__') + for name in dir(object()): # '__class__', '__str__', etc. + py.test.raises(AttributeError, getattr, lib, name) + py.test.raises(AttributeError, setattr, lib, name, '?') + py.test.raises(AttributeError, delattr, lib, name) def test_types(): ffi = support.new_ffi() From noreply at buildbot.pypy.org Thu Dec 4 23:57:11 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Thu, 4 Dec 2014 23:57:11 +0100 (CET) Subject: [pypy-commit] pypy default: cleanups Message-ID: <20141204225711.E12091C07BB@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74819:a0e9ee8c4971 Date: 2014-12-04 17:57 -0500 http://bitbucket.org/pypy/pypy/changeset/a0e9ee8c4971/ Log: cleanups diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -287,8 +287,9 @@ def logical_xor(self, v1, v2): return bool(v1) ^ bool(v2) + @raw_unary_op def bool(self, v): - return bool(self.for_computation(self.unbox(v))) + return bool(v) @simple_binary_op def max(self, v1, v2): diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -18,6 +18,7 @@ def done_if_false(dtype, val): return not dtype.itemtype.bool(val) + def _get_dtype(space, w_npyobj): if isinstance(w_npyobj, boxes.W_GenericBox): return w_npyobj.get_dtype(space) diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -16,14 +16,14 @@ i33 = raw_load(i9, i29, descr=) guard_false(i33, descr=...) guard_not_invalidated(descr=...) - i34 = getarrayitem_raw(#, 1, descr=) - guard_value(i34, 0, descr=...) - i35 = getarrayitem_raw(#, 0, descr=) + i34 = getarrayitem_raw(#, 1, descr=) # XXX what are these? + guard_value(i34, 0, descr=...) # XXX + i35 = getarrayitem_raw(#, 0, descr=) # XXX i36 = int_add(i24, 1) i37 = int_add(i29, i28) i38 = int_ge(i36, i30) guard_false(i38, descr=...) - guard_value(i35, 1, descr=...) + guard_value(i35, 1, descr=...) # XXX jump(p0, p25, i36, i37, i9, i28, i30, descr=...) """) @@ -130,7 +130,7 @@ setfield_gc(p97, i93, descr=) i96 = int_lt(i95, 0) guard_false(i96, descr=...) - jump(p0, p1, p3, p6, p12, p14, p16, i94, f90, p26, i45, i91, i59, p97, p96, i67, i93, i76, descr=...) + jump(p0, p1, p3, p6, p12, p14, p16, i94, f90, p26, i45, i91, i59, p96, p97, i67, i93, i76, descr=...) """) def test_array_flatiter_getitem_single(self): From noreply at buildbot.pypy.org Fri Dec 5 02:38:09 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Fri, 5 Dec 2014 02:38:09 +0100 (CET) Subject: [pypy-commit] pypy default: cleanup some numpy test_pypy_c tests Message-ID: <20141205013809.73BFD1C100F@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74820:e99e8fe69789 Date: 2014-12-04 20:35 -0500 http://bitbucket.org/pypy/pypy/changeset/e99e8fe69789/ Log: cleanup some numpy test_pypy_c tests diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -58,9 +58,8 @@ """ + alignment_check + """ f80 = raw_load(i67, i79, descr=) i81 = int_add(i71, 1) - guard_not_invalidated(descr=...) --TICK-- - jump(p0, p1, p3, p6, p7, p12, p14, p16, i81, f80, i59, p38, i55, p40, i37, i61, i67, descr=...) + jump(..., descr=...) """) def test_array_getitem_accumulate(self): @@ -130,7 +129,7 @@ setfield_gc(p97, i93, descr=) i96 = int_lt(i95, 0) guard_false(i96, descr=...) - jump(p0, p1, p3, p6, p12, p14, p16, i94, f90, p26, i45, i91, i59, p96, p97, i67, i93, i76, descr=...) + jump(..., descr=...) """) def test_array_flatiter_getitem_single(self): @@ -158,11 +157,8 @@ setarrayitem_gc(p150, 1, 0, descr=) setarrayitem_gc(p150, 0, 0, descr=) setfield_gc(p156, i55, descr=) - guard_not_invalidated(descr=...) - i154 = getfield_raw(#, descr=) - i155 = int_lt(i154, 0) - guard_false(i155, descr=...) - jump(p0, p1, p3, p6, p7, p12, p14, p16, i151, f149, p26, i44, i50, i59, i55, i100, p150, p156, descr=...) + --TICK-- + jump(..., descr=...) """) def test_array_flatiter_setitem_single(self): @@ -194,5 +190,5 @@ setfield_gc(p158, i53, descr=) i157 = int_lt(i154, 0) guard_false(i157, descr=...) - jump(p0, p1, p3, p6, p7, p12, p14, p16, i153, i42, i48, i57, i53, p47, i103, p152, p158, descr=...) + jump(..., descr=...) """) From noreply at buildbot.pypy.org Fri Dec 5 02:38:10 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Fri, 5 Dec 2014 02:38:10 +0100 (CET) Subject: [pypy-commit] pypy default: simplify array.any test_pypy_c to use reduce directly Message-ID: <20141205013810.A81901C100F@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74821:e301f280ff33 Date: 2014-12-04 20:24 -0500 http://bitbucket.org/pypy/pypy/changeset/e301f280ff33/ Log: simplify array.any test_pypy_c to use reduce directly diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -3,28 +3,31 @@ class TestMicroNumPy(BaseTestPyPyC): - def test_array_any(self): + def test_reduce_logical_and(self): def main(): import _numpypy.multiarray as np - arr = np.array([False] * 1500) - return arr.any() + import _numpypy.umath as um + arr = np.array([1.0] * 1500) + return um.logical_and.reduce(arr) log = self.run(main, []) - assert log.result == False + assert log.result is True assert len(log.loops) == 1 loop = log._filter(log.loops[0]) assert loop.match(""" - i33 = raw_load(i9, i29, descr=) - guard_false(i33, descr=...) + f31 = raw_load(i9, i29, descr=) guard_not_invalidated(descr=...) - i34 = getarrayitem_raw(#, 1, descr=) # XXX what are these? - guard_value(i34, 0, descr=...) # XXX - i35 = getarrayitem_raw(#, 0, descr=) # XXX + i32 = cast_float_to_int(f31) + i33 = int_and(i32, 255) + guard_true(i33, descr=...) + i34 = getarrayitem_raw(#, 2, descr=) # XXX what are these? + guard_value(i34, 1, descr=...) # XXX don't appear in + i35 = getarrayitem_raw(#, 1, descr=) # XXX equiv test_zjit i36 = int_add(i24, 1) i37 = int_add(i29, i28) i38 = int_ge(i36, i30) guard_false(i38, descr=...) - guard_value(i35, 1, descr=...) # XXX - jump(p0, p25, i36, i37, i9, i28, i30, descr=...) + guard_value(i35, 2, descr=...) # XXX + jump(..., descr=...) """) def test_array_getitem_basic(self): From noreply at buildbot.pypy.org Fri Dec 5 02:38:11 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Fri, 5 Dec 2014 02:38:11 +0100 (CET) Subject: [pypy-commit] pypy default: add test_pypy_c for logical_xor.reduce Message-ID: <20141205013811.D716B1C100F@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74822:81a86598865d Date: 2014-12-04 20:25 -0500 http://bitbucket.org/pypy/pypy/changeset/81a86598865d/ Log: add test_pypy_c for logical_xor.reduce diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -3,6 +3,59 @@ class TestMicroNumPy(BaseTestPyPyC): + def test_reduce_logical_xor(self): + def main(): + import _numpypy.multiarray as np + import _numpypy.umath as um + arr = np.array([1.0] * 1500) + return um.logical_xor.reduce(arr) + log = self.run(main, []) + assert log.result is False + assert len(log.loops) == 1 + loop = log._filter(log.loops[0]) + assert loop.match(""" + guard_class(p0, #, descr=...) + p4 = getfield_gc_pure(p0, descr=) + i5 = getfield_gc(p2, descr=) + p6 = getfield_gc_pure(p4, descr=) + p7 = getfield_gc_pure(p6, descr=) + guard_class(p7, ConstClass(Float64), descr=...) + i9 = getfield_gc_pure(p4, descr=) + f10 = raw_load(i9, i5, descr=) + i11 = getfield_gc_pure(p7, descr=) + guard_true(i11, descr=...) + guard_not_invalidated(descr=...) + i12 = cast_float_to_int(f10) + i14 = int_and(i12, 255) + guard_true(i14, descr=...) + i15 = getfield_gc_pure(p1, descr=) + i16 = int_is_true(i15) + i18 = int_xor(i16, 1) + i19 = int_is_true(i18) + guard_true(i19, descr=...) + i20 = getfield_gc(p2, descr=) + i21 = getfield_gc_pure(p0, descr=) + guard_true(i21, descr=...) + i23 = int_add(i20, 1) + p24 = getfield_gc_pure(p2, descr=) + i25 = getfield_gc_pure(p0, descr=) + i26 = int_is_true(i25) + guard_true(i26, descr=...) + i27 = getfield_gc_pure(p6, descr=) + i28 = int_add(i5, i27) + i29 = getfield_gc_pure(p0, descr=) + i30 = int_ge(i23, i29) + guard_false(i30, descr=...) + p32 = new_with_vtable(#) + {{{ + setfield_gc(p32, i23, descr=) + setfield_gc(p32, p24, descr=) + setfield_gc(p32, i28, descr=) + setfield_gc(p32, p0, descr=) + }}} + jump(..., descr=...) + """) + def test_reduce_logical_and(self): def main(): import _numpypy.multiarray as np From noreply at buildbot.pypy.org Fri Dec 5 05:02:06 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Fri, 5 Dec 2014 05:02:06 +0100 (CET) Subject: [pypy-commit] pypy default: fix this test_pypy_c, these numbers can vary Message-ID: <20141205040206.68D781C07BB@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74823:e27f4fbd7134 Date: 2014-12-04 21:57 -0500 http://bitbucket.org/pypy/pypy/changeset/e27f4fbd7134/ Log: fix this test_pypy_c, these numbers can vary diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -72,14 +72,14 @@ i32 = cast_float_to_int(f31) i33 = int_and(i32, 255) guard_true(i33, descr=...) - i34 = getarrayitem_raw(#, 2, descr=) # XXX what are these? - guard_value(i34, 1, descr=...) # XXX don't appear in - i35 = getarrayitem_raw(#, 1, descr=) # XXX equiv test_zjit + i34 = getarrayitem_raw(#, #, descr=) # XXX what are these? + guard_value(i34, #, descr=...) # XXX don't appear in + i35 = getarrayitem_raw(#, #, descr=) # XXX equiv test_zjit i36 = int_add(i24, 1) i37 = int_add(i29, i28) i38 = int_ge(i36, i30) guard_false(i38, descr=...) - guard_value(i35, 2, descr=...) # XXX + guard_value(i35, #, descr=...) # XXX jump(..., descr=...) """) From noreply at buildbot.pypy.org Fri Dec 5 06:50:14 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Fri, 5 Dec 2014 06:50:14 +0100 (CET) Subject: [pypy-commit] pypy default: test/fix ufunc reduce with comparison func when dtype specified Message-ID: <20141205055014.464A61D28F0@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74824:4213885db36d Date: 2014-12-05 00:23 -0500 http://bitbucket.org/pypy/pypy/changeset/4213885db36d/ Log: test/fix ufunc reduce with comparison func when dtype specified diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -785,6 +785,7 @@ assert exc.value[0] == "'axis' entry is out of bounds" def test_reduce_1d(self): + import numpy as np from numpypy import array, add, maximum, less, float16, complex64 assert less.reduce([5, 4, 3, 2, 1]) @@ -799,6 +800,10 @@ assert type(add.reduce(array([True, False] * 200, dtype='float16'))) is float16 assert type(add.reduce(array([True, False] * 200, dtype='complex64'))) is complex64 + for dtype in ['bool', 'int']: + assert np.equal.reduce([1, 2], dtype=dtype) == True + assert np.equal.reduce([1, 2, 0], dtype=dtype) == False + def test_reduceND(self): from numpypy import add, arange a = arange(12).reshape(3, 4) diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -196,16 +196,15 @@ axis += shapelen assert axis >= 0 dtype = descriptor.decode_w_dtype(space, dtype) - if dtype is None: - if self.comparison_func: - dtype = descriptor.get_dtype_cache(space).w_booldtype - else: - dtype = find_unaryop_result_dtype( - space, obj.get_dtype(), - promote_to_float=self.promote_to_float, - promote_to_largest=self.promote_to_largest, - promote_bools=self.promote_bools, - ) + if self.comparison_func: + dtype = descriptor.get_dtype_cache(space).w_booldtype + elif dtype is None: + dtype = find_unaryop_result_dtype( + space, obj.get_dtype(), + promote_to_float=self.promote_to_float, + promote_to_largest=self.promote_to_largest, + promote_bools=self.promote_bools, + ) if self.identity is None: for i in range(shapelen): if space.is_none(w_axis) or i == axis: From noreply at buildbot.pypy.org Fri Dec 5 10:00:44 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 10:00:44 +0100 (CET) Subject: [pypy-commit] creflect default: global vars, starting Message-ID: <20141205090044.830AE1C03D5@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r156:f5bc966d0d96 Date: 2014-12-05 10:01 +0100 http://bitbucket.org/cffi/creflect/changeset/f5bc966d0d96/ Log: global vars, starting diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -413,7 +413,17 @@ static void zef_define_var(_crx_builder_t *cb, const char *name, _crx_type_t *type, int quals, const void *addr) { - abort(); + if (PyErr_Occurred()) + return; + + PyObject *l_dict = ((zeffir_builder_t *)cb)->l_dict; + + PyObject *x = make_global_var(type, addr); + if (x == NULL) + return; + + PyDict_SetItemString(l_dict, name, x); + Py_DECREF(x); } static void zef_define_func(_crx_builder_t *cb, const char *name, diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -1,1 +1,56 @@ +struct CDataObject_s { + PyObject_HEAD + CTypeDescrObject *c_type; + char *c_data; + PyObject *c_weakreflist; +}; + +/* +#define CData_Check(ob) (Py_TYPE(ob) == &CData_Type || \ + Py_TYPE(ob) == &CDataOwning_Type || \ + Py_TYPE(ob) == &CDataOwningGC_Type) +#define CDataOwn_Check(ob) (Py_TYPE(ob) == &CDataOwning_Type || \ + Py_TYPE(ob) == &CDataOwningGC_Type) +*/ + +static void cdata_dealloc(CDataObject *cd) +{ + if (cd->c_weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) cd); + + Py_DECREF(cd->c_type); +#ifndef CFFI_MEM_LEAK /* never release anything, tests only */ + Py_TYPE(cd)->tp_free((PyObject *)cd); +#endif +} + +static PyTypeObject CData_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "zeffir.CData", + sizeof(CDataObject), + 0, + (destructor)cdata_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0,//(reprfunc)cdata_repr, /* tp_repr */ + 0,//&CData_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0,//&CData_as_mapping, /* tp_as_mapping */ + 0,//(hashfunc)cdata_hash, /* tp_hash */ + 0,//(ternaryfunc)cdata_call, /* tp_call */ + 0, /* tp_str */ + 0,//(getattrofunc)cdata_getattro, /* tp_getattro */ + 0,//(setattrofunc)cdata_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0,//cdata_richcompare, /* tp_richcompare */ + offsetof(CDataObject, c_weakreflist), /* tp_weaklistoffset */ + 0,//(getiterfunc)cdata_iter, /* tp_iter */ + 0, /* tp_iternext */ +}; diff --git a/zeffir/cfunc.c b/zeffir/cfunc.c --- a/zeffir/cfunc.c +++ b/zeffir/cfunc.c @@ -9,7 +9,7 @@ } ZefFuncSupportObject; -static void zef_builtin_support_dealloc(ZefFuncSupportObject *zfs) +static void zef_func_support_dealloc(ZefFuncSupportObject *zfs) { PyObject_Del(zfs); } @@ -19,7 +19,7 @@ "zeffir.FuncSupport", sizeof(ZefFuncSupportObject), 0, - (destructor)zef_builtin_support_dealloc, /* tp_dealloc */ + (destructor)zef_func_support_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ diff --git a/zeffir/cglob.c b/zeffir/cglob.c new file mode 100644 --- /dev/null +++ b/zeffir/cglob.c @@ -0,0 +1,53 @@ + +typedef struct { + PyObject_HEAD + + CTypeDescrObject *zgs_type; + char *zgs_data; + +} ZefGlobSupportObject; + +static void zef_glob_support_dealloc(ZefGlobSupportObject *zgs) +{ + Py_DECREF(zgs->zgs_type); + PyObject_Del(zgs); +} + +static PyTypeObject ZefGlobSupport_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "zeffir.GlobSupport", + sizeof(ZefGlobSupportObject), + 0, + (destructor)zef_glob_support_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ +}; + +#define ZefGlobSupport_Check(ob) (Py_TYPE(ob) == &ZefGlobSupport_Type) + +static PyObject *make_global_var(_crx_type_t *type, const void *addr) +{ + ZefGlobSupportObject *zgs = + PyObject_New(ZefGlobSupportObject, &ZefGlobSupport_Type); + if (zgs == NULL) + return NULL; + + Py_INCREF(type); + zgs->zgs_type = type; + zgs->zgs_data = (char *)addr; + assert(addr != NULL); + return (PyObject *)zgs; +} diff --git a/zeffir/ctype.c b/zeffir/ctype.c --- a/zeffir/ctype.c +++ b/zeffir/ctype.c @@ -49,18 +49,7 @@ char ct_name[1]; /* string, e.g. "int *" for pointers to ints */ }; -static PyTypeObject CTypeDescr_Type; -//static PyTypeObject CField_Type; -//static PyTypeObject CData_Type; -//static PyTypeObject CDataOwning_Type; -//static PyTypeObject CDataOwningGC_Type; - #define CTypeDescr_Check(ob) (Py_TYPE(ob) == &CTypeDescr_Type) -#define CData_Check(ob) (Py_TYPE(ob) == &CData_Type || \ - Py_TYPE(ob) == &CDataOwning_Type || \ - Py_TYPE(ob) == &CDataOwningGC_Type) -#define CDataOwn_Check(ob) (Py_TYPE(ob) == &CDataOwning_Type || \ - Py_TYPE(ob) == &CDataOwningGC_Type) /************************************************************/ diff --git a/zeffir/lib_obj.c b/zeffir/lib_obj.c --- a/zeffir/lib_obj.c +++ b/zeffir/lib_obj.c @@ -25,8 +25,10 @@ lib->l_dl_lib == NULL ? " (closed)" : ""); } -static PyObject *lib_getattr(ZefLibObject *lib, PyObject *name) +static PyObject *lib_findattr(ZefLibObject *lib, PyObject *name) { + /* does not return a new reference! */ + if (lib->l_dict == NULL) { PyErr_Format(ZefError, "lib '%.200s' was closed", lib->l_libname); return NULL; @@ -39,13 +41,49 @@ " global variable or constant '%.200s'", lib->l_libname, PyString_Check(name) ? PyString_AS_STRING(name) : "?"); + return NULL; } return x; } +static PyObject *lib_getattr(ZefLibObject *lib, PyObject *name) +{ + PyObject *x = lib_findattr(lib, name); + if (x == NULL) + return NULL; + + if (ZefGlobSupport_Check(x)) { + // XXX! + return PyInt_FromLong(*(int *)(((ZefGlobSupportObject *)x)->zgs_data)); + } + Py_INCREF(x); + return x; +} + static int lib_setattr(ZefLibObject *lib, PyObject *name, PyObject *val) { - PyErr_SetString(PyExc_AttributeError, "Lib object is read-only"); + PyObject *x = lib_findattr(lib, name); + if (x == NULL) + return -1; + + if (val == NULL) { + PyErr_SetString(PyExc_AttributeError, + "cannot delete attributes from Lib object"); + return -1; + } + + if (ZefGlobSupport_Check(x)) { + // XXX! + long y = PyInt_AsLong(val); + if (PyErr_Occurred()) + return -1; + *(int *)(((ZefGlobSupportObject *)x)->zgs_data) = y; + return 0; + } + + PyErr_Format(PyExc_AttributeError, + "cannot write to function or constant '%.200s'", + PyString_Check(name) ? PyString_AS_STRING(name) : "?"); return -1; } diff --git a/zeffir/test/global.crx b/zeffir/test/global.crx new file mode 100644 --- /dev/null +++ b/zeffir/test/global.crx @@ -0,0 +1,8 @@ +short myglob = 42; + + +// CREFLECT: start + +short myglob; + +// CREFLECT: end diff --git a/zeffir/test/test_global.py b/zeffir/test/test_global.py new file mode 100644 --- /dev/null +++ b/zeffir/test/test_global.py @@ -0,0 +1,17 @@ +import py +import support + + +def test_simple_global(): + ffi, lib = support.compile_and_open('global') + res = lib.myglob + assert type(res) is int + assert res == 42 + # + lib.myglob = -43 + res = lib.myglob + assert type(res) is int + assert res == -43 + # + #py.test.raises(OverflowError, setattr, lib, 'myglob', 40000) + #py.test.raises(OverflowError, setattr, lib, 'myglob', -40000) diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c --- a/zeffir/zeffir.c +++ b/zeffir/zeffir.c @@ -12,6 +12,7 @@ #include "zeffir.h" #include "ctype.c" #include "cdata.c" +#include "cglob.c" #include "lib_obj.c" #include "ffi_obj.c" #include "cfunc.c" @@ -39,13 +40,21 @@ return; if (PyType_Ready(&CTypeDescr_Type) < 0) return; + if (PyType_Ready(&CData_Type) < 0) + return; if (PyType_Ready(&ZefFuncSupport_Type) < 0) return; + if (PyType_Ready(&ZefGlobSupport_Type) < 0) + return; if (PyModule_AddObject(m, "FFI", (PyObject *)&ZefFFI_Type) < 0) return; + if (PyModule_AddObject(m, "Lib", (PyObject *)&ZefLib_Type) < 0) + return; if (PyModule_AddObject(m, "CType", (PyObject *)&CTypeDescr_Type) < 0) return; + if (PyModule_AddObject(m, "CData", (PyObject *)&CData_Type) < 0) + return; ZefError = PyErr_NewException("zeffir.error", NULL, NULL); if (ZefError == NULL) diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h --- a/zeffir/zeffir.h +++ b/zeffir/zeffir.h @@ -1,9 +1,15 @@ typedef struct _crx_type_s CTypeDescrObject; +typedef struct CDataObject_s CDataObject; typedef struct ZefLibObject_s ZefLibObject; typedef struct ZefFFIObject_s ZefFFIObject; static PyTypeObject ZefFFI_Type; +static PyTypeObject CTypeDescr_Type; +//static PyTypeObject CField_Type; +static PyTypeObject CData_Type; +//static PyTypeObject CDataOwning_Type; +//static PyTypeObject CDataOwningGC_Type; static PyObject *ZefError; From noreply at buildbot.pypy.org Fri Dec 5 10:04:03 2014 From: noreply at buildbot.pypy.org (Raemi) Date: Fri, 5 Dec 2014 10:04:03 +0100 (CET) Subject: [pypy-commit] stmgc c8-private-pages: merge (hopefully) fixed _stm_validate() Message-ID: <20141205090403.0AFB71C03D5@cobra.cs.uni-duesseldorf.de> Author: Remi Meier Branch: c8-private-pages Changeset: r1514:970af41866c7 Date: 2014-12-05 10:05 +0100 http://bitbucket.org/pypy/stmgc/changeset/970af41866c7/ Log: merge (hopefully) fixed _stm_validate() diff --git a/c8/stm/core.c b/c8/stm/core.c --- a/c8/stm/core.c +++ b/c8/stm/core.c @@ -278,87 +278,108 @@ return; } - /* Find the set of segments we need to copy from and lock them: */ - uint64_t segments_to_lock = 1UL << my_segnum; - cl = first_cl; - while ((next_cl = cl->next) != NULL) { - if (next_cl == INEV_RUNNING) { + bool needs_abort = false; + + while(1) { + /* retry IF: */ + /* if at the time of "HERE" (s.b.) there happen to be + more commits (and bk copies) then it could be that + copy_bk_objs_in_page_from (s.b.) reads a bk copy that + is itself more recent than last_cl. This is fixed + by re-validating. */ + first_cl = STM_PSEGMENT->last_commit_log_entry; + if (first_cl->next == NULL) + break; + + /* Find the set of segments we need to copy from and lock them: */ + uint64_t segments_to_lock = 1UL << my_segnum; + cl = first_cl; + while ((next_cl = cl->next) != NULL) { + if (next_cl == INEV_RUNNING) { #if STM_TESTS - if (free_if_abort != (void *)-1) - free(free_if_abort); - stm_abort_transaction(); + if (free_if_abort != (void *)-1) + free(free_if_abort); + stm_abort_transaction(); #endif - /* only validate entries up to INEV */ - break; + /* only validate entries up to INEV */ + break; + } + assert(next_cl->rev_num > cl->rev_num); + cl = next_cl; + + if (cl->written_count) { + segments_to_lock |= (1UL << cl->segment_num); + } } - assert(next_cl->rev_num > cl->rev_num); - cl = next_cl; + last_cl = cl; + /* HERE */ + acquire_modification_lock_set(segments_to_lock); - if (cl->written_count) { - segments_to_lock |= (1UL << cl->segment_num); - } - } - last_cl = cl; - acquire_modification_lock_set(segments_to_lock); + /* import objects from first_cl to last_cl: */ + if (first_cl != last_cl) { + uint64_t segment_really_copied_from = 0UL; - /* import objects from first_cl to last_cl: */ - bool needs_abort = false; - if (first_cl != last_cl) { - uint64_t segment_really_copied_from = 0UL; - - cl = first_cl; - while ((cl = cl->next) != NULL) { - if (!needs_abort) { - struct stm_undo_s *undo = cl->written; - struct stm_undo_s *end = cl->written + cl->written_count; - for (; undo < end; undo++) { - if (_stm_was_read(undo->object)) { - /* first reset all modified objects from the backup - copies as soon as the first conflict is detected; - then we will proceed below to update our segment from - the old (but unmodified) version to the newer version. - */ - reset_modified_from_backup_copies(my_segnum); - needs_abort = true; - break; + cl = first_cl; + while ((cl = cl->next) != NULL) { + if (!needs_abort) { + struct stm_undo_s *undo = cl->written; + struct stm_undo_s *end = cl->written + cl->written_count; + for (; undo < end; undo++) { + if (_stm_was_read(undo->object)) { + /* first reset all modified objects from the backup + copies as soon as the first conflict is detected; + then we will proceed below to update our segment from + the old (but unmodified) version to the newer version. + */ + reset_modified_from_backup_copies(my_segnum); + needs_abort = true; + break; + } } } + + if (cl->written_count) { + struct stm_undo_s *undo = cl->written; + struct stm_undo_s *end = cl->written + cl->written_count; + + segment_really_copied_from |= (1UL << cl->segment_num); + import_objects(cl->segment_num, -1, undo, end); + + /* here we can actually have our own modified version, so + make sure to only copy things that are not modified in our + segment... (if we do not abort) */ + copy_bk_objs_in_page_from + (cl->segment_num, -1, /* any page */ + !needs_abort); /* if we abort, we still want to copy everything */ + } + + /* last fully validated entry */ + STM_PSEGMENT->last_commit_log_entry = cl; + if (cl == last_cl) + break; } + assert(cl == last_cl); - if (cl->written_count) { - struct stm_undo_s *undo = cl->written; - struct stm_undo_s *end = cl->written + cl->written_count; + /* XXX: this optimization fails in test_basic.py, bug3 */ + /* OPT_ASSERT(segment_really_copied_from < (1 << NB_SEGMENTS)); */ + /* int segnum; */ + /* for (segnum = 0; segnum < NB_SEGMENTS; segnum++) { */ + /* if (segment_really_copied_from & (1UL << segnum)) { */ + /* /\* here we can actually have our own modified version, so */ + /* make sure to only copy things that are not modified in our */ + /* segment... (if we do not abort) *\/ */ + /* copy_bk_objs_in_page_from( */ + /* segnum, -1, /\* any page *\/ */ + /* !needs_abort); /\* if we abort, we still want to copy everything *\/ */ + /* } */ + /* } */ + } - segment_really_copied_from |= (1UL << cl->segment_num); - import_objects(cl->segment_num, -1, undo, end); - - copy_bk_objs_in_page_from( - segnum, -1, /* any page */ - !needs_abort); /* if we abort, we still want to copy everything */ - } - - /* last fully validated entry */ - STM_PSEGMENT->last_commit_log_entry = cl; - if (cl == last_cl) - break; - } - assert(cl == last_cl); - - /* OPT_ASSERT(segment_really_copied_from <= ((1UL << NB_SEGMENTS) - 1)); */ - /* int segnum; */ - /* for (segnum = 0; segnum < NB_SEGMENTS; segnum++) { */ - /* if (segment_really_copied_from & (1UL << segnum)) { */ - /* /\* here we can actually have our own modified version, so */ - /* make sure to only copy things that are not modified in our */ - /* segment... (if we do not abort) *\/ */ - /* } */ - /* } */ + /* done with modifications */ + release_modification_lock_set(segments_to_lock); } - /* done with modifications */ - release_modification_lock_set(segments_to_lock); - if (needs_abort) { if (free_if_abort != (void *)-1) free(free_if_abort); @@ -490,6 +511,7 @@ assert(!(bk_obj->stm_flags & GCFLAG_WB_EXECUTED)); dprintf(("write_slowpath(%p): sz=%lu, bk=%p\n", obj, obj_size, bk_obj)); + retry: /* privatize pages: */ /* XXX don't always acquire all locks... */ @@ -540,6 +562,7 @@ /* all pages are either private or we were the first to write to a shared page and therefore got it as our private one */ + /* phew, now add the obj to the write-set and register the backup copy. */ /* XXX: we should not be here at all fiddling with page status diff --git a/c8/test/test_basic.py b/c8/test/test_basic.py --- a/c8/test/test_basic.py +++ b/c8/test/test_basic.py @@ -811,6 +811,38 @@ assert stm_get_char(lp_char_5, 384 - 1) == 'o' + def test_bug3(self): + lp_char_5 = stm_allocate_old(384) + + for i in range(NB_SEGMENTS): + self.start_transaction() + stm_set_char(lp_char_5, '\0', HDR, False) + self.commit_transaction() + + # + self.switch(2) + self.start_transaction() + stm_set_char(lp_char_5, 'i', HDR, False) + self.commit_transaction() + + self.start_transaction() + stm_set_char(lp_char_5, 'x', HDR, False) + + # + self.switch(1) + self.start_transaction() + stm_set_char(lp_char_5, 'a', HDR, False) + self.commit_transaction() + + # + self.switch(0) + self.start_transaction() + assert stm_get_char(lp_char_5, HDR) == 'a' + + # + py.test.raises(Conflict, self.switch, 2) + + def test_repeated_wb(self): lp_char_5 = stm_allocate_old(384) From noreply at buildbot.pypy.org Fri Dec 5 10:40:04 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 10:40:04 +0100 (CET) Subject: [pypy-commit] creflect default: starting to port some more cdata logic Message-ID: <20141205094004.D9C501D2E18@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r157:46722c958fdb Date: 2014-12-05 10:40 +0100 http://bitbucket.org/cffi/creflect/changeset/46722c958fdb/ Log: starting to port some more cdata logic diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -269,7 +269,10 @@ if (ct == NULL) goto done; + Py_INCREF(totype); + ct->ct_itemdescr = totype; ct->ct_size = sizeof(void *); + ct->ct_flags = CT_POINTER; if (totype->ct_flags & CT_VOID) ct->ct_flags |= CT_IS_VOID_PTR; diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -1,18 +1,53 @@ -struct CDataObject_s { +typedef struct { PyObject_HEAD CTypeDescrObject *c_type; char *c_data; PyObject *c_weakreflist; -}; +} CDataObject; -/* +typedef union { + unsigned char m_char; + unsigned short m_short; + unsigned int m_int; + unsigned long m_long; + unsigned long long m_longlong; + float m_float; + double m_double; + long double m_longdouble; +} union_alignment; + +typedef struct { + CDataObject head; + union_alignment alignment; +} CDataObject_casted_primitive; + +typedef struct { + CDataObject head; + union_alignment alignment; +} CDataObject_own_nolength; + +typedef struct { + CDataObject head; + Py_ssize_t length; + union_alignment alignment; +} CDataObject_own_length; + #define CData_Check(ob) (Py_TYPE(ob) == &CData_Type || \ Py_TYPE(ob) == &CDataOwning_Type || \ Py_TYPE(ob) == &CDataOwningGC_Type) #define CDataOwn_Check(ob) (Py_TYPE(ob) == &CDataOwning_Type || \ Py_TYPE(ob) == &CDataOwningGC_Type) -*/ + + +static Py_ssize_t get_array_length(CDataObject *cd) +{ + if (cd->c_type->ct_length < 0) + return ((CDataObject_own_length *)cd)->length; + else + return cd->c_type->ct_length; +} + static void cdata_dealloc(CDataObject *cd) { @@ -25,6 +60,169 @@ #endif } +static void cdataowninggc_dealloc(CDataObject *cd) +{ + abort(); +#if 0 + assert(!(cd->c_type->ct_flags & (CT_IS_PTR_TO_OWNED | + CT_PRIMITIVE_ANY | + CT_STRUCT | CT_UNION))); + PyObject_GC_UnTrack(cd); + + if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ + PyObject *x = (PyObject *)(cd->c_data + 42); + Py_DECREF(x); + } + else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ + ffi_closure *closure = (ffi_closure *)cd->c_data; + PyObject *args = (PyObject *)(closure->user_data); + Py_XDECREF(args); + cffi_closure_free(closure); + } + cdata_dealloc(cd); +#endif +} + +static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg) +{ + abort(); +#if 0 + if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ + PyObject *x = (PyObject *)(cd->c_data + 42); + Py_VISIT(x); + } + else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ + ffi_closure *closure = (ffi_closure *)cd->c_data; + PyObject *args = (PyObject *)(closure->user_data); + Py_VISIT(args); + } + return 0; +#endif +} + +static int cdataowninggc_clear(CDataObject *cd) +{ + abort(); +#if 0 + if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ + PyObject *x = (PyObject *)(cd->c_data + 42); + Py_INCREF(Py_None); + cd->c_data = ((char *)Py_None) - 42; + Py_DECREF(x); + } + else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ + ffi_closure *closure = (ffi_closure *)cd->c_data; + PyObject *args = (PyObject *)(closure->user_data); + closure->user_data = NULL; + Py_XDECREF(args); + } + return 0; +#endif +} + +static PyObject *cdata_repr(CDataObject *cd) +{ + char *extra; + PyObject *result, *s; + + if (cd->c_type->ct_flags & CT_PRIMITIVE_ANY) { + abort();//XXX +#if 0 + if (cd->c_type->ct_flags & CT_IS_ENUM) { + s = convert_cdata_to_enum_string(cd, 1); + } + else if (cd->c_type->ct_flags & CT_IS_LONGDOUBLE) { + long double lvalue; + char buffer[128]; /* big enough */ + /*READ(cd->c_data, sizeof(long double)*/ + lvalue = read_raw_longdouble_data(cd->c_data); + sprintf(buffer, "%LE", lvalue); + s = PyText_FromString(buffer); + } + else { + PyObject *o = convert_to_object(cd->c_data, cd->c_type); + if (o == NULL) + return NULL; + s = PyObject_Repr(o); + Py_DECREF(o); + } +#endif + } + else if ((cd->c_type->ct_flags & CT_ARRAY) && cd->c_type->ct_length < 0) { + s = PyString_FromFormat("sliced length %zd", get_array_length(cd)); + } + else { + if (cd->c_data != NULL) { + s = PyString_FromFormat("%p", cd->c_data); + } + else + s = PyString_FromString("NULL"); + } + if (s == NULL) + return NULL; + /* it's slightly confusing to get "" because the + struct foo is not owned. Trying to make it clearer, write in this + case "". */ + if (cd->c_type->ct_flags & (CT_STRUCT|CT_UNION)) + extra = " &"; + else + extra = ""; + result = PyString_FromFormat("", + cd->c_type->ct_name, extra, + PyString_AsString(s)); + Py_DECREF(s); + return result; +} + +static PyObject *_cdata_repr2(CDataObject *cd, char *text, PyObject *x) +{ + PyObject *res, *s = PyObject_Repr(x); + if (s == NULL) + return NULL; + res = PyString_FromFormat("", + cd->c_type->ct_name, text, PyString_AsString(s)); + Py_DECREF(s); + return res; +} + +static PyObject *cdataowning_repr(CDataObject *cd) +{ + Py_ssize_t size; + if (cd->c_type->ct_flags & CT_POINTER) { + if (cd->c_type->ct_flags & CT_IS_VOID_PTR) + goto handle_repr; + size = cd->c_type->ct_itemdescr->ct_size; + } + else if (cd->c_type->ct_flags & CT_ARRAY) + size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size; +#if 0 // XXX + else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) + goto callback_repr; +#endif + else + size = cd->c_type->ct_size; + + return PyString_FromFormat("", + cd->c_type->ct_name, size); + +#if 0 + callback_repr: + { + PyObject *args = (PyObject *)((ffi_closure *)cd->c_data)->user_data; + if (args == NULL) + return cdata_repr(cd); + else + return _cdata_repr2(cd, "calling", PyTuple_GET_ITEM(args, 1)); + } +#endif + + handle_repr: + { + PyObject *x = (PyObject *)(cd->c_data + 42); + return _cdata_repr2(cd, "handle to", x); + } +} + static PyTypeObject CData_Type = { PyVarObject_HEAD_INIT(NULL, 0) "zeffir.CData", @@ -35,7 +233,7 @@ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ - 0,//(reprfunc)cdata_repr, /* tp_repr */ + (reprfunc)cdata_repr, /* tp_repr */ 0,//&CData_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ 0,//&CData_as_mapping, /* tp_as_mapping */ @@ -54,3 +252,86 @@ 0,//(getiterfunc)cdata_iter, /* tp_iter */ 0, /* tp_iternext */ }; + +static PyTypeObject CDataOwning_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "zeffir.CDataOwn", + sizeof(CDataObject), + 0, + (destructor)cdata_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)cdataowning_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0,//&CDataOwn_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &CData_Type, /* tp_base */ +}; + +static PyTypeObject CDataOwningGC_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "zeffir.CDataOwnGC", + sizeof(CDataObject), + 0, + (destructor)cdataowninggc_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES /* tp_flags */ + | Py_TPFLAGS_HAVE_GC, + 0, /* tp_doc */ + (traverseproc)cdataowninggc_traverse, /* tp_traverse */ + (inquiry)cdataowninggc_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &CDataOwning_Type, /* tp_base */ +}; + +static CDataObject *allocate_owning_object(Py_ssize_t size, + CTypeDescrObject *ct) +{ + CDataObject *cd; + cd = (CDataObject *)PyObject_Malloc(size); + if (PyObject_Init((PyObject *)cd, &CDataOwning_Type) == NULL) + return NULL; + + Py_INCREF(ct); + cd->c_type = ct; + cd->c_weakreflist = NULL; + return cd; +} diff --git a/zeffir/ctype.c b/zeffir/ctype.c --- a/zeffir/ctype.c +++ b/zeffir/ctype.c @@ -16,7 +16,6 @@ #define CT_CAST_ANYTHING 2048 /* 'char *' and 'void *' only */ #define CT_PRIMITIVE_FITS_LONG 4096 #define CT_IS_ENUM 8192 -#define CT_IS_PTR_TO_OWNED 16384 #define CT_IS_LONGDOUBLE 65536 #define CT_IS_BOOL 131072 #define CT_IS_VOID_PTR 524288 diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -35,7 +35,7 @@ static PyObject *ffiobj_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { char *keywords[] = {NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "", keywords)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, ":FFI", keywords)) return NULL; PyObject *dict = PyDict_New(); @@ -62,7 +62,7 @@ PyObject *path; ZefLibObject *lib; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|z", keywords, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|z:load_library", keywords, &libname, &relative_to)) return NULL; @@ -100,7 +100,7 @@ { ZefLibObject *lib; - if (!PyArg_ParseTuple(args, "O!", &lib, &ZefLib_Type)) + if (!PyArg_ParseTuple(args, "O!:close_library", &lib, &ZefLib_Type)) return NULL; if (lib_close(lib) < 0) @@ -110,12 +110,18 @@ return Py_None; } -static CTypeDescrObject *_ffi_type(ZefFFIObject *ffi, PyObject *arg) +#define ACCEPT_STRING 1 +#define ACCEPT_CTYPE 2 +#define ACCEPT_CDATA 4 +#define ACCEPT_ALL (ACCEPT_STRING | ACCEPT_CTYPE | ACCEPT_CDATA) + +static CTypeDescrObject *_ffi_type(ZefFFIObject *ffi, PyObject *arg, + int accept) { /* Returns the CTypeDescrObject from the user-supplied 'arg'. Does not return a new reference! */ - if (PyString_Check(arg)) { + if ((accept & ACCEPT_STRING) && PyString_Check(arg)) { PyObject *x = PyDict_GetItem(ffi->types_dict, arg); if (x != NULL && CTypeDescr_Check(x)) return (CTypeDescrObject *)x; @@ -130,24 +136,34 @@ Py_DECREF(x); return ct; } - else if (CTypeDescr_Check(arg)) { + else if ((accept & ACCEPT_CTYPE) && CTypeDescr_Check(arg)) { return (CTypeDescrObject *)arg; } + else if ((accept & ACCEPT_CDATA) && CData_Check(arg)) { + return ((CDataObject *)arg)->c_type; + } else { - PyErr_SetString(PyExc_TypeError, "expected a string or a ctype object"); + const char *m1 = (accept & ACCEPT_STRING) ? "string" : ""; + const char *m2 = (accept & ACCEPT_CTYPE) ? "ctype object" : ""; + const char *m3 = (accept & ACCEPT_CDATA) ? "cdata object" : ""; + const char *s12 = (*m1 && (*m2 || *m3)) ? " or " : ""; + const char *s23 = (*m2 && *m3) ? " or " : ""; + PyErr_Format(PyExc_TypeError, "expected a %s%s%s%s%s, got '%.200s'", + m1, s12, m2, s23, m3, + Py_TYPE(arg)->tp_name); return NULL; } } static PyObject *ffi_sizeof(ZefFFIObject *self, PyObject *arg) { - CTypeDescrObject *ct = _ffi_type(self, arg); + CTypeDescrObject *ct = _ffi_type(self, arg, ACCEPT_ALL); if (ct == NULL) return NULL; if (ct->ct_size < 0) { - PyErr_Format(ZefError, "don't know the size of ctype '%s': " - "incomplete type", ct->ct_name); + PyErr_Format(ZefError, "don't know the size of ctype '%s'", + ct->ct_name); return NULL; } return PyInt_FromSsize_t(ct->ct_size); @@ -155,20 +171,97 @@ static PyObject *ffi_typeof(ZefFFIObject *self, PyObject *arg) { - if (!PyString_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "expected a string"); + PyObject *x = (PyObject *)_ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CDATA); + Py_XINCREF(x); + return x; +} + +static PyObject *ffi_new(ZefFFIObject *self, PyObject *args) +{ + CTypeDescrObject *ct, *ctitem; + CDataObject *cd; + PyObject *arg, *init = Py_None; + Py_ssize_t dataoffset, datasize, explicitlength; + if (!PyArg_ParseTuple(args, "O|O:new", &arg, &init)) + return NULL; + + ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE); + if (ct == NULL) + return NULL; + + explicitlength = -1; + if (ct->ct_flags & CT_POINTER) { + dataoffset = offsetof(CDataObject_own_nolength, alignment); + ctitem = ct->ct_itemdescr; + datasize = ctitem->ct_size; + if (datasize < 0) { + PyErr_Format(PyExc_TypeError, + "cannot instantiate ctype '%s' of unknown size", + ctitem->ct_name); + return NULL; + } + if (ctitem->ct_flags & CT_PRIMITIVE_CHAR) + datasize *= 2; /* forcefully add another character: a null */ + + /* XXX + if ((ctitem->ct_flags & CT_WITH_VAR_ARRAY) && init != Py_None) { + Py_ssize_t optvarsize = datasize; + if (convert_struct_from_object(NULL,ctitem, init, &optvarsize) < 0) + return NULL; + datasize = optvarsize; + }*/ + } + /* XXX + else if (ct->ct_flags & CT_ARRAY) { + dataoffset = offsetof(CDataObject_own_nolength, alignment); + datasize = ct->ct_size; + if (datasize < 0) { + explicitlength = get_new_array_length(&init); + if (explicitlength < 0) + return NULL; + ctitem = ct->ct_itemdescr; + dataoffset = offsetof(CDataObject_own_length, alignment); + datasize = explicitlength * ctitem->ct_size; + if (explicitlength > 0 && + (datasize / explicitlength) != ctitem->ct_size) { + PyErr_SetString(PyExc_OverflowError, + "array size would overflow a Py_ssize_t"); + return NULL; + } + } + }*/ + else { + PyErr_Format(PyExc_TypeError, + "expected a pointer or array ctype, got '%s'", + ct->ct_name); return NULL; } - PyObject *x = (PyObject *)_ffi_type(self, arg); - Py_XINCREF(x); - return x; + cd = allocate_owning_object(dataoffset + datasize, ct); + if (cd == NULL) + return NULL; + + cd->c_data = ((char *)cd) + dataoffset; + if (explicitlength >= 0) + ((CDataObject_own_length*)cd)->length = explicitlength; + + memset(cd->c_data, 0, datasize); + if (init != Py_None) { + /* XXX + if (convert_from_object(cd->c_data, + (ct->ct_flags & CT_POINTER) ? ct->ct_itemdescr : ct, init) < 0) { + Py_DECREF(cd); + return NULL; + }*/ + } + return (PyObject *)cd; } static PyMethodDef ffi_methods[] = { {"close_library", ffi_close_library, METH_VARARGS | METH_STATIC}, {"load_library", (PyCFunction)ffi_load_library, METH_VARARGS | METH_KEYWORDS}, + {"new", (PyCFunction)ffi_new, METH_VARARGS}, {"sizeof", (PyCFunction)ffi_sizeof, METH_O}, {"typeof", (PyCFunction)ffi_typeof, METH_O}, {NULL} diff --git a/zeffir/test/test_cdata.py b/zeffir/test/test_cdata.py new file mode 100644 --- /dev/null +++ b/zeffir/test/test_cdata.py @@ -0,0 +1,8 @@ +import py +import support + + +def test_simple_new(): + ffi = support.new_ffi() + p = ffi.new("short *") + assert repr(p) == "" diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c --- a/zeffir/zeffir.c +++ b/zeffir/zeffir.c @@ -42,6 +42,10 @@ return; if (PyType_Ready(&CData_Type) < 0) return; + if (PyType_Ready(&CDataOwning_Type) < 0) + return; + if (PyType_Ready(&CDataOwningGC_Type) < 0) + return; if (PyType_Ready(&ZefFuncSupport_Type) < 0) return; if (PyType_Ready(&ZefGlobSupport_Type) < 0) diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h --- a/zeffir/zeffir.h +++ b/zeffir/zeffir.h @@ -1,6 +1,5 @@ typedef struct _crx_type_s CTypeDescrObject; -typedef struct CDataObject_s CDataObject; typedef struct ZefLibObject_s ZefLibObject; typedef struct ZefFFIObject_s ZefFFIObject; @@ -8,8 +7,8 @@ static PyTypeObject CTypeDescr_Type; //static PyTypeObject CField_Type; static PyTypeObject CData_Type; -//static PyTypeObject CDataOwning_Type; -//static PyTypeObject CDataOwningGC_Type; +static PyTypeObject CDataOwning_Type; +static PyTypeObject CDataOwningGC_Type; static PyObject *ZefError; From noreply at buildbot.pypy.org Fri Dec 5 12:19:03 2014 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 5 Dec 2014 12:19:03 +0100 (CET) Subject: [pypy-commit] pypy ufuncapi: refactor, properly allocate via signature dtypes. Still no casting Message-ID: <20141205111903.0DE0A1D257D@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: ufuncapi Changeset: r74825:d5aace1c3418 Date: 2014-12-05 01:54 +0200 http://bitbucket.org/pypy/pypy/changeset/d5aace1c3418/ Log: refactor, properly allocate via signature dtypes. Still no casting diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -561,7 +561,8 @@ self.name, self.nin, len(args_w)) for i in range(self.nin): inargs[i] = convert_to_array(space, args_w[i]) - assert isinstance(inargs[i], W_NDimArray) + for i in inargs: + assert isinstance(i, W_NDimArray) outargs = [None] * self.nout for i in range(len(args_w)-self.nin): out = args_w[i+self.nin] @@ -574,16 +575,23 @@ outargs[i] = out if sig is None: sig = space.wrap(self.signature) - index, dtypes = self.type_resolver(space, inargs, outargs, sig) - outargs = self.alloc_outargs(space, index, inargs, outargs, dtypes) - for i in range(len(outargs)): - assert isinstance(outargs[i], W_NDimArray) - outargs0 = outargs[0] - assert isinstance(outargs0, W_NDimArray) - res_dtype = outargs0.get_dtype() + _dtypes = self.dtypes + if self.match_dtypes: + _dtypes = [i.get_dtype() for i in inargs if isinstance(i, W_NDimArray)] + for i in outargs: + if isinstance(i, W_NDimArray): + _dtypes.append(i.get_dtype()) + else: + _dtypes.append(_dtypes[0]) + index, dtypes = self.type_resolver(space, inargs, outargs, sig, _dtypes) func = self.funcs[index] if not self.core_enabled: # func is going to do all the work, it must accept W_NDimArray args + inargs0 = inargs[0] + assert isinstance(inargs0, W_NDimArray) + outarg_shapes = [inargs0.get_shape()] * self.nargs + inargs, outargs = self.alloc_args(space, inargs, outargs, + dtypes, outarg_shapes) if self.stack_inputs: arglist = space.newlist(list(inargs + outargs)) space.call_args(func, Arguments.frompacked(space, arglist)) @@ -594,121 +602,14 @@ if len(outargs) < 2: return outargs[0] return space.newtuple(outargs) - # Figure out the number of iteration dimensions, which - # is the broadcast result of all the input non-core - # dimensions - broadcast_ndim = 0 - for i in range(len(inargs)): - curarg = inargs[i] - assert isinstance(curarg, W_NDimArray) - n = curarg.ndims() - self.core_num_dims[i] - broadcast_ndim = max(broadcast_ndim, n) - # Figure out the number of iterator creation dimensions, - # which is the broadcast dimensions + all the core dimensions of - # the outputs, so that the iterator can allocate those output - # dimensions following the rules of order='F', for example. - iter_ndim = broadcast_ndim - for i in range(self.nin, self.nargs): - iter_ndim += self.core_num_dims[i]; - # Validate the core dimensions of all the operands, - inner_dimensions = [1] * (self.core_num_dim_ix + 2) - idim = 0 - core_start_dim = 0 - for i in range(self.nin): - curarg = inargs[i] - assert isinstance(curarg, W_NDimArray) - dim_offset = self.core_offsets[i] - num_dims = self.core_num_dims[i] - core_start_dim = curarg.ndims() - num_dims - if core_start_dim >=0: - idim = 0 - else: - idim = -core_start_dim - while(idim < num_dims): - core_dim_index = self.core_dim_ixs[dim_offset + idim] - op_dim_size = curarg.get_shape()[core_start_dim + idim] - if inner_dimensions[core_dim_index + 1] == 1: - inner_dimensions[core_dim_index + 1] = op_dim_size - elif op_dim_size != 1 and inner_dimensions[1 + core_dim_index] != op_dim_size: - raise oefmt(space.w_ValueError, "%s: Operand %d has a " - "mismatch in its core dimension %d, with gufunc " - "signature %s (size %d is different from %d)", - self.name, i, idim, self.signature, op_dim_size, - inner_dimensions[1 + core_dim_index]) - idim += 1 - for i in range(len(outargs)): - curarg = outargs[i] - assert isinstance(curarg, W_NDimArray) - dim_offset = self.core_offsets[i] - num_dims = self.core_num_dims[i] - core_start_dim = curarg.ndims() - num_dims - if core_start_dim < 0: - raise oefmt(space.w_ValueError, "%s: Output operand %d does " - "not have enough dimensions (has %d, gufunc with " - "signature %s requires %d)", self.name, i, - curarg.ndims(), self.signature, num_dims) - if core_start_dim >=0: - idim = 0 - else: - idim = -core_start_dim - while(idim < num_dims): - core_dim_index = self.core_dim_ixs[dim_offset + idim] - op_dim_size = curarg.get_shape()[core_start_dim + idim] - if inner_dimensions[core_dim_index + 1] == 1: - inner_dimensions[core_dim_index + 1] = op_dim_size - elif inner_dimensions[1 + core_dim_index] != op_dim_size: - raise oefmt(space.w_ValueError, "%s: Operand %d has a " - "mismatch in its core dimension %d, with gufunc " - "signature %s (size %d is different from %d)", - self.name, i, idim, self.signature, op_dim_size, - inner_dimensions[1 + core_dim_index]) - idim += 1 - iter_shape = [-1] * (broadcast_ndim + (len(outargs) * iter_ndim)) - j = broadcast_ndim - core_dim_ixs_size = 0 - firstdim = broadcast_ndim - for cnd in self.core_num_dims: - firstdim += cnd - op_axes_arrays = [[-1,] * (self.nin + len(outargs)),] * firstdim - for i in range(self.nin): - # Note that n may be negative if broadcasting - # extends into the core dimensions. - curarg = inargs[i] - assert isinstance(curarg, W_NDimArray) - n = curarg.ndims() - self.core_num_dims[i] - for idim in range(broadcast_ndim): - if idim >= broadcast_ndim -n: - op_axes_arrays[idim][i] = idim - (broadcast_ndim -n) - core_dim_ixs_size += self.core_num_dims[i]; - for i in range(len(outargs)): - curarg = outargs[i] - assert isinstance(curarg, W_NDimArray) - iout = i + self.nin - n = curarg.ndims() - self.core_num_dims[iout] - for idim in range(broadcast_ndim): - if idim >= broadcast_ndim -n: - op_axes_arrays[idim][iout] = idim - (broadcast_ndim -n) - dim_offset = self.core_offsets[iout] - num_dims = self.core_num_dims[iout] - for idim in range(num_dims): - cdi = self.core_dim_ixs[dim_offset + idim] - iter_shape[j] = inner_dimensions[1 + cdi] - op_axes_arrays[j][iout] = n + idim - j += 1 - core_dim_ixs_size += self.core_num_dims[iout]; - # TODO once we support obejct dtypes, - # FAIL with NotImplemented if the other object has - # the __r__ method and has a higher priority than - # the current op (signalling it can handle ndarray's). - - # TODO parse and handle subok - # TODO handle flags, op_flags + iter_shape, outarg_shapes, matched_dims = self.verify_args(space, inargs, outargs) + inargs, outargs = self.alloc_args(space, inargs, outargs, dtypes, + outarg_shapes) w_flags = space.w_None # NOT 'external_loop', we do coalescing by core_num_dims w_op_flags = space.newtuple([space.wrap(r) for r in ['readonly'] * len(inargs)] + \ [space.wrap(r) for r in ['readwrite'] * len(outargs)]) w_op_dtypes = space.w_None w_casting = space.w_None - w_itershape = space.newlist([space.wrap(i) for i in iter_shape]) w_op_axes = space.w_None if self.stack_inputs: @@ -722,16 +623,17 @@ # Unlike numpy, we will not broadcast dims before # the core_ndims rather we use nditer iteration # so dims[0] == 1 - dims = [1] + inner_dimensions[1:] + dims = [1] + matched_dims steps = [] allargs = inargs + outargs - assert core_start_dim >= 0 for i in range(len(allargs)): steps.append(0) for i in range(len(allargs)): _arg = allargs[i] assert isinstance(_arg, W_NDimArray) - steps += _arg.implementation.strides[core_start_dim:] + start_dim = len(_arg.get_shape()) - len(iter_shape) + assert start_dim >= 0 + steps += _arg.implementation.strides[start_dim:] #print 'set_dims_and_steps with dims, steps',dims,steps func.set_dims_and_steps(space, dims, steps) else: @@ -739,6 +641,7 @@ # from frompyfunc pass # mimic NpyIter_AdvancedNew with a nditer + w_itershape = space.newlist([space.wrap(i) for i in iter_shape]) nd_it = W_NDIter(space, space.newlist(inargs + outargs), w_flags, w_op_flags, w_op_dtypes, w_casting, w_op_axes, w_itershape) @@ -770,7 +673,10 @@ return space.newtuple([convert_to_array(space, o) for o in outargs]) return outargs[0] inargs0 = inargs[0] + outargs0 = outargs[0] assert isinstance(inargs0, W_NDimArray) + assert isinstance(outargs0, W_NDimArray) + res_dtype = outargs0.get_dtype() new_shape = inargs0.get_shape() if len(outargs) < 2: return loop.call_many_to_one(space, new_shape, func, @@ -808,8 +714,8 @@ kwargs_w.pop(kw) return w_subok, w_out, sig, casting, extobj - def type_resolver(self, space, inargs, outargs, type_tup): - # Find a match for the inargs.dtype in self.dtypes, like + def type_resolver(self, space, inargs, outargs, type_tup, _dtypes): + # Find a match for the inargs.dtype in _dtypes, like # linear_search_type_resolver in numpy ufunc_type_resolutions.c # type_tup can be '', a tuple of dtypes, or a string # of the form d,t -> D where the letters are dtype specs @@ -831,7 +737,7 @@ " after the -> sign, not '%s'", self.name, self.nin, self.nout, type_tup) else: - # XXX does not pass translation + # XXX why does the next line not pass translation? # dtypes = [i.get_dtype() for i in inargs] for i in inargs: if isinstance(i, W_NDimArray): @@ -843,39 +749,164 @@ dtypes.append(i.get_dtype()) else: dtypes.append(None) - #Find the first matchup of dtypes with self.dtypes - for i in range(0, len(self.dtypes), self.nargs): + #Find the first matchup of dtypes with _dtypes + for i in range(0, len(_dtypes), self.nargs): allok = True for j in range(self.nargs): - if dtypes[j] is not None and dtypes[j] != self.dtypes[i+j]: + if dtypes[j] is not None and dtypes[j] != _dtypes[i+j]: allok = False if allok: break else: - if len(self.funcs) < 2: - return 0, dtypes - raise oefmt(space.w_TypeError, - 'input dtype did not match any known dtypes', - ) + if len(self.funcs) > 1: + raise oefmt(space.w_TypeError, + 'input dtype did not match any known dtypes', + ) + i = 0 # Fill in empty dtypes for j in range(self.nargs): if dtypes[j] is None: - dtypes[j] = self.dtypes[i+j] + dtypes[j] = _dtypes[i+j] return i / self.nargs, dtypes - def alloc_outargs(self, space, index, inargs, outargs, dtypes): - # Any None outarg should be allocated here + def alloc_args(self, space, inargs, outargs, dtypes, outarg_shapes): + # Any None outarg are allocated, and inargs, outargs may need casting inargs0 = inargs[0] assert isinstance(inargs0, W_NDimArray) - temp_shape = inargs0.get_shape() # XXX wrong!!! - dtype = inargs0.get_dtype() # XXX wrong!!! order = inargs0.get_order() for i in range(len(outargs)): if outargs[i] is None: - outargs[i] = W_NDimArray.from_shape(space, temp_shape, dtype, order) + j = self.nin + i + outargs[i] = W_NDimArray.from_shape(space, outarg_shapes[i], dtypes[j], order) + for i in outargs: + assert isinstance(i, W_NDimArray) + return inargs, outargs + + def verify_args(self, space, inargs, outargs): + # Figure out the number of iteration dimensions, which + # is the broadcast result of all the input non-core + # dimensions + iter_shape = [] + max_matched_dims = 0 + for i in self.core_dim_ixs: + if i > max_matched_dims: + max_matched_dims = i + matched_dims = [-1] * (1 + max_matched_dims) + for i in range(self.nin): + curarg = inargs[i] + assert isinstance(curarg, W_NDimArray) + dim_offset = self.core_offsets[i] # index into XXX_ixs + num_dims = self.core_num_dims[i] + # Make sure the last num_dims shape of curarg match the signature + n = len(curarg.get_shape()) - num_dims + if n < 0: + raise oefmt(space.w_ValueError, "%s: Input operand %d does " + "not have enough dimensions (has %d, gufunc with " + "signature %s requires %d)", self.name, i, + num_dims+n, self.signature, num_dims) + dims_to_match = curarg.get_shape()[n:] + dims_to_broadcast = curarg.get_shape()[:n] + offset = len(dims_to_broadcast) - len(iter_shape) + if offset >= 0: + # Prepend extra dimensions to iter_shape + iter_shape = dims_to_broadcast[:offset] + iter_shape + offset = 0 + # Make sure iter_shape[offset:] matches dims_to_broadcast + offset = abs(offset) # for translation + for j in range(offset, len(iter_shape)): + x = iter_shape[j + offset] + y = dims_to_broadcast[j] + if (x > y and x % y) or y %x: + raise oefmt(space.w_ValueError, "%s: Operand %d has a " + "mismatch in its broadcast dimension %d " + "(size %d is different from %d)", + self.name, i, j, x, y) + iter_shape[offset + j] = max(x, y) + # Find or verify signature ixs + for j in range(num_dims): + core_dim_index = self.core_dim_ixs[dim_offset + j] + if core_dim_index > len(dims_to_match): + raise oefmt(space.w_ValueError, "%s: Operand %d has a " + "mismatch in its core dimension %d, with gufunc " + "signature %s (index is larger than input shape)", + self.name, i, j, self.signature, core_dim_index) + if matched_dims[core_dim_index] < 0: + matched_dims[core_dim_index] = dims_to_match[j] + elif matched_dims[core_dim_index] != dims_to_match[j]: + raise oefmt(space.w_ValueError, "%s: Operand %d has a " + "mismatch in its core dimension %d, with gufunc " + "signature %s (expected %d, got %d)", + self.name, i, j, + self.signature, matched_dims[core_dim_index], + dims_to_match[j]) + outarg_shapes = [] for i in range(len(outargs)): - assert isinstance(outargs[i], W_NDimArray) - return outargs + curarg = outargs[i] + dim_offset = self.core_offsets[i] + num_dims = self.core_num_dims[i] + if not isinstance(curarg, W_NDimArray): + arg_shape = iter_shape + for j in range(num_dims): + core_dim_index = self.core_dim_ixs[dim_offset + j] + if matched_dims[core_dim_index] < 0: + raise oefmt(space.w_ValueError, "%s: Output operand %d " + "is empty but unique core dimension %d in signature " + "%s of gufunc was not specified", + self.name, i, core_dim_index, self.signature) + arg_shape.append(matched_dims[core_dim_index]) + outarg_shapes.append(arg_shape) + continue + n = len(curarg.get_shape()) - num_dims + if n < 0: + raise oefmt(space.w_ValueError, "%s: Output operand %d does " + "not have enough dimensions (has %d, gufunc with " + "signature %s requires %d)", self.name, i, + num_dims+n, self.signature, num_dims) + dims_to_match = curarg.get_shape()[n:] + dims_to_broadcast = curarg.get_shape()[:n] + offset = len(dims_to_broadcast) - len(iter_shape) + if offset >= 0: + # Prepend extra dimensions to iter_shape, matched_dims + iter_shape = dims_to_broadcast[:offset] + iter_shape + outarg_shapes = [dims_to_broadcast[:offset] + asp for asp in outarg_shapes] + offset = 0 + # Make sure iter_shape[offset:] matches dims_to_broadcast + offset = abs(offset) # for translation + for j in range(offset, len(iter_shape)): + x = iter_shape[j + offset] + y = dims_to_broadcast[j] + if (x > y and x % y) or y %x: + raise oefmt(space.w_ValueError, "%s: Operand %d has a " + "mismatch in its broadcast dimension %d " + "(size %d is different from %d)", + self.name, i, j, x, y) + iter_shape[offset + j] = max(x, y) + # Find or verify signature ixs + for j in range(num_dims): + core_dim_index = self.core_dim_ixs[dim_offset + j] + if core_dim_index > len(dims_to_match): + raise oefmt(space.w_ValueError, "%s: Operand %d has a " + "mismatch in its core dimension %d, with gufunc " + "signature %s (index is larger than input shape)", + self.name, i, j, self.signature, core_dim_index) + if matched_dims[core_dim_index] < 0: + matched_dims[core_dim_index] = dims_to_match[core_dim_index] + elif matched_dims[core_dim_index] != dims_to_match[core_dim_index]: + raise oefmt(space.w_ValueError, "%s: Operand %d has a " + "mismatch in its core dimension %d, with gufunc " + "signature %s (expected %d, got %d)", + self.name, i, core_dim_index + num_dims, + self.signature, matched_dims[core_dim_index], + dims_to_match[core_dim_index]) + outarg_shapes.append(iter_shape + dims_to_match) + # TODO once we support obejct dtypes, + # FAIL with NotImplemented if the other object has + # the __r__ method and has a higher priority than + # the current op (signalling it can handle ndarray's). + + # TODO parse and handle subok + # TODO handle flags, op_flags + return iter_shape, outarg_shapes, matched_dims W_Ufunc.typedef = TypeDef("numpy.ufunc", __call__ = interp2app(W_Ufunc.descr_call), From noreply at buildbot.pypy.org Fri Dec 5 12:19:04 2014 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 5 Dec 2014 12:19:04 +0100 (CET) Subject: [pypy-commit] pypy ufuncapi: simplify, test for not-implemented need to cast args Message-ID: <20141205111904.468851D257D@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: ufuncapi Changeset: r74826:384b1e427559 Date: 2014-12-05 08:28 +0200 http://bitbucket.org/pypy/pypy/changeset/384b1e427559/ Log: simplify, test for not-implemented need to cast args diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -590,8 +590,10 @@ inargs0 = inargs[0] assert isinstance(inargs0, W_NDimArray) outarg_shapes = [inargs0.get_shape()] * self.nargs - inargs, outargs = self.alloc_args(space, inargs, outargs, + inargs, outargs, need_to_cast = self.alloc_args(space, inargs, outargs, dtypes, outarg_shapes) + if any(need_to_cast): + raise oefmt(space.w_NotImplementedError, "casting not supported yet") if self.stack_inputs: arglist = space.newlist(list(inargs + outargs)) space.call_args(func, Arguments.frompacked(space, arglist)) @@ -602,9 +604,11 @@ if len(outargs) < 2: return outargs[0] return space.newtuple(outargs) - iter_shape, outarg_shapes, matched_dims = self.verify_args(space, inargs, outargs) - inargs, outargs = self.alloc_args(space, inargs, outargs, dtypes, - outarg_shapes) + iter_shape, arg_shapes, matched_dims = self.verify_args(space, inargs, outargs) + inargs, outargs, need_to_cast = self.alloc_args(space, inargs, outargs, dtypes, + arg_shapes) + if any(need_to_cast): + raise oefmt(space.w_NotImplementedError, "casting not supported yet") w_flags = space.w_None # NOT 'external_loop', we do coalescing by core_num_dims w_op_flags = space.newtuple([space.wrap(r) for r in ['readonly'] * len(inargs)] + \ [space.wrap(r) for r in ['readwrite'] * len(outargs)]) @@ -769,79 +773,49 @@ dtypes[j] = _dtypes[i+j] return i / self.nargs, dtypes - def alloc_args(self, space, inargs, outargs, dtypes, outarg_shapes): + def alloc_args(self, space, inargs, outargs, dtypes, arg_shapes): # Any None outarg are allocated, and inargs, outargs may need casting inargs0 = inargs[0] assert isinstance(inargs0, W_NDimArray) order = inargs0.get_order() + need_to_cast = [] + for i in range(self.nin): + curarg = inargs[i] + assert isinstance(curarg, W_NDimArray) + if len(arg_shapes[i]) != curarg.ndims(): + # XXX reshape (after merge with default) + pass + need_to_cast.append(curarg.get_dtype() == dtypes[i]) for i in range(len(outargs)): + j = self.nin + i if outargs[i] is None: - j = self.nin + i - outargs[i] = W_NDimArray.from_shape(space, outarg_shapes[i], dtypes[j], order) - for i in outargs: - assert isinstance(i, W_NDimArray) - return inargs, outargs + outargs[i] = W_NDimArray.from_shape(space, outarg_shapes[j], dtypes[j], order) + elif len(arg_shapes[i]) != curarg.ndims(): + # XXX reshape (after merge with default) + pass + need_to_cast.append(curarg.get_dtype() == dtypes[j]) + return inargs, outargs, need_to_cast def verify_args(self, space, inargs, outargs): # Figure out the number of iteration dimensions, which # is the broadcast result of all the input non-core # dimensions iter_shape = [] + arg_shapes = [] max_matched_dims = 0 for i in self.core_dim_ixs: if i > max_matched_dims: max_matched_dims = i matched_dims = [-1] * (1 + max_matched_dims) - for i in range(self.nin): - curarg = inargs[i] - assert isinstance(curarg, W_NDimArray) - dim_offset = self.core_offsets[i] # index into XXX_ixs - num_dims = self.core_num_dims[i] - # Make sure the last num_dims shape of curarg match the signature - n = len(curarg.get_shape()) - num_dims - if n < 0: - raise oefmt(space.w_ValueError, "%s: Input operand %d does " - "not have enough dimensions (has %d, gufunc with " - "signature %s requires %d)", self.name, i, - num_dims+n, self.signature, num_dims) - dims_to_match = curarg.get_shape()[n:] - dims_to_broadcast = curarg.get_shape()[:n] - offset = len(dims_to_broadcast) - len(iter_shape) - if offset >= 0: - # Prepend extra dimensions to iter_shape - iter_shape = dims_to_broadcast[:offset] + iter_shape - offset = 0 - # Make sure iter_shape[offset:] matches dims_to_broadcast - offset = abs(offset) # for translation - for j in range(offset, len(iter_shape)): - x = iter_shape[j + offset] - y = dims_to_broadcast[j] - if (x > y and x % y) or y %x: - raise oefmt(space.w_ValueError, "%s: Operand %d has a " - "mismatch in its broadcast dimension %d " - "(size %d is different from %d)", - self.name, i, j, x, y) - iter_shape[offset + j] = max(x, y) - # Find or verify signature ixs - for j in range(num_dims): - core_dim_index = self.core_dim_ixs[dim_offset + j] - if core_dim_index > len(dims_to_match): - raise oefmt(space.w_ValueError, "%s: Operand %d has a " - "mismatch in its core dimension %d, with gufunc " - "signature %s (index is larger than input shape)", - self.name, i, j, self.signature, core_dim_index) - if matched_dims[core_dim_index] < 0: - matched_dims[core_dim_index] = dims_to_match[j] - elif matched_dims[core_dim_index] != dims_to_match[j]: - raise oefmt(space.w_ValueError, "%s: Operand %d has a " - "mismatch in its core dimension %d, with gufunc " - "signature %s (expected %d, got %d)", - self.name, i, j, - self.signature, matched_dims[core_dim_index], - dims_to_match[j]) - outarg_shapes = [] - for i in range(len(outargs)): - curarg = outargs[i] + for i in range(len(inargs) + len(outargs)): + if i < len(inargs): + _i = i + name = 'Input' + curarg = inargs[i] + else: + _i = i + self.nin + name = 'Output' + curarg = outargs[_i] dim_offset = self.core_offsets[i] num_dims = self.core_num_dims[i] if not isinstance(curarg, W_NDimArray): @@ -849,18 +823,18 @@ for j in range(num_dims): core_dim_index = self.core_dim_ixs[dim_offset + j] if matched_dims[core_dim_index] < 0: - raise oefmt(space.w_ValueError, "%s: Output operand %d " + raise oefmt(space.w_ValueError, "%s: %s operand %d " "is empty but unique core dimension %d in signature " "%s of gufunc was not specified", - self.name, i, core_dim_index, self.signature) + self.name, name, _i, core_dim_index, self.signature) arg_shape.append(matched_dims[core_dim_index]) - outarg_shapes.append(arg_shape) + arg_shapes.append(arg_shape) continue n = len(curarg.get_shape()) - num_dims if n < 0: - raise oefmt(space.w_ValueError, "%s: Output operand %d does " + raise oefmt(space.w_ValueError, "%s: %s operand %d does " "not have enough dimensions (has %d, gufunc with " - "signature %s requires %d)", self.name, i, + "signature %s requires %d)", self.name, name, _i, num_dims+n, self.signature, num_dims) dims_to_match = curarg.get_shape()[n:] dims_to_broadcast = curarg.get_shape()[:n] @@ -876,37 +850,37 @@ x = iter_shape[j + offset] y = dims_to_broadcast[j] if (x > y and x % y) or y %x: - raise oefmt(space.w_ValueError, "%s: Operand %d has a " + raise oefmt(space.w_ValueError, "%s: %s operand %d has a " "mismatch in its broadcast dimension %d " "(size %d is different from %d)", - self.name, i, j, x, y) + self.name, name, _i, j, x, y) iter_shape[offset + j] = max(x, y) # Find or verify signature ixs for j in range(num_dims): core_dim_index = self.core_dim_ixs[dim_offset + j] if core_dim_index > len(dims_to_match): - raise oefmt(space.w_ValueError, "%s: Operand %d has a " + raise oefmt(space.w_ValueError, "%s: %s operand %d has a " "mismatch in its core dimension %d, with gufunc " "signature %s (index is larger than input shape)", - self.name, i, j, self.signature, core_dim_index) + self.name, name, _i, j, self.signature, core_dim_index) if matched_dims[core_dim_index] < 0: matched_dims[core_dim_index] = dims_to_match[core_dim_index] elif matched_dims[core_dim_index] != dims_to_match[core_dim_index]: - raise oefmt(space.w_ValueError, "%s: Operand %d has a " + raise oefmt(space.w_ValueError, "%s: %s operand %d has a " "mismatch in its core dimension %d, with gufunc " "signature %s (expected %d, got %d)", - self.name, i, core_dim_index + num_dims, + self.name, name, _i, core_dim_index + num_dims, self.signature, matched_dims[core_dim_index], dims_to_match[core_dim_index]) - outarg_shapes.append(iter_shape + dims_to_match) + arg_shapes.append(iter_shape + dims_to_match) # TODO once we support obejct dtypes, - # FAIL with NotImplemented if the other object has + # FAIL with NotImplementedError if the other object has # the __r__ method and has a higher priority than # the current op (signalling it can handle ndarray's). # TODO parse and handle subok # TODO handle flags, op_flags - return iter_shape, outarg_shapes, matched_dims + return iter_shape, arg_shapes, matched_dims W_Ufunc.typedef = TypeDef("numpy.ufunc", __call__ = interp2app(W_Ufunc.descr_call), From noreply at buildbot.pypy.org Fri Dec 5 12:19:08 2014 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 5 Dec 2014 12:19:08 +0100 (CET) Subject: [pypy-commit] pypy ufuncapi: merge default into branch Message-ID: <20141205111908.8E9321D257D@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: ufuncapi Changeset: r74827:8f7cc875fd26 Date: 2014-12-05 08:50 +0200 http://bitbucket.org/pypy/pypy/changeset/8f7cc875fd26/ Log: merge default into branch diff too long, truncating to 2000 out of 8352 lines diff --git a/lib-python/2.7/subprocess.py b/lib-python/2.7/subprocess.py --- a/lib-python/2.7/subprocess.py +++ b/lib-python/2.7/subprocess.py @@ -655,6 +655,21 @@ """Create new Popen instance.""" _cleanup() + # --- PyPy hack, see _pypy_install_libs_after_virtualenv() --- + # match arguments passed by different versions of virtualenv + if args[1:] in ( + ['-c', 'import sys; print(sys.prefix)'], # 1.6 10ba3f3c + ['-c', "\nimport sys\nprefix = sys.prefix\n" # 1.7 0e9342ce + "if sys.version_info[0] == 3:\n" + " prefix = prefix.encode('utf8')\n" + "if hasattr(sys.stdout, 'detach'):\n" + " sys.stdout = sys.stdout.detach()\n" + "elif hasattr(sys.stdout, 'buffer'):\n" + " sys.stdout = sys.stdout.buffer\nsys.stdout.write(prefix)\n"], + ['-c', 'import sys;out=sys.stdout;getattr(out, "buffer"' + ', out).write(sys.prefix.encode("utf-8"))']): # 1.7.2 a9454bce + _pypy_install_libs_after_virtualenv(args[0]) + if not isinstance(bufsize, (int, long)): raise TypeError("bufsize must be an integer") @@ -1560,6 +1575,27 @@ self.send_signal(signal.SIGKILL) +def _pypy_install_libs_after_virtualenv(target_executable): + # https://bitbucket.org/pypy/pypy/issue/1922/future-proofing-virtualenv + # + # PyPy 2.4.1 turned --shared on by default. This means the pypy binary + # depends on the 'libpypy-c.so' shared library to be able to run. + # The virtualenv code existing at the time did not account for this + # and would break. Try to detect that we're running under such a + # virtualenv in the "Testing executable with" phase and copy the + # library ourselves. + caller = sys._getframe(2) + if ('virtualenv_version' in caller.f_globals and + 'copyfile' in caller.f_globals): + dest_dir = sys.pypy_resolvedirof(target_executable) + src_dir = sys.pypy_resolvedirof(sys.executable) + for libname in ['libpypy-c.so']: + dest_library = os.path.join(dest_dir, libname) + src_library = os.path.join(src_dir, libname) + if os.path.exists(src_library): + caller.f_globals['copyfile'](src_library, dest_library) + + def _demo_posix(): # # Example 1: Simple redirection: Get process list diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -205,23 +205,28 @@ The above is true both in CPython and in PyPy. Differences can occur about whether a built-in function or method will call an overridden method of *another* object than ``self``. -In PyPy, they are generally always called, whereas not in -CPython. For example, in PyPy, ``dict1.update(dict2)`` -considers that ``dict2`` is just a general mapping object, and -will thus call overridden ``keys()`` and ``__getitem__()`` -methods on it. So the following code prints ``42`` on PyPy -but ``foo`` on CPython:: +In PyPy, they are often called in cases where CPython would not. +Two examples:: - >>>> class D(dict): - .... def __getitem__(self, key): - .... return 42 - .... - >>>> - >>>> d1 = {} - >>>> d2 = D(a='foo') - >>>> d1.update(d2) - >>>> print d1['a'] - 42 + class D(dict): + def __getitem__(self, key): + return "%r from D" % (key,) + + class A(object): + pass + + a = A() + a.__dict__ = D() + a.foo = "a's own foo" + print a.foo + # CPython => a's own foo + # PyPy => 'foo' from D + + glob = D(foo="base item") + loc = {} + exec "print foo" in glob, loc + # CPython => base item + # PyPy => 'foo' from D Mutating classes of objects which are already used as dictionary keys @@ -292,6 +297,9 @@ above types will return a value that is computed from the argument, and can thus be larger than ``sys.maxint`` (i.e. it can be an arbitrary long). +Notably missing from the list above are ``str`` and ``unicode``. If your +code relies on comparing strings with ``is``, then it might break in PyPy. + Miscellaneous ------------- diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -1,15 +1,13 @@ -""" -Python control flow graph generation and bytecode assembly. -""" +"""Python control flow graph generation and bytecode assembly.""" -from pypy.interpreter.astcompiler import ast, symtable -from pypy.interpreter import pycode +from rpython.rlib import rfloat +from rpython.rlib.objectmodel import we_are_translated + +from pypy.interpreter.astcompiler import ast, misc, symtable +from pypy.interpreter.error import OperationError +from pypy.interpreter.pycode import PyCode from pypy.tool import stdlib_opcode as ops -from pypy.interpreter.error import OperationError -from rpython.rlib.objectmodel import we_are_translated -from rpython.rlib import rfloat - class Instruction(object): """Represents a single opcode.""" @@ -21,14 +19,12 @@ self.has_jump = False def size(self): - """Return the size of bytes of this instruction when it is encoded.""" + """Return the size of bytes of this instruction when it is + encoded. + """ if self.opcode >= ops.HAVE_ARGUMENT: - if self.arg > 0xFFFF: - return 6 - else: - return 3 - else: - return 1 + return (6 if self.arg > 0xFFFF else 3) + return 1 def jump_to(self, target, absolute=False): """Indicate the target this jump instruction. @@ -54,9 +50,9 @@ class Block(object): """A basic control flow block. - It has one entry point and several possible exit points. Its instructions - may be jumps to other blocks, or if control flow reaches the end of the - block, it continues to next_block. + It has one entry point and several possible exit points. Its + instructions may be jumps to other blocks, or if control flow + reaches the end of the block, it continues to next_block. """ def __init__(self): @@ -71,10 +67,10 @@ stack.append(nextblock) def post_order(self): - """Return this block and its children in post order. - This means that the graph of blocks is first cleaned up to - ignore back-edges, thus turning it into a DAG. Then the DAG - is linearized. For example: + """Return this block and its children in post order. This means + that the graph of blocks is first cleaned up to ignore + back-edges, thus turning it into a DAG. Then the DAG is + linearized. For example: A --> B -\ => [A, D, B, C] \-> D ---> C @@ -105,7 +101,9 @@ return resultblocks def code_size(self): - """Return the encoded size of all the instructions in this block.""" + """Return the encoded size of all the instructions in this + block. + """ i = 0 for instr in self.instructions: i += instr.size() @@ -141,6 +139,7 @@ i += 1 return result + def _list_to_dict(l, offset=0): result = {} index = offset @@ -300,11 +299,11 @@ def _resolve_block_targets(self, blocks): """Compute the arguments of jump instructions.""" last_extended_arg_count = 0 - # The reason for this loop is extended jumps. EXTENDED_ARG extends the - # bytecode size, so it might invalidate the offsets we've already given. - # Thus we have to loop until the number of extended args is stable. Any - # extended jump at all is extremely rare, so performance is not too - # concerning. + # The reason for this loop is extended jumps. EXTENDED_ARG + # extends the bytecode size, so it might invalidate the offsets + # we've already given. Thus we have to loop until the number of + # extended args is stable. Any extended jump at all is + # extremely rare, so performance is not too concerning. while True: extended_arg_count = 0 offset = 0 @@ -330,7 +329,8 @@ instr.opcode = ops.JUMP_ABSOLUTE absolute = True elif target_op == ops.RETURN_VALUE: - # Replace JUMP_* to a RETURN into just a RETURN + # Replace JUMP_* to a RETURN into + # just a RETURN instr.opcode = ops.RETURN_VALUE instr.arg = 0 instr.has_jump = False @@ -345,7 +345,8 @@ instr.arg = jump_arg if jump_arg > 0xFFFF: extended_arg_count += 1 - if extended_arg_count == last_extended_arg_count and not force_redo: + if (extended_arg_count == last_extended_arg_count and + not force_redo): break else: last_extended_arg_count = extended_arg_count @@ -360,12 +361,14 @@ while True: try: w_key = space.next(w_iter) - except OperationError, e: + except OperationError as e: if not e.match(space, space.w_StopIteration): raise break w_index = space.getitem(w_consts, w_key) - consts_w[space.int_w(w_index)] = space.getitem(w_key, first) + w_constant = space.getitem(w_key, first) + w_constant = misc.intern_if_common_string(space, w_constant) + consts_w[space.int_w(w_index)] = w_constant return consts_w def _get_code_flags(self): @@ -433,15 +436,16 @@ continue addr = offset - current_off # Python assumes that lineno always increases with - # increasing bytecode address (lnotab is unsigned char). - # Depending on when SET_LINENO instructions are emitted this - # is not always true. Consider the code: + # increasing bytecode address (lnotab is unsigned + # char). Depending on when SET_LINENO instructions + # are emitted this is not always true. Consider the + # code: # a = (1, # b) - # In the bytecode stream, the assignment to "a" occurs after - # the loading of "b". This works with the C Python compiler - # because it only generates a SET_LINENO instruction for the - # assignment. + # In the bytecode stream, the assignment to "a" + # occurs after the loading of "b". This works with + # the C Python compiler because it only generates a + # SET_LINENO instruction for the assignment. if line or addr: while addr > 255: push(chr(255)) @@ -484,22 +488,22 @@ free_names = _list_from_dict(self.free_vars, len(cell_names)) flags = self._get_code_flags() | self.compile_info.flags bytecode = ''.join([block.get_code() for block in blocks]) - return pycode.PyCode(self.space, - self.argcount, - len(self.var_names), - stack_depth, - flags, - bytecode, - list(consts_w), - names, - var_names, - self.compile_info.filename, - self.name, - self.first_lineno, - lnotab, - free_names, - cell_names, - self.compile_info.hidden_applevel) + return PyCode(self.space, + self.argcount, + len(self.var_names), + stack_depth, + flags, + bytecode, + list(consts_w), + names, + var_names, + self.compile_info.filename, + self.name, + self.first_lineno, + lnotab, + free_names, + cell_names, + self.compile_info.hidden_applevel) def _list_from_dict(d, offset=0): @@ -510,134 +514,134 @@ _static_opcode_stack_effects = { - ops.NOP : 0, - ops.STOP_CODE : 0, + ops.NOP: 0, + ops.STOP_CODE: 0, - ops.POP_TOP : -1, - ops.ROT_TWO : 0, - ops.ROT_THREE : 0, - ops.ROT_FOUR : 0, - ops.DUP_TOP : 1, + ops.POP_TOP: -1, + ops.ROT_TWO: 0, + ops.ROT_THREE: 0, + ops.ROT_FOUR: 0, + ops.DUP_TOP: 1, - ops.UNARY_POSITIVE : 0, - ops.UNARY_NEGATIVE : 0, - ops.UNARY_NOT : 0, - ops.UNARY_CONVERT : 0, - ops.UNARY_INVERT : 0, + ops.UNARY_POSITIVE: 0, + ops.UNARY_NEGATIVE: 0, + ops.UNARY_NOT: 0, + ops.UNARY_CONVERT: 0, + ops.UNARY_INVERT: 0, - ops.LIST_APPEND : -1, - ops.SET_ADD : -1, - ops.MAP_ADD : -2, - ops.STORE_MAP : -2, + ops.LIST_APPEND: -1, + ops.SET_ADD: -1, + ops.MAP_ADD: -2, + ops.STORE_MAP: -2, - ops.BINARY_POWER : -1, - ops.BINARY_MULTIPLY : -1, - ops.BINARY_DIVIDE : -1, - ops.BINARY_MODULO : -1, - ops.BINARY_ADD : -1, - ops.BINARY_SUBTRACT : -1, - ops.BINARY_SUBSCR : -1, - ops.BINARY_FLOOR_DIVIDE : -1, - ops.BINARY_TRUE_DIVIDE : -1, - ops.BINARY_LSHIFT : -1, - ops.BINARY_RSHIFT : -1, - ops.BINARY_AND : -1, - ops.BINARY_OR : -1, - ops.BINARY_XOR : -1, + ops.BINARY_POWER: -1, + ops.BINARY_MULTIPLY: -1, + ops.BINARY_DIVIDE: -1, + ops.BINARY_MODULO: -1, + ops.BINARY_ADD: -1, + ops.BINARY_SUBTRACT: -1, + ops.BINARY_SUBSCR: -1, + ops.BINARY_FLOOR_DIVIDE: -1, + ops.BINARY_TRUE_DIVIDE: -1, + ops.BINARY_LSHIFT: -1, + ops.BINARY_RSHIFT: -1, + ops.BINARY_AND: -1, + ops.BINARY_OR: -1, + ops.BINARY_XOR: -1, - ops.INPLACE_FLOOR_DIVIDE : -1, - ops.INPLACE_TRUE_DIVIDE : -1, - ops.INPLACE_ADD : -1, - ops.INPLACE_SUBTRACT : -1, - ops.INPLACE_MULTIPLY : -1, - ops.INPLACE_DIVIDE : -1, - ops.INPLACE_MODULO : -1, - ops.INPLACE_POWER : -1, - ops.INPLACE_LSHIFT : -1, - ops.INPLACE_RSHIFT : -1, - ops.INPLACE_AND : -1, - ops.INPLACE_OR : -1, - ops.INPLACE_XOR : -1, + ops.INPLACE_FLOOR_DIVIDE: -1, + ops.INPLACE_TRUE_DIVIDE: -1, + ops.INPLACE_ADD: -1, + ops.INPLACE_SUBTRACT: -1, + ops.INPLACE_MULTIPLY: -1, + ops.INPLACE_DIVIDE: -1, + ops.INPLACE_MODULO: -1, + ops.INPLACE_POWER: -1, + ops.INPLACE_LSHIFT: -1, + ops.INPLACE_RSHIFT: -1, + ops.INPLACE_AND: -1, + ops.INPLACE_OR: -1, + ops.INPLACE_XOR: -1, - ops.SLICE+0 : 1, - ops.SLICE+1 : 0, - ops.SLICE+2 : 0, - ops.SLICE+3 : -1, - ops.STORE_SLICE+0 : -2, - ops.STORE_SLICE+1 : -3, - ops.STORE_SLICE+2 : -3, - ops.STORE_SLICE+3 : -4, - ops.DELETE_SLICE+0 : -1, - ops.DELETE_SLICE+1 : -2, - ops.DELETE_SLICE+2 : -2, - ops.DELETE_SLICE+3 : -3, + ops.SLICE+0: 1, + ops.SLICE+1: 0, + ops.SLICE+2: 0, + ops.SLICE+3: -1, + ops.STORE_SLICE+0: -2, + ops.STORE_SLICE+1: -3, + ops.STORE_SLICE+2: -3, + ops.STORE_SLICE+3: -4, + ops.DELETE_SLICE+0: -1, + ops.DELETE_SLICE+1: -2, + ops.DELETE_SLICE+2: -2, + ops.DELETE_SLICE+3: -3, - ops.STORE_SUBSCR : -2, - ops.DELETE_SUBSCR : -2, + ops.STORE_SUBSCR: -2, + ops.DELETE_SUBSCR: -2, - ops.GET_ITER : 0, - ops.FOR_ITER : 1, - ops.BREAK_LOOP : 0, - ops.CONTINUE_LOOP : 0, - ops.SETUP_LOOP : 0, + ops.GET_ITER: 0, + ops.FOR_ITER: 1, + ops.BREAK_LOOP: 0, + ops.CONTINUE_LOOP: 0, + ops.SETUP_LOOP: 0, - ops.PRINT_EXPR : -1, - ops.PRINT_ITEM : -1, - ops.PRINT_NEWLINE : 0, - ops.PRINT_ITEM_TO : -2, - ops.PRINT_NEWLINE_TO : -1, + ops.PRINT_EXPR: -1, + ops.PRINT_ITEM: -1, + ops.PRINT_NEWLINE: 0, + ops.PRINT_ITEM_TO: -2, + ops.PRINT_NEWLINE_TO: -1, - ops.WITH_CLEANUP : -1, - ops.POP_BLOCK : 0, - ops.END_FINALLY : -1, - ops.SETUP_WITH : 1, - ops.SETUP_FINALLY : 0, - ops.SETUP_EXCEPT : 0, + ops.WITH_CLEANUP: -1, + ops.POP_BLOCK: 0, + ops.END_FINALLY: -1, + ops.SETUP_WITH: 1, + ops.SETUP_FINALLY: 0, + ops.SETUP_EXCEPT: 0, - ops.LOAD_LOCALS : 1, - ops.RETURN_VALUE : -1, - ops.EXEC_STMT : -3, - ops.YIELD_VALUE : 0, - ops.BUILD_CLASS : -2, - ops.BUILD_MAP : 1, - ops.BUILD_SET : 1, - ops.COMPARE_OP : -1, + ops.LOAD_LOCALS: 1, + ops.RETURN_VALUE: -1, + ops.EXEC_STMT: -3, + ops.YIELD_VALUE: 0, + ops.BUILD_CLASS: -2, + ops.BUILD_MAP: 1, + ops.BUILD_SET: 1, + ops.COMPARE_OP: -1, - ops.LOOKUP_METHOD : 1, + ops.LOOKUP_METHOD: 1, - ops.LOAD_NAME : 1, - ops.STORE_NAME : -1, - ops.DELETE_NAME : 0, + ops.LOAD_NAME: 1, + ops.STORE_NAME: -1, + ops.DELETE_NAME: 0, - ops.LOAD_FAST : 1, - ops.STORE_FAST : -1, - ops.DELETE_FAST : 0, + ops.LOAD_FAST: 1, + ops.STORE_FAST: -1, + ops.DELETE_FAST: 0, - ops.LOAD_ATTR : 0, - ops.STORE_ATTR : -2, - ops.DELETE_ATTR : -1, + ops.LOAD_ATTR: 0, + ops.STORE_ATTR: -2, + ops.DELETE_ATTR: -1, - ops.LOAD_GLOBAL : 1, - ops.STORE_GLOBAL : -1, - ops.DELETE_GLOBAL : 0, + ops.LOAD_GLOBAL: 1, + ops.STORE_GLOBAL: -1, + ops.DELETE_GLOBAL: 0, - ops.LOAD_CLOSURE : 1, - ops.LOAD_DEREF : 1, - ops.STORE_DEREF : -1, + ops.LOAD_CLOSURE: 1, + ops.LOAD_DEREF: 1, + ops.STORE_DEREF: -1, - ops.LOAD_CONST : 1, + ops.LOAD_CONST: 1, - ops.IMPORT_STAR : -1, - ops.IMPORT_NAME : -1, - ops.IMPORT_FROM : 1, + ops.IMPORT_STAR: -1, + ops.IMPORT_NAME: -1, + ops.IMPORT_FROM: 1, - ops.JUMP_FORWARD : 0, - ops.JUMP_ABSOLUTE : 0, - ops.JUMP_IF_TRUE_OR_POP : 0, - ops.JUMP_IF_FALSE_OR_POP : 0, - ops.POP_JUMP_IF_TRUE : -1, - ops.POP_JUMP_IF_FALSE : -1, - ops.JUMP_IF_NOT_DEBUG : 0, + ops.JUMP_FORWARD: 0, + ops.JUMP_ABSOLUTE: 0, + ops.JUMP_IF_TRUE_OR_POP: 0, + ops.JUMP_IF_FALSE_OR_POP: 0, + ops.POP_JUMP_IF_TRUE: -1, + ops.POP_JUMP_IF_FALSE: -1, + ops.JUMP_IF_NOT_DEBUG: 0, ops.BUILD_LIST_FROM_ARG: 1, } diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -106,3 +106,13 @@ except IndexError: return name return "_%s%s" % (klass[i:], name) + + +def intern_if_common_string(space, w_const): + # only intern identifier-like strings + if not space.is_w(space.type(w_const), space.w_str): + return w_const + for c in space.str_w(w_const): + if not (c.isalnum() or c == '_'): + return w_const + return space.new_interned_w_str(w_const) diff --git a/pypy/interpreter/astcompiler/optimize.py b/pypy/interpreter/astcompiler/optimize.py --- a/pypy/interpreter/astcompiler/optimize.py +++ b/pypy/interpreter/astcompiler/optimize.py @@ -272,6 +272,11 @@ if w_const is None: return tup consts_w[i] = w_const + # intern the string constants packed into the tuple here, + # because assemble.py will see the result as just a tuple constant + for i in range(len(consts_w)): + consts_w[i] = misc.intern_if_common_string( + self.space, consts_w[i]) else: consts_w = [] w_consts = self.space.newtuple(consts_w) diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -14,7 +14,7 @@ UserDelAction) from pypy.interpreter.error import OperationError, new_exception_class, oefmt from pypy.interpreter.argument import Arguments -from pypy.interpreter.miscutils import ThreadLocals +from pypy.interpreter.miscutils import ThreadLocals, make_weak_value_dictionary __all__ = ['ObjSpace', 'OperationError', 'W_Root'] @@ -384,7 +384,7 @@ self.builtin_modules = {} self.reloading_modules = {} - self.interned_strings = {} + self.interned_strings = make_weak_value_dictionary(self, str, W_Root) self.actionflag = ActionFlag() # changed by the signal module self.check_signal_action = None # changed by the signal module self.user_del_action = UserDelAction(self) @@ -777,25 +777,30 @@ return self.w_False def new_interned_w_str(self, w_s): + assert isinstance(w_s, W_Root) # and is not None s = self.str_w(w_s) if not we_are_translated(): assert type(s) is str - try: - return self.interned_strings[s] - except KeyError: - pass - self.interned_strings[s] = w_s - return w_s + w_s1 = self.interned_strings.get(s) + if w_s1 is None: + w_s1 = w_s + self.interned_strings.set(s, w_s1) + return w_s1 def new_interned_str(self, s): if not we_are_translated(): assert type(s) is str - try: - return self.interned_strings[s] - except KeyError: - pass - w_s = self.interned_strings[s] = self.wrap(s) - return w_s + w_s1 = self.interned_strings.get(s) + if w_s1 is None: + w_s1 = self.wrap(s) + self.interned_strings.set(s, w_s1) + return w_s1 + + def is_interned_str(self, s): + # interface for marshal_impl + if not we_are_translated(): + assert type(s) is str + return self.interned_strings.get(s) is not None def descr_self_interp_w(self, RequiredClass, w_obj): if not isinstance(w_obj, RequiredClass): diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py --- a/pypy/interpreter/miscutils.py +++ b/pypy/interpreter/miscutils.py @@ -31,3 +31,19 @@ def getallvalues(self): return {0: self._value} + + +def make_weak_value_dictionary(space, keytype, valuetype): + "NOT_RPYTHON" + if space.config.translation.rweakref: + from rpython.rlib.rweakref import RWeakValueDictionary + return RWeakValueDictionary(keytype, valuetype) + else: + class FakeWeakValueDict(object): + def __init__(self): + self._dict = {} + def get(self, key): + return self._dict.get(key, None) + def set(self, key, value): + self._dict[key] = value + return FakeWeakValueDict() diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -131,7 +131,6 @@ # class bodies only have CO_NEWLOCALS. # CO_NEWLOCALS: make a locals dict unless optimized is also set # CO_OPTIMIZED: no locals dict needed at all - # NB: this method is overridden in nestedscope.py flags = code.co_flags if not (flags & pycode.CO_OPTIMIZED): if flags & pycode.CO_NEWLOCALS: diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -970,7 +970,12 @@ sys.stdout = out output = s.getvalue() assert "CALL_METHOD" in output - + + def test_interned_strings(self): + source = """x = ('foo_bar42', 5); y = 'foo_bar42'; z = x[0]""" + exec source + assert y is z + class AppTestExceptions: def test_indentation_error(self): diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py --- a/pypy/interpreter/test/test_objspace.py +++ b/pypy/interpreter/test/test_objspace.py @@ -378,3 +378,41 @@ assert space.str_w(space.getattr(space.sys, w_executable)) == 'foobar' space.startup() assert space.str_w(space.getattr(space.sys, w_executable)) == 'foobar' + + def test_interned_strings_are_weak(self): + import weakref, gc, random + space = self.space + assert space.config.translation.rweakref + w1 = space.new_interned_str("abcdef") + w2 = space.new_interned_str("abcdef") + assert w2 is w1 + # + # check that 'w1' goes away if we don't hold a reference to it + rw1 = weakref.ref(w1) + del w1, w2 + i = 10 + while rw1() is not None: + i -= 1 + assert i >= 0 + gc.collect() + # + s = "foobar%r" % random.random() + w0 = space.wrap(s) + w1 = space.new_interned_w_str(w0) + assert w1 is w0 + w2 = space.new_interned_w_str(w0) + assert w2 is w0 + w3 = space.wrap(s) + assert w3 is not w0 + w4 = space.new_interned_w_str(w3) + assert w4 is w0 + # + # check that 'w0' goes away if we don't hold a reference to it + # (even if we hold a reference to 'w3') + rw0 = weakref.ref(w0) + del w0, w1, w2, w4 + i = 10 + while rw0() is not None: + i -= 1 + assert i >= 0 + gc.collect() diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -158,21 +158,14 @@ class W_CTypePrimitiveSigned(W_CTypePrimitive): - _attrs_ = ['value_fits_long', 'vmin', 'vrangemax'] - _immutable_fields_ = ['value_fits_long', 'vmin', 'vrangemax'] + _attrs_ = ['value_fits_long', 'value_smaller_than_long'] + _immutable_fields_ = ['value_fits_long', 'value_smaller_than_long'] is_primitive_integer = True def __init__(self, *args): W_CTypePrimitive.__init__(self, *args) self.value_fits_long = self.size <= rffi.sizeof(lltype.Signed) - if self.size < rffi.sizeof(lltype.Signed): - assert self.value_fits_long - sh = self.size * 8 - self.vmin = r_uint(-1) << (sh - 1) - self.vrangemax = (r_uint(1) << sh) - 1 - else: - self.vmin = r_uint(0) - self.vrangemax = r_uint(-1) + self.value_smaller_than_long = self.size < rffi.sizeof(lltype.Signed) def cast_to_int(self, cdata): return self.convert_to_object(cdata) @@ -192,8 +185,17 @@ def convert_from_object(self, cdata, w_ob): if self.value_fits_long: value = misc.as_long(self.space, w_ob) - if self.size < rffi.sizeof(lltype.Signed): - if r_uint(value) - self.vmin > self.vrangemax: + if self.value_smaller_than_long: + size = self.size + if size == 1: + signextended = misc.signext(value, 1) + elif size == 2: + signextended = misc.signext(value, 2) + elif size == 4: + signextended = misc.signext(value, 4) + else: + raise AssertionError("unsupported size") + if value != signextended: self._overflow(w_ob) misc.write_raw_signed_data(cdata, value, self.size) else: @@ -221,7 +223,7 @@ length = w_cdata.get_array_length() populate_list_from_raw_array(res, buf, length) return res - elif self.value_fits_long: + elif self.value_smaller_than_long: res = [0] * w_cdata.get_array_length() misc.unpack_list_from_raw_array(res, w_cdata._cdata, self.size) return res @@ -235,8 +237,8 @@ cdata = rffi.cast(rffi.LONGP, cdata) copy_list_to_raw_array(int_list, cdata) else: - overflowed = misc.pack_list_to_raw_array_bounds( - int_list, cdata, self.size, self.vmin, self.vrangemax) + overflowed = misc.pack_list_to_raw_array_bounds_signed( + int_list, cdata, self.size) if overflowed != 0: self._overflow(self.space.wrap(overflowed)) return True @@ -314,8 +316,8 @@ def pack_list_of_items(self, cdata, w_ob): int_list = self.space.listview_int(w_ob) if int_list is not None: - overflowed = misc.pack_list_to_raw_array_bounds( - int_list, cdata, self.size, r_uint(0), self.vrangemax) + overflowed = misc.pack_list_to_raw_array_bounds_unsigned( + int_list, cdata, self.size, self.vrangemax) if overflowed != 0: self._overflow(self.space.wrap(overflowed)) return True diff --git a/pypy/module/_cffi_backend/misc.py b/pypy/module/_cffi_backend/misc.py --- a/pypy/module/_cffi_backend/misc.py +++ b/pypy/module/_cffi_backend/misc.py @@ -216,6 +216,19 @@ neg_msg = "can't convert negative number to unsigned" ovf_msg = "long too big to convert" + at specialize.arg(1) +def signext(value, size): + # 'value' is sign-extended from 'size' bytes to a full integer. + # 'size' should be a constant smaller than a full integer size. + if size == rffi.sizeof(rffi.SIGNEDCHAR): + return rffi.cast(lltype.Signed, rffi.cast(rffi.SIGNEDCHAR, value)) + elif size == rffi.sizeof(rffi.SHORT): + return rffi.cast(lltype.Signed, rffi.cast(rffi.SHORT, value)) + elif size == rffi.sizeof(rffi.INT): + return rffi.cast(lltype.Signed, rffi.cast(rffi.INT, value)) + else: + raise AssertionError("unsupported size") + # ____________________________________________________________ class _NotStandardObject(Exception): @@ -334,13 +347,26 @@ # ____________________________________________________________ -def pack_list_to_raw_array_bounds(int_list, target, size, vmin, vrangemax): +def pack_list_to_raw_array_bounds_signed(int_list, target, size): for TP, TPP in _prim_signed_types: if size == rffi.sizeof(TP): ptr = rffi.cast(TPP, target) for i in range(len(int_list)): x = int_list[i] - if r_uint(x) - vmin > vrangemax: + y = rffi.cast(TP, x) + if x != rffi.cast(lltype.Signed, y): + return x # overflow + ptr[i] = y + return 0 + raise NotImplementedError("bad integer size") + +def pack_list_to_raw_array_bounds_unsigned(int_list, target, size, vrangemax): + for TP, TPP in _prim_signed_types: + if size == rffi.sizeof(TP): + ptr = rffi.cast(TPP, target) + for i in range(len(int_list)): + x = int_list[i] + if r_uint(x) > vrangemax: return x # overflow ptr[i] = rffi.cast(TP, x) return 0 diff --git a/pypy/module/_file/test/test_file.py b/pypy/module/_file/test/test_file.py --- a/pypy/module/_file/test/test_file.py +++ b/pypy/module/_file/test/test_file.py @@ -304,7 +304,7 @@ py.test.skip("works with internals of _file impl on py.py") state = [0] def read(fd, n=None): - if fd != 42: + if fd != 424242: return cls.old_read(fd, n) if state[0] == 0: state[0] += 1 @@ -315,7 +315,7 @@ return '' os.read = read stdin = W_File(cls.space) - stdin.file_fdopen(42, 'rb', 1) + stdin.file_fdopen(424242, 'rb', 1) stdin.name = '' cls.w_stream = stdin diff --git a/pypy/module/_ssl/thread_lock.py b/pypy/module/_ssl/thread_lock.py --- a/pypy/module/_ssl/thread_lock.py +++ b/pypy/module/_ssl/thread_lock.py @@ -24,12 +24,19 @@ separate_module_source = """ #include +#ifndef _WIN32 +# include +#endif static unsigned int _ssl_locks_count = 0; static struct RPyOpaque_ThreadLock *_ssl_locks; static unsigned long _ssl_thread_id_function(void) { - return RPyThreadGetIdent(); +#ifdef _WIN32 + return (unsigned long)GetCurrentThreadId(); +#else + return (unsigned long)pthread_self(); +#endif } static void _ssl_thread_locking_function(int mode, int n, const char *file, diff --git a/pypy/module/cpyext/src/pythread.c b/pypy/module/cpyext/src/pythread.c --- a/pypy/module/cpyext/src/pythread.c +++ b/pypy/module/cpyext/src/pythread.c @@ -1,11 +1,18 @@ #include +#ifndef _WIN32 +# include +#endif #include "pythread.h" #include "src/thread.h" long PyThread_get_thread_ident(void) { - return RPyThreadGetIdent(); +#ifdef _WIN32 + return (long)GetCurrentThreadId(); +#else + return (long)pthread_self(); +#endif } PyThread_type_lock diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -144,7 +144,6 @@ atom_int(tc, int) puts code and int atom_int64(tc, int64) puts code and int64 atom_str(tc, str) puts code, len and string - atom_strlist(tc, strlist) puts code, len and list of strings building blocks for compound types: @@ -198,15 +197,6 @@ self.atom_int(typecode, len(x)) self.put(x) - def atom_strlist(self, typecode, tc2, x): - self.atom_int(typecode, len(x)) - atom_str = self.atom_str - for item in x: - # type(str) seems to be forbidden - #if type(item) is not str: - # self.raise_exc('object with wrong type in strlist') - atom_str(tc2, item) - def start(self, typecode): # type(char) not supported self.put(typecode) @@ -379,16 +369,6 @@ self.start(typecode) return self.get_lng() - def atom_strlist(self, typecode, tc2): - self.start(typecode) - lng = self.get_lng() - res = [None] * lng - idx = 0 - while idx < lng: - res[idx] = self.atom_str(tc2) - idx += 1 - return res - def start(self, typecode): tc = self.get1() if tc != typecode: @@ -436,7 +416,6 @@ def get_w_obj(self, allow_null=False): space = self.space - w_ret = space.w_None # something not None tc = self.get1() w_ret = self._dispatch[ord(tc)](space, self, tc) if w_ret is None and not allow_null: diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -1,7 +1,7 @@ from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, oefmt from rpython.tool.pairtype import extendabletype - +from pypy.module.micronumpy import support def wrap_impl(space, w_cls, w_instance, impl): if w_cls is None or space.is_w(w_cls, space.gettypefor(W_NDimArray)): @@ -45,11 +45,32 @@ return W_NDimArray(impl) @staticmethod - def from_shape_and_storage(space, shape, storage, dtype, order='C', owning=False, - w_subtype=None, w_base=None, writable=True): + def from_shape_and_storage(space, shape, storage, dtype, storage_bytes=-1, + order='C', owning=False, w_subtype=None, + w_base=None, writable=True, strides=None): from pypy.module.micronumpy import concrete - from pypy.module.micronumpy.strides import calc_strides - strides, backstrides = calc_strides(shape, dtype, order) + from pypy.module.micronumpy.strides import (calc_strides, + calc_backstrides) + isize = dtype.elsize + if storage_bytes > 0 : + totalsize = support.product(shape) * isize + if totalsize > storage_bytes: + raise OperationError(space.w_TypeError, space.wrap( + "buffer is too small for requested array")) + else: + storage_bytes = support.product(shape) * isize + if strides is None: + strides, backstrides = calc_strides(shape, dtype, order) + else: + if len(strides) != len(shape): + raise oefmt(space.w_ValueError, + 'strides, if given, must be the same length as shape') + for i in range(len(strides)): + if strides[i] < 0 or strides[i]*shape[i] > storage_bytes: + raise oefmt(space.w_ValueError, + 'strides is incompatible with shape of requested ' + 'array and size of buffer') + backstrides = calc_backstrides(strides, shape) if w_base is not None: if owning: raise OperationError(space.w_ValueError, diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py --- a/pypy/module/micronumpy/boxes.py +++ b/pypy/module/micronumpy/boxes.py @@ -168,7 +168,7 @@ if len(args_w) >= 1: for w_arg in args_w: try: - idx = support.index_w(space, w_arg) + support.index_w(space, w_arg) except OperationError: raise oefmt(space.w_TypeError, "an integer is required") raise oefmt(space.w_ValueError, "axes don't match array") diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -11,7 +11,7 @@ from pypy.module.micronumpy.iterators import ArrayIter from pypy.module.micronumpy.strides import (Chunk, Chunks, NewAxisChunk, RecordChunk, calc_strides, calc_new_strides, shape_agreement, - calculate_broadcast_strides) + calculate_broadcast_strides, calc_backstrides) class BaseConcreteArray(object): @@ -47,6 +47,7 @@ def setitem(self, index, value): self.dtype.itemtype.store(self, index, 0, value) + @jit.unroll_safe def setslice(self, space, arr): if len(arr.get_shape()) > 0 and len(self.get_shape()) == 0: raise oefmt(space.w_ValueError, @@ -78,10 +79,7 @@ self.get_strides(), self.order) if new_strides is not None: # We can create a view, strides somehow match up. - ndims = len(new_shape) - new_backstrides = [0] * ndims - for nd in range(ndims): - new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd] + new_backstrides = calc_backstrides(new_strides, new_shape) assert isinstance(orig_array, W_NDimArray) or orig_array is None return SliceArray(self.start, new_strides, new_backstrides, new_shape, self, orig_array) diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py --- a/pypy/module/micronumpy/ctors.py +++ b/pypy/module/micronumpy/ctors.py @@ -302,5 +302,5 @@ return a else: writable = not buf.readonly - return W_NDimArray.from_shape_and_storage(space, [n], storage, dtype=dtype, - w_base=w_buffer, writable=writable) + return W_NDimArray.from_shape_and_storage(space, [n], storage, storage_bytes=s, + dtype=dtype, w_base=w_buffer, writable=writable) diff --git a/pypy/module/micronumpy/descriptor.py b/pypy/module/micronumpy/descriptor.py --- a/pypy/module/micronumpy/descriptor.py +++ b/pypy/module/micronumpy/descriptor.py @@ -288,7 +288,6 @@ def descr_hash(self, space): return space.wrap(self._compute_hash(space, 0x345678)) - def descr_str(self, space): if self.fields: return space.str(self.descr_get_descr(space)) diff --git a/pypy/module/micronumpy/flagsobj.py b/pypy/module/micronumpy/flagsobj.py --- a/pypy/module/micronumpy/flagsobj.py +++ b/pypy/module/micronumpy/flagsobj.py @@ -1,3 +1,5 @@ +from rpython.rlib import jit + from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.error import OperationError from pypy.interpreter.gateway import interp2app @@ -13,6 +15,7 @@ arr.flags &= ~flags + at jit.unroll_safe def _update_contiguous_flags(arr): shape = arr.shape strides = arr.strides diff --git a/pypy/module/micronumpy/flatiter.py b/pypy/module/micronumpy/flatiter.py --- a/pypy/module/micronumpy/flatiter.py +++ b/pypy/module/micronumpy/flatiter.py @@ -22,6 +22,9 @@ def get_shape(self): return self.shape + def get_size(self): + return self.base().get_size() + def create_iter(self, shape=None, backward_broadcast=False): assert isinstance(self.base(), W_NDimArray) return self.base().create_iter() @@ -41,8 +44,8 @@ return space.wrap(self.state.index) def descr_coords(self, space): - self.state = self.iter.update(self.state) - return space.newtuple([space.wrap(c) for c in self.state.indices]) + coords = self.iter.indices(self.state) + return space.newtuple([space.wrap(c) for c in coords]) def descr_iter(self): return self @@ -54,7 +57,7 @@ if self.iter.done(self.state): raise OperationError(space.w_StopIteration, space.w_None) w_res = self.iter.getitem(self.state) - self.state = self.iter.next(self.state) + self.iter.next(self.state, mutate=True) return w_res def descr_getitem(self, space, w_idx): @@ -71,7 +74,7 @@ base.get_order(), w_instance=base) return loop.flatiter_getitem(res, self.iter, state, step) finally: - self.state = self.iter.reset(self.state) + self.iter.reset(self.state, mutate=True) def descr_setitem(self, space, w_idx, w_value): if not (space.isinstance_w(w_idx, space.w_int) or @@ -91,7 +94,7 @@ arr = convert_to_array(space, w_value) loop.flatiter_setitem(space, dtype, arr, self.iter, state, step, length) finally: - self.state = self.iter.reset(self.state) + self.iter.reset(self.state, mutate=True) W_FlatIterator.typedef = TypeDef("numpy.flatiter", diff --git a/pypy/module/micronumpy/iterators.py b/pypy/module/micronumpy/iterators.py --- a/pypy/module/micronumpy/iterators.py +++ b/pypy/module/micronumpy/iterators.py @@ -41,16 +41,6 @@ from pypy.module.micronumpy.base import W_NDimArray from pypy.module.micronumpy.flagsobj import _update_contiguous_flags -class OpFlag(object): - def __init__(self): - self.rw = '' - self.broadcast = True - self.force_contig = False - self.force_align = False - self.native_byte_order = False - self.tmp_copy = '' - self.allocate = False - class PureShapeIter(object): def __init__(self, shape, idx_w): @@ -87,25 +77,24 @@ class IterState(object): - _immutable_fields_ = ['iterator', 'index', 'indices', 'offset'] + _immutable_fields_ = ['iterator', '_indices'] def __init__(self, iterator, index, indices, offset): self.iterator = iterator self.index = index - self.indices = indices + self._indices = indices self.offset = offset class ArrayIter(object): _immutable_fields_ = ['contiguous', 'array', 'size', 'ndim_m1', 'shape_m1[*]', 'strides[*]', 'backstrides[*]', 'factors[*]', - 'slice_shape[*]', 'slice_stride[*]', 'slice_backstride[*]', - 'track_index', 'operand_type', 'slice_operand_type'] + 'track_index'] track_index = True - def __init__(self, array, size, shape, strides, backstrides, op_flags=OpFlag()): - from pypy.module.micronumpy import concrete + @jit.unroll_safe + def __init__(self, array, size, shape, strides, backstrides): assert len(shape) == len(strides) == len(backstrides) _update_contiguous_flags(array) self.contiguous = (array.flags & NPY.ARRAY_C_CONTIGUOUS and @@ -117,10 +106,6 @@ self.shape_m1 = [s - 1 for s in shape] self.strides = strides self.backstrides = backstrides - self.slice_shape = [] - self.slice_stride = [] - self.slice_backstride = [] - self.slice_operand_type = concrete.SliceArray ndim = len(shape) factors = [0] * ndim @@ -130,32 +115,35 @@ else: factors[ndim-i-1] = factors[ndim-i] * shape[ndim-i] self.factors = factors - if op_flags.rw == 'r': - self.operand_type = concrete.ConcreteNonWritableArrayWithBase - else: - self.operand_type = concrete.ConcreteArrayWithBase @jit.unroll_safe - def reset(self, state=None): + def reset(self, state=None, mutate=False): + index = 0 if state is None: indices = [0] * len(self.shape_m1) else: assert state.iterator is self - indices = state.indices + indices = state._indices for i in xrange(self.ndim_m1, -1, -1): indices[i] = 0 - return IterState(self, 0, indices, self.array.start) + offset = self.array.start + if not mutate: + return IterState(self, index, indices, offset) + state.index = index + state.offset = offset @jit.unroll_safe - def next(self, state): + def next(self, state, mutate=False): assert state.iterator is self index = state.index if self.track_index: index += 1 - indices = state.indices + indices = state._indices offset = state.offset if self.contiguous: offset += self.array.dtype.elsize + elif self.ndim_m1 == 0: + offset += self.strides[0] else: for i in xrange(self.ndim_m1, -1, -1): idx = indices[i] @@ -166,13 +154,18 @@ else: indices[i] = 0 offset -= self.backstrides[i] - return IterState(self, index, indices, offset) + if not mutate: + return IterState(self, index, indices, offset) + state.index = index + state.offset = offset @jit.unroll_safe def goto(self, index): offset = self.array.start if self.contiguous: offset += index * self.array.dtype.elsize + elif self.ndim_m1 == 0: + offset += index * self.strides[0] else: current = index for i in xrange(len(self.shape_m1)): @@ -181,20 +174,20 @@ return IterState(self, index, None, offset) @jit.unroll_safe - def update(self, state): + def indices(self, state): assert state.iterator is self assert self.track_index - if not self.contiguous: - return state + indices = state._indices + if not (self.contiguous or self.ndim_m1 == 0): + return indices current = state.index - indices = state.indices for i in xrange(len(self.shape_m1)): if self.factors[i] != 0: indices[i] = current / self.factors[i] current %= self.factors[i] else: indices[i] = 0 - return IterState(self, state.index, indices, state.offset) + return indices def done(self, state): assert state.iterator is self @@ -213,12 +206,6 @@ assert state.iterator is self self.array.setitem(state.offset, elem) - def getoperand(self, st, base): - impl = self.operand_type - res = impl([], self.array.dtype, self.array.order, [], [], - self.array.storage, base) - res.start = st.offset - return res def AxisIter(array, shape, axis, cumulative): strides = array.get_strides() @@ -242,42 +229,3 @@ size /= shape[axis] shape[axis] = backstrides[axis] = 0 return ArrayIter(array, size, shape, array.strides, backstrides) - -class SliceIter(ArrayIter): - ''' - used with external loops, getitem and setitem return a SliceArray - view into the original array - ''' - _immutable_fields_ = ['base'] - - def __init__(self, array, size, shape, strides, backstrides, slice_shape, - slice_stride, slice_backstride, op_flags, base): - from pypy.module.micronumpy import concrete - ArrayIter.__init__(self, array, size, shape, strides, backstrides, op_flags) - self.slice_shape = slice_shape - self.slice_stride = slice_stride - self.slice_backstride = slice_backstride - self.base = base - if op_flags.rw == 'r': - self.slice_operand_type = concrete.NonWritableSliceArray - else: - self.slice_operand_type = concrete.SliceArray - - def getitem(self, state): - # XXX cannot be called - must return a boxed value - assert False - - def getitem_bool(self, state): - # XXX cannot be called - must return a boxed value - assert False - - def setitem(self, state, elem): - # XXX cannot be called - must return a boxed value - assert False - - def getoperand(self, state, base): - assert state.iterator is self - impl = self.slice_operand_type - arr = impl(state.offset, self.slice_stride, self.slice_backstride, - self.slice_shape, self.array, self.base) - return arr diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -43,23 +43,38 @@ # TODO handle __array_priorities__ and maybe flip the order + if w_lhs.get_size() == 1: + w_left = w_lhs.get_scalar_value().convert_to(space, calc_dtype) + left_iter = left_state = None + else: + w_left = None + left_iter, left_state = w_lhs.create_iter(shape) + left_iter.track_index = False + + if w_rhs.get_size() == 1: + w_right = w_rhs.get_scalar_value().convert_to(space, calc_dtype) + right_iter = right_state = None + else: + w_right = None + right_iter, right_state = w_rhs.create_iter(shape) + right_iter.track_index = False + if out is None: out = W_NDimArray.from_shape(space, shape, res_dtype, w_instance=lhs_for_subtype) - left_iter, left_state = w_lhs.create_iter(shape) - right_iter, right_state = w_rhs.create_iter(shape) out_iter, out_state = out.create_iter(shape) - left_iter.track_index = right_iter.track_index = False shapelen = len(shape) while not out_iter.done(out_state): call2_driver.jit_merge_point(shapelen=shapelen, func=func, calc_dtype=calc_dtype, res_dtype=res_dtype) - w_left = left_iter.getitem(left_state).convert_to(space, calc_dtype) - w_right = right_iter.getitem(right_state).convert_to(space, calc_dtype) + if left_iter: + w_left = left_iter.getitem(left_state).convert_to(space, calc_dtype) + left_state = left_iter.next(left_state) + if right_iter: + w_right = right_iter.getitem(right_state).convert_to(space, calc_dtype) + right_state = right_iter.next(right_state) out_iter.setitem(out_state, func(calc_dtype, w_left, w_right).convert_to( space, res_dtype)) - left_state = left_iter.next(left_state) - right_state = right_iter.next(right_state) out_state = out_iter.next(out_state) return out @@ -69,11 +84,12 @@ reds='auto') def call1(space, shape, func, calc_dtype, res_dtype, w_obj, out): + obj_iter, obj_state = w_obj.create_iter(shape) + obj_iter.track_index = False + if out is None: out = W_NDimArray.from_shape(space, shape, res_dtype, w_instance=w_obj) - obj_iter, obj_state = w_obj.create_iter(shape) out_iter, out_state = out.create_iter(shape) - obj_iter.track_index = False shapelen = len(shape) while not out_iter.done(out_state): call1_driver.jit_merge_point(shapelen=shapelen, func=func, @@ -172,10 +188,23 @@ reds = 'auto') def setslice(space, shape, target, source): + if not shape: + dtype = target.dtype + val = source.getitem(source.start) + if dtype.is_str_or_unicode(): + val = dtype.coerce(space, val) + else: + val = val.convert_to(space, dtype) + target.setitem(target.start, val) + return target + return _setslice(space, shape, target, source) + +def _setslice(space, shape, target, source): # note that unlike everything else, target and source here are # array implementations, not arrays target_iter, target_state = target.create_iter(shape) source_iter, source_state = source.create_iter(shape) + source_iter.track_index = False dtype = target.dtype shapelen = len(shape) while not target_iter.done(target_state): @@ -294,10 +323,9 @@ state = x_state return out -axis_reduce__driver = jit.JitDriver(name='numpy_axis_reduce', - greens=['shapelen', - 'func', 'dtype'], - reds='auto') +axis_reduce_driver = jit.JitDriver(name='numpy_axis_reduce', + greens=['shapelen', 'func', 'dtype'], + reds='auto') def do_axis_reduce(space, shape, func, arr, dtype, axis, out, identity, cumulative, temp): @@ -310,21 +338,24 @@ temp_iter = out_iter # hack temp_state = out_state arr_iter, arr_state = arr.create_iter() + arr_iter.track_index = False if identity is not None: identity = identity.convert_to(space, dtype) shapelen = len(shape) while not out_iter.done(out_state): - axis_reduce__driver.jit_merge_point(shapelen=shapelen, func=func, - dtype=dtype) - assert not arr_iter.done(arr_state) + axis_reduce_driver.jit_merge_point(shapelen=shapelen, func=func, + dtype=dtype) w_val = arr_iter.getitem(arr_state).convert_to(space, dtype) - out_state = out_iter.update(out_state) - if out_state.indices[axis] == 0: + arr_state = arr_iter.next(arr_state) + + out_indices = out_iter.indices(out_state) + if out_indices[axis] == 0: if identity is not None: w_val = func(dtype, identity, w_val) else: cur = temp_iter.getitem(temp_state) w_val = func(dtype, cur, w_val) + out_iter.setitem(out_state, w_val) out_state = out_iter.next(out_state) if cumulative: @@ -332,7 +363,6 @@ temp_state = temp_iter.next(temp_state) else: temp_state = out_state - arr_state = arr_iter.next(arr_state) return out @@ -451,9 +481,9 @@ while not arr_iter.done(arr_state): nonzero_driver.jit_merge_point(shapelen=shapelen, dims=dims, dtype=dtype) if arr_iter.getitem_bool(arr_state): - arr_state = arr_iter.update(arr_state) + arr_indices = arr_iter.indices(arr_state) for d in dims: - res_iter.setitem(res_state, box(arr_state.indices[d])) + res_iter.setitem(res_state, box(arr_indices[d])) res_state = res_iter.next(res_state) arr_state = arr_iter.next(arr_state) return res diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -516,9 +516,10 @@ "__array__(dtype) not implemented")) if type(self) is W_NDimArray: return self + sz = support.product(self.get_shape()) * self.get_dtype().elsize return W_NDimArray.from_shape_and_storage( space, self.get_shape(), self.implementation.storage, - self.get_dtype(), w_base=self) + self.get_dtype(), storage_bytes=sz, w_base=self) def descr_array_iface(self, space): addr = self.implementation.get_storage_as_int(space) @@ -1180,8 +1181,8 @@ "improper dtype '%R'", dtype) self.implementation = W_NDimArray.from_shape_and_storage( space, [space.int_w(i) for i in space.listview(shape)], - rffi.str2charp(space.str_w(storage), track_allocation=False), - dtype, owning=True).implementation + rffi.str2charp(space.str_w(storage), track_allocation=False), + dtype, storage_bytes=space.len_w(storage), owning=True).implementation def descr___array_finalize__(self, space, w_obj): pass @@ -1205,8 +1206,10 @@ if not space.is_none(w_buffer): if (not space.is_none(w_strides)): - raise OperationError(space.w_NotImplementedError, - space.wrap("unsupported param")) + strides = [space.int_w(w_i) for w_i in + space.unpackiterable(w_strides)] + else: + strides = None try: buf = space.writebuf_w(w_buffer) @@ -1220,16 +1223,14 @@ if not shape: raise OperationError(space.w_TypeError, space.wrap( "numpy scalars from buffers not supported yet")) - totalsize = support.product(shape) * dtype.elsize - if totalsize + offset > buf.getlength(): - raise OperationError(space.w_TypeError, space.wrap( - "buffer is too small for requested array")) storage = rffi.cast(RAW_STORAGE_PTR, raw_ptr) storage = rffi.ptradd(storage, offset) - return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, + return W_NDimArray.from_shape_and_storage(space, shape, storage, + dtype, w_base=w_buffer, + storage_bytes=buf.getlength()-offset, w_subtype=w_subtype, - w_base=w_buffer, - writable=not buf.readonly) + writable=not buf.readonly, + strides=strides) order = order_converter(space, w_order, NPY.CORDER) if order == NPY.CORDER: @@ -1247,8 +1248,9 @@ return w_ret - at unwrap_spec(addr=int) -def descr__from_shape_and_storage(space, w_cls, w_shape, addr, w_dtype, w_subtype=None): + at unwrap_spec(addr=int, buf_len=int) +def descr__from_shape_and_storage(space, w_cls, w_shape, addr, w_dtype, + buf_len=-1, w_subtype=None, w_strides=None): """ Create an array from an existing buffer, given its address as int. PyPy-only implementation detail. @@ -1257,14 +1259,22 @@ dtype = space.interp_w(descriptor.W_Dtype, space.call_function( space.gettypefor(descriptor.W_Dtype), w_dtype)) shape = shape_converter(space, w_shape, dtype) + if not space.is_none(w_strides): + strides = [space.int_w(w_i) for w_i in + space.unpackiterable(w_strides)] + else: + strides = None if w_subtype: if not space.isinstance_w(w_subtype, space.w_type): raise OperationError(space.w_ValueError, space.wrap( "subtype must be a subtype of ndarray, not a class instance")) return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, - 'C', False, w_subtype) + buf_len, 'C', False, w_subtype, + strides=strides) else: - return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype) + return W_NDimArray.from_shape_and_storage(space, shape, storage, dtype, + storage_bytes=buf_len, + strides=strides) app_take = applevel(r""" def take(a, indices, axis, out, mode): diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py --- a/pypy/module/micronumpy/nditer.py +++ b/pypy/module/micronumpy/nditer.py @@ -1,3 +1,4 @@ +from rpython.rlib import jit from pypy.interpreter.baseobjspace import W_Root from pypy.interpreter.typedef import TypeDef, GetSetProperty from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault @@ -5,7 +6,7 @@ from pypy.module.micronumpy import support, concrete from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy.descriptor import decode_w_dtype -from pypy.module.micronumpy.iterators import ArrayIter, SliceIter, OpFlag +from pypy.module.micronumpy.iterators import ArrayIter from pypy.module.micronumpy.strides import (calculate_broadcast_strides, shape_agreement, shape_agreement_multiple) @@ -35,6 +36,16 @@ return ret +class OpFlag(object): + def __init__(self): + self.rw = '' + self.broadcast = True + self.force_contig = False + self.force_align = False + self.native_byte_order = False + self.tmp_copy = '' + self.allocate = False + def parse_op_flag(space, lst): op_flag = OpFlag() for w_item in lst: @@ -141,11 +152,73 @@ raise NotImplementedError('not implemented yet') -def get_iter(space, order, arr, shape, dtype, op_flags): +class OperandIter(ArrayIter): + _immutable_fields_ = ['slice_shape', 'slice_stride', 'slice_backstride', + 'operand_type', 'base'] + + def getitem(self, state): + # cannot be called - must return a boxed value + assert False + + def getitem_bool(self, state): + # cannot be called - must return a boxed value + assert False + + def setitem(self, state, elem): + # cannot be called - must return a boxed value + assert False + + +class ConcreteIter(OperandIter): + def __init__(self, array, size, shape, strides, backstrides, + op_flags, base): + OperandIter.__init__(self, array, size, shape, strides, backstrides) + self.slice_shape = 1 + self.slice_stride = -1 + if strides: + self.slice_stride = strides[-1] + self.slice_backstride = 1 + if op_flags.rw == 'r': + self.operand_type = concrete.ConcreteNonWritableArrayWithBase + else: + self.operand_type = concrete.ConcreteArrayWithBase + self.base = base + + def getoperand(self, state): + assert state.iterator is self + impl = self.operand_type + res = impl([], self.array.dtype, self.array.order, [], [], + self.array.storage, self.base) + res.start = state.offset + return res + + +class SliceIter(OperandIter): + def __init__(self, array, size, shape, strides, backstrides, slice_shape, + slice_stride, slice_backstride, op_flags, base): + OperandIter.__init__(self, array, size, shape, strides, backstrides) + self.slice_shape = slice_shape + self.slice_stride = slice_stride + self.slice_backstride = slice_backstride + if op_flags.rw == 'r': + self.operand_type = concrete.NonWritableSliceArray + else: + self.operand_type = concrete.SliceArray + self.base = base + + def getoperand(self, state): + assert state.iterator is self + impl = self.operand_type + arr = impl(state.offset, [self.slice_stride], [self.slice_backstride], + [self.slice_shape], self.array, self.base) + return arr + + +def get_iter(space, order, arr, shape, dtype, op_flags, base): imp = arr.implementation backward = is_backward(imp, order) if arr.is_scalar(): - return ArrayIter(imp, 1, [], [], [], op_flags=op_flags) + return ConcreteIter(imp, 1, [], [], [], op_flags, base) if (imp.strides[0] < imp.strides[-1] and not backward) or \ (imp.strides[0] > imp.strides[-1] and backward): # flip the strides. Is this always true for multidimension? @@ -160,7 +233,7 @@ backstrides = imp.backstrides r = calculate_broadcast_strides(strides, backstrides, imp.shape, shape, backward) - return ArrayIter(imp, imp.get_size(), shape, r[0], r[1], op_flags=op_flags) + return ConcreteIter(imp, imp.get_size(), shape, r[0], r[1], op_flags, base) def calculate_ndim(op_in, oa_ndim): if oa_ndim >=0: @@ -269,8 +342,8 @@ self.index = [0] * len(shape) self.backward = backward + @jit.unroll_safe def next(self): - # TODO It's probably possible to refactor all the "next" method from each iterator for i in range(len(self.shape) - 1, -1, -1): if self.index[i] < self.shape[i] - 1: self.index[i] += 1 @@ -404,7 +477,7 @@ self.iters = [] for i in range(len(self.seq)): it = get_iter(space, self.order, self.seq[i], self.shape, - self.dtypes[i], self.op_flags[i]) + self.dtypes[i], self.op_flags[i], self) it.contiguous = False self.iters.append((it, it.reset())) @@ -443,7 +516,7 @@ return space.wrap(self) def getitem(self, it, st): - res = it.getoperand(st, self) + res = it.getoperand(st) return W_NDimArray(res) def descr_getitem(self, space, w_idx): @@ -461,6 +534,7 @@ def descr_len(self, space): space.wrap(len(self.iters)) + @jit.unroll_safe def descr_next(self, space): for it, st in self.iters: if not it.done(st): diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py --- a/pypy/module/micronumpy/strides.py +++ b/pypy/module/micronumpy/strides.py @@ -270,7 +270,7 @@ shape = shape_agreement(space, shape, arr) return shape - + at jit.unroll_safe def _shape_agreement(shape1, shape2): """ Checks agreement about two shapes with respect to broadcasting. Returns the resulting shape. @@ -362,6 +362,13 @@ backstrides.reverse() return strides, backstrides + at jit.unroll_safe +def calc_backstrides(strides, shape): + ndims = len(shape) + new_backstrides = [0] * ndims + for nd in range(ndims): + new_backstrides[nd] = (shape[nd] - 1) * strides[nd] + return new_backstrides # Recalculating strides. Find the steps that the iteration does for each # dimension, given the stride and shape. Then try to create a new stride that diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -392,6 +392,7 @@ t5 = dtype([('x', ' Author: mattip Branch: ufuncapi Changeset: r74828:1453b5101ed2 Date: 2014-12-05 11:56 +0200 http://bitbucket.org/pypy/pypy/changeset/1453b5101ed2/ Log: fix after merge, wip diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py --- a/pypy/module/micronumpy/nditer.py +++ b/pypy/module/micronumpy/nditer.py @@ -173,11 +173,9 @@ def __init__(self, array, size, shape, strides, backstrides, op_flags, base): OperandIter.__init__(self, array, size, shape, strides, backstrides) - self.slice_shape = 1 - self.slice_stride = -1 - if strides: - self.slice_stride = strides[-1] - self.slice_backstride = 1 + self.slice_shape =[] + self.slice_stride = [] + self.slice_backstride = [] if op_flags.rw == 'r': self.operand_type = concrete.ConcreteNonWritableArrayWithBase else: @@ -209,8 +207,8 @@ def getoperand(self, state): assert state.iterator is self impl = self.operand_type - arr = impl(state.offset, [self.slice_stride], [self.slice_backstride], - [self.slice_shape], self.array, self.base) + arr = impl(state.offset, self.slice_stride, self.slice_backstride, + self.slice_shape, self.array, self.base) return arr diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py --- a/pypy/module/micronumpy/test/test_ufuncs.py +++ b/pypy/module/micronumpy/test/test_ufuncs.py @@ -120,11 +120,13 @@ c128_dtype, c128_dtype], '') f32_array = W_NDimArray(VoidBoxStorage(0, f32_dtype)) - index, dtypes = ufunc.type_resolver(space, [f32_array], [None], 'd->D') + index, dtypes = ufunc.type_resolver(space, [f32_array], [None], + 'd->D', ufunc.dtypes) #needs to cast input type, create output type assert index == 1 assert dtypes == [f64_dtype, c128_dtype] - index, dtypes = ufunc.type_resolver(space, [f32_array], [None], '') + index, dtypes = ufunc.type_resolver(space, [f32_array], [None], + '', ufunc.dtypes) assert index == 0 assert dtypes == [f32_dtype, c64_dtype] @@ -229,7 +231,7 @@ ) ai = arange(18, dtype=int).reshape(2,3,3) exc = raises(ValueError, ufunc, ai[:,:,0]) - assert "Operand 0 has a mismatch in its core dimension 1" in exc.value.message + assert "perand 0 has a mismatch in its core dimension 1" in exc.value.message ai3 = ufunc(ai[0,:,:]) ai2 = ufunc(ai) assert (ai2 == ai * 2).all() diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -590,11 +590,12 @@ # func is going to do all the work, it must accept W_NDimArray args inargs0 = inargs[0] assert isinstance(inargs0, W_NDimArray) - outarg_shapes = [inargs0.get_shape()] * self.nargs + arg_shapes = [inargs0.get_shape()] * self.nargs inargs, outargs, need_to_cast = self.alloc_args(space, inargs, outargs, - dtypes, outarg_shapes) - if any(need_to_cast): - raise oefmt(space.w_NotImplementedError, "casting not supported yet") + dtypes, arg_shapes) + for tf in need_to_cast: + if tf: + raise oefmt(space.w_NotImplementedError, "casting not supported yet") if self.stack_inputs: arglist = space.newlist(list(inargs + outargs)) space.call_args(func, Arguments.frompacked(space, arglist)) @@ -608,8 +609,9 @@ iter_shape, arg_shapes, matched_dims = self.verify_args(space, inargs, outargs) inargs, outargs, need_to_cast = self.alloc_args(space, inargs, outargs, dtypes, arg_shapes) - if any(need_to_cast): - raise oefmt(space.w_NotImplementedError, "casting not supported yet") + for tf in need_to_cast: + if tf: + raise oefmt(space.w_NotImplementedError, "casting not supported yet") w_flags = space.w_None # NOT 'external_loop', we do coalescing by core_num_dims w_op_flags = space.newtuple([space.wrap(r) for r in ['readonly'] * len(inargs)] + \ [space.wrap(r) for r in ['readwrite'] * len(outargs)]) @@ -786,15 +788,18 @@ if len(arg_shapes[i]) != curarg.ndims(): # XXX reshape (after merge with default) pass - need_to_cast.append(curarg.get_dtype() == dtypes[i]) + need_to_cast.append(curarg.get_dtype() != dtypes[i]) for i in range(len(outargs)): j = self.nin + i - if outargs[i] is None: - outargs[i] = W_NDimArray.from_shape(space, outarg_shapes[j], dtypes[j], order) + curarg = outargs[i] + assert isinstance(curarg, W_NDimArray) + if not isinstance(curarg, W_NDimArray): + outargs[i] = W_NDimArray.from_shape(space, arg_shapes[j], dtypes[j], order) + curarg = outargs[i] elif len(arg_shapes[i]) != curarg.ndims(): # XXX reshape (after merge with default) pass - need_to_cast.append(curarg.get_dtype() == dtypes[j]) + need_to_cast.append(curarg.get_dtype() != dtypes[j]) return inargs, outargs, need_to_cast def verify_args(self, space, inargs, outargs): @@ -814,13 +819,13 @@ name = 'Input' curarg = inargs[i] else: - _i = i + self.nin + _i = i - self.nin name = 'Output' curarg = outargs[_i] dim_offset = self.core_offsets[i] num_dims = self.core_num_dims[i] if not isinstance(curarg, W_NDimArray): - arg_shape = iter_shape + arg_shape = iter_shape[:] for j in range(num_dims): core_dim_index = self.core_dim_ixs[dim_offset + j] if matched_dims[core_dim_index] < 0: @@ -839,11 +844,11 @@ num_dims+n, self.signature, num_dims) dims_to_match = curarg.get_shape()[n:] dims_to_broadcast = curarg.get_shape()[:n] - offset = len(dims_to_broadcast) - len(iter_shape) - if offset >= 0: + offset = n - len(iter_shape) + if offset > 0: # Prepend extra dimensions to iter_shape, matched_dims iter_shape = dims_to_broadcast[:offset] + iter_shape - outarg_shapes = [dims_to_broadcast[:offset] + asp for asp in outarg_shapes] + arg_shapes = [dims_to_broadcast[:offset] + asp for asp in arg_shapes] offset = 0 # Make sure iter_shape[offset:] matches dims_to_broadcast offset = abs(offset) # for translation @@ -856,7 +861,8 @@ "(size %d is different from %d)", self.name, name, _i, j, x, y) iter_shape[offset + j] = max(x, y) - # Find or verify signature ixs + #print 'Find or verify signature ixs',self.core_dim_ixs, + #print 'starting',dim_offset,'n',num_dims,'matching',dims_to_match for j in range(num_dims): core_dim_index = self.core_dim_ixs[dim_offset + j] if core_dim_index > len(dims_to_match): @@ -865,12 +871,12 @@ "signature %s (index is larger than input shape)", self.name, name, _i, j, self.signature, core_dim_index) if matched_dims[core_dim_index] < 0: - matched_dims[core_dim_index] = dims_to_match[core_dim_index] - elif matched_dims[core_dim_index] != dims_to_match[core_dim_index]: + matched_dims[core_dim_index] = dims_to_match[j] + elif matched_dims[core_dim_index] != dims_to_match[j]: raise oefmt(space.w_ValueError, "%s: %s operand %d has a " "mismatch in its core dimension %d, with gufunc " "signature %s (expected %d, got %d)", - self.name, name, _i, core_dim_index + num_dims, + self.name, name, _i, j, self.signature, matched_dims[core_dim_index], dims_to_match[core_dim_index]) arg_shapes.append(iter_shape + dims_to_match) @@ -881,6 +887,7 @@ # TODO parse and handle subok # TODO handle flags, op_flags + #print 'iter_shape',iter_shape,'arg_shapes',arg_shapes,'matched_dims',matched_dims return iter_shape, arg_shapes, matched_dims W_Ufunc.typedef = TypeDef("numpy.ufunc", From noreply at buildbot.pypy.org Fri Dec 5 12:19:10 2014 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 5 Dec 2014 12:19:10 +0100 (CET) Subject: [pypy-commit] pypy ufuncapi: translation fix Message-ID: <20141205111910.C9BFA1D257D@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: ufuncapi Changeset: r74829:9d7d30ef07d4 Date: 2014-12-05 12:53 +0200 http://bitbucket.org/pypy/pypy/changeset/9d7d30ef07d4/ Log: translation fix diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -825,16 +825,17 @@ dim_offset = self.core_offsets[i] num_dims = self.core_num_dims[i] if not isinstance(curarg, W_NDimArray): - arg_shape = iter_shape[:] + target_dims = [] for j in range(num_dims): core_dim_index = self.core_dim_ixs[dim_offset + j] - if matched_dims[core_dim_index] < 0: + v = matched_dims[core_dim_index] + if v < 0: raise oefmt(space.w_ValueError, "%s: %s operand %d " "is empty but unique core dimension %d in signature " "%s of gufunc was not specified", self.name, name, _i, core_dim_index, self.signature) - arg_shape.append(matched_dims[core_dim_index]) - arg_shapes.append(arg_shape) + target_dims.append(v) + arg_shapes.append(iter_shape + target_dims) continue n = len(curarg.get_shape()) - num_dims if n < 0: From noreply at buildbot.pypy.org Fri Dec 5 12:19:11 2014 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 5 Dec 2014 12:19:11 +0100 (CET) Subject: [pypy-commit] pypy ufuncapi: reshape for broadcasting Message-ID: <20141205111911.E927A1D257D@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: ufuncapi Changeset: r74830:d5e8a34c0382 Date: 2014-12-05 13:18 +0200 http://bitbucket.org/pypy/pypy/changeset/d5e8a34c0382/ Log: reshape for broadcasting diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -13,7 +13,7 @@ from pypy.module.micronumpy.ctors import numpify from pypy.module.micronumpy.nditer import W_NDIter, coalesce_iter from pypy.module.micronumpy.strides import shape_agreement -from pypy.module.micronumpy.support import _parse_signature +from pypy.module.micronumpy.support import _parse_signature, product from rpython.rlib.rawstorage import (raw_storage_setitem, free_raw_storage, alloc_raw_storage) from rpython.rtyper.lltypesystem import rffi, lltype @@ -786,19 +786,27 @@ curarg = inargs[i] assert isinstance(curarg, W_NDimArray) if len(arg_shapes[i]) != curarg.ndims(): - # XXX reshape (after merge with default) + # reshape + sz = product(curarg.get_shape()) * curarg.get_dtype().elsize + inargs[i] = W_NDimArray.from_shape_and_storage( + space, arg_shapes[i], curarg.implementation.storage, + curarg.get_dtype(), storage_bytes=sz, w_base=curarg) pass need_to_cast.append(curarg.get_dtype() != dtypes[i]) for i in range(len(outargs)): j = self.nin + i curarg = outargs[i] - assert isinstance(curarg, W_NDimArray) if not isinstance(curarg, W_NDimArray): outargs[i] = W_NDimArray.from_shape(space, arg_shapes[j], dtypes[j], order) curarg = outargs[i] elif len(arg_shapes[i]) != curarg.ndims(): - # XXX reshape (after merge with default) - pass + # reshape + sz = product(curarg.get_shape()) * curarg.get_dtype().elsize + outargs[i] = W_NDimArray.from_shape_and_storage( + space, arg_shapes[i], curarg.implementation.storage, + curarg.get_dtype(), storage_bytes=sz, w_base=curarg) + curarg = outargs[i] + assert isinstance(curarg, W_NDimArray) need_to_cast.append(curarg.get_dtype() != dtypes[j]) return inargs, outargs, need_to_cast From noreply at buildbot.pypy.org Fri Dec 5 12:24:41 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 12:24:41 +0100 (CET) Subject: [pypy-commit] creflect default: copy loads of code from _cffi_backend.c Message-ID: <20141205112441.A9E661D29F4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r158:64bc5e56d01a Date: 2014-12-05 12:24 +0100 http://bitbucket.org/cffi/creflect/changeset/64bc5e56d01a/ Log: copy loads of code from _cffi_backend.c diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -288,9 +288,12 @@ return ct; } -static _crx_type_t *zef_get_array_type(_crx_builder_t *cb, _crx_type_t *ctitem, - size_t len) +static _crx_type_t *_zef_array_type(_crx_builder_t *cb, _crx_type_t *ctitem, + size_t len, CTypeDescrObject *ctptr) { + /* this function is called with different sets of non-NULL arguments + from various functions (just afterwards) + */ if (PyErr_Occurred()) return NULL; @@ -315,9 +318,11 @@ if (name_obj == NULL) return NULL; - ct = get_cached_type(cb, name_obj); - if (ct && (ct->ct_flags & CT_ARRAY)) - goto done; + if (cb != NULL) { + ct = get_cached_type(cb, name_obj); + if (ct && (ct->ct_flags & CT_ARRAY)) + goto done; + } if (length < 0) { arraysize = -1; @@ -331,6 +336,12 @@ } } + if (ctptr == NULL) { + ctptr = zef_get_pointer_type(cb, ctitem, 0); + if (PyErr_Occurred()) + goto done; + } + ct = ctypedescr_new(name_obj, ctitem->ct_name_position); if (ct == NULL) goto done; @@ -338,18 +349,43 @@ ct->ct_size = arraysize; ct->ct_length = length; ct->ct_flags = CT_ARRAY; + Py_INCREF(ctptr); + ct->ct_stuff = (PyObject *)ctptr; - put_cached_type(cb, name_obj, ct); + if (cb != NULL) { + if (length < 0 && ctptr->ct_stuff == NULL) { + Py_INCREF(ct); + ctptr->ct_stuff = (PyObject *)ct; + } + put_cached_type(cb, name_obj, ct); + } + else { + assert(length < 0); + assert(ctptr->ct_stuff == NULL); + ctptr->ct_stuff = (PyObject *)ct; + } done: Py_DECREF(name_obj); return ct; } +static int fill_array_type(CTypeDescrObject *ctptr) +{ + _zef_array_type(NULL, ctptr->ct_itemdescr, (size_t)-1, ctptr); + return PyErr_Occurred() ? -1 : 0; +} + +static _crx_type_t *zef_get_array_type(_crx_builder_t *cb, _crx_type_t *ctitem, + size_t len) +{ + return _zef_array_type(cb, ctitem, len, NULL); +} + static _crx_type_t *zef_get_incomplete_array_type(_crx_builder_t *cb, _crx_type_t *ctitem) { - return zef_get_array_type(cb, ctitem, (size_t)-1); + return _zef_array_type(cb, ctitem, (size_t)-1, NULL); } static _crx_type_t *zef_get_struct_type(_crx_builder_t *cb, const char *name) diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -6,6 +6,17 @@ PyObject *c_weakreflist; } CDataObject; +struct cfieldobject_s { + PyObject_HEAD + CTypeDescrObject *cf_type; + Py_ssize_t cf_offset; + short cf_bitshift; /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY */ + short cf_bitsize; + struct cfieldobject_s *cf_next; +}; +#define BS_REGULAR (-1) /* a regular field, not with bitshift */ +#define BS_EMPTY_ARRAY (-2) /* a field which is an array 'type[0]' */ + typedef union { unsigned char m_char; unsigned short m_short; @@ -39,7 +50,763 @@ #define CDataOwn_Check(ob) (Py_TYPE(ob) == &CDataOwning_Type || \ Py_TYPE(ob) == &CDataOwningGC_Type) +/************************************************************/ +static int +CDataObject_Or_PyFloat_Check(PyObject *ob) +{ + return (PyFloat_Check(ob) || + (CData_Check(ob) && + (((CDataObject *)ob)->c_type->ct_flags & CT_PRIMITIVE_FLOAT))); +} + +static PY_LONG_LONG +_my_PyLong_AsLongLong(PyObject *ob) +{ + /* (possibly) convert and cast a Python object to a long long. + Like PyLong_AsLongLong(), this version accepts a Python int too, and + does convertions from other types of objects. The difference is that + this version refuses floats. */ +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(ob)) { + return PyInt_AS_LONG(ob); + } + else +#endif + if (PyLong_Check(ob)) { + return PyLong_AsLongLong(ob); + } + else { + PyObject *io; + PY_LONG_LONG res; + PyNumberMethods *nb = ob->ob_type->tp_as_number; + + if (CDataObject_Or_PyFloat_Check(ob) || + nb == NULL || nb->nb_int == NULL) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return -1; + } + io = (*nb->nb_int) (ob); + if (io == NULL) + return -1; + + if (PyIntOrLong_Check(io)) { + res = _my_PyLong_AsLongLong(io); + } + else { + PyErr_SetString(PyExc_TypeError, "integer conversion failed"); + res = -1; + } + Py_DECREF(io); + return res; + } +} + +static unsigned PY_LONG_LONG +_my_PyLong_AsUnsignedLongLong(PyObject *ob, int strict) +{ + /* (possibly) convert and cast a Python object to an unsigned long long. + Like PyLong_AsLongLong(), this version accepts a Python int too, and + does convertions from other types of objects. If 'strict', complains + with OverflowError and refuses floats. If '!strict', rounds floats + and masks the result. */ +#if PY_MAJOR_VERSION < 3 + if (PyInt_Check(ob)) { + long value1 = PyInt_AS_LONG(ob); + if (strict && value1 < 0) + goto negative; + return (unsigned PY_LONG_LONG)(PY_LONG_LONG)value1; + } + else +#endif + if (PyLong_Check(ob)) { + if (strict) { + if (_PyLong_Sign(ob) < 0) + goto negative; + return PyLong_AsUnsignedLongLong(ob); + } + else { + return PyLong_AsUnsignedLongLongMask(ob); + } + } + else { + PyObject *io; + unsigned PY_LONG_LONG res; + PyNumberMethods *nb = ob->ob_type->tp_as_number; + + if ((strict && CDataObject_Or_PyFloat_Check(ob)) || + nb == NULL || nb->nb_int == NULL) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return (unsigned PY_LONG_LONG)-1; + } + io = (*nb->nb_int) (ob); + if (io == NULL) + return (unsigned PY_LONG_LONG)-1; + + if (PyIntOrLong_Check(io)) { + res = _my_PyLong_AsUnsignedLongLong(io, strict); + } + else { + PyErr_SetString(PyExc_TypeError, "integer conversion failed"); + res = (unsigned PY_LONG_LONG)-1; + } + Py_DECREF(io); + return res; + } + + negative: + PyErr_SetString(PyExc_OverflowError, + "can't convert negative number to unsigned"); + return (unsigned PY_LONG_LONG)-1; +} + +#define _read_raw_data(type) \ + do { \ + if (size == sizeof(type)) { \ + type r; \ + memcpy(&r, target, sizeof(type)); \ + return r; \ + } \ + } while(0) + +static PY_LONG_LONG +read_raw_signed_data(char *target, int size) +{ + _read_raw_data(signed char); + _read_raw_data(short); + _read_raw_data(int); + _read_raw_data(long); + _read_raw_data(PY_LONG_LONG); + Py_FatalError("read_raw_signed_data: bad integer size"); + return 0; +} + +static unsigned PY_LONG_LONG +read_raw_unsigned_data(char *target, int size) +{ + _read_raw_data(unsigned char); + _read_raw_data(unsigned short); + _read_raw_data(unsigned int); + _read_raw_data(unsigned long); + _read_raw_data(unsigned PY_LONG_LONG); + Py_FatalError("read_raw_unsigned_data: bad integer size"); + return 0; +} + +#define _write_raw_data(type) \ + do { \ + if (size == sizeof(type)) { \ + type r = (type)source; \ + memcpy(target, &r, sizeof(type)); \ + return; \ + } \ + } while(0) + +static void +write_raw_integer_data(char *target, unsigned PY_LONG_LONG source, int size) +{ + _write_raw_data(unsigned char); + _write_raw_data(unsigned short); + _write_raw_data(unsigned int); + _write_raw_data(unsigned long); + _write_raw_data(unsigned PY_LONG_LONG); + Py_FatalError("write_raw_integer_data: bad integer size"); +} + +static double +read_raw_float_data(char *target, int size) +{ + _read_raw_data(float); + _read_raw_data(double); + Py_FatalError("read_raw_float_data: bad float size"); + return 0; +} + +static long double +read_raw_longdouble_data(char *target) +{ + int size = sizeof(long double); + _read_raw_data(long double); + Py_FatalError("read_raw_longdouble_data: bad long double size"); + return 0; +} + +static void +write_raw_float_data(char *target, double source, int size) +{ + _write_raw_data(float); + _write_raw_data(double); + Py_FatalError("write_raw_float_data: bad float size"); +} + +static void +write_raw_longdouble_data(char *target, long double source) +{ + int size = sizeof(long double); + _write_raw_data(long double); +} + +static PyObject * +new_simple_cdata(char *data, CTypeDescrObject *ct) +{ + CDataObject *cd = PyObject_New(CDataObject, &CData_Type); + if (cd == NULL) + return NULL; + Py_INCREF(ct); + cd->c_data = data; + cd->c_type = ct; + cd->c_weakreflist = NULL; + return (PyObject *)cd; +} + +static CDataObject *_new_casted_primitive(CTypeDescrObject *ct) +{ + int dataoffset = offsetof(CDataObject_casted_primitive, alignment); + CDataObject *cd = (CDataObject *)PyObject_Malloc(dataoffset + ct->ct_size); + if (PyObject_Init((PyObject *)cd, &CData_Type) == NULL) + return NULL; + Py_INCREF(ct); + cd->c_type = ct; + cd->c_data = ((char*)cd) + dataoffset; + cd->c_weakreflist = NULL; + return cd; +} + +//845 +static PyObject *convert_to_object(char *data, CTypeDescrObject *ct) +{ + if (!(ct->ct_flags & CT_PRIMITIVE_ANY)) { + /* non-primitive types (check done just for performance) */ + if (ct->ct_flags & CT_POINTER) { + char *ptrdata = *(char **)data; + /*READ(data, sizeof(char *))*/ + return new_simple_cdata(ptrdata, ct); + } + else if (ct->ct_flags & CT_ARRAY) { + if (ct->ct_length < 0) { + /* we can't return a here, because we don't + know the length to give it. As a compromize, returns + in this case. */ + ct = (CTypeDescrObject *)ct->ct_stuff; + } + return new_simple_cdata(data, ct); + } + else if (ct->ct_size < 0) { + PyErr_Format(PyExc_TypeError, "cdata '%s' is opaque", + ct->ct_name); + return NULL; + } + else if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { + return new_simple_cdata(data, ct); + } + } + else if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { + PY_LONG_LONG value; + /*READ(data, ct->ct_size)*/ + value = read_raw_signed_data(data, ct->ct_size); + if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) + return PyInt_FromLong((long)value); + else + return PyLong_FromLongLong(value); + } + else if (ct->ct_flags & CT_PRIMITIVE_UNSIGNED) { + unsigned PY_LONG_LONG value; + /*READ(data, ct->ct_size)*/ + value = read_raw_unsigned_data(data, ct->ct_size); + + if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) + return PyInt_FromLong((long)value); + else + return PyLong_FromUnsignedLongLong(value); + } + else if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { + /*READ(data, ct->ct_size)*/ + if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) { + double value = read_raw_float_data(data, ct->ct_size); + return PyFloat_FromDouble(value); + } + else { + long double value = read_raw_longdouble_data(data); + CDataObject *cd = _new_casted_primitive(ct); + if (cd != NULL) + write_raw_longdouble_data(cd->c_data, value); + return (PyObject *)cd; + } + } + else if (ct->ct_flags & CT_PRIMITIVE_CHAR) { + /*READ(data, ct->ct_size)*/ + return PyBytes_FromStringAndSize(data, 1); + } + + PyErr_Format(PyExc_SystemError, + "convert_to_object: '%s'", ct->ct_name); + return NULL; +} + +#if 0 +static PyObject * +convert_to_object_bitfield(char *data, CFieldObject *cf) +{ + CTypeDescrObject *ct = cf->cf_type; + /*READ(data, ct->ct_size)*/ + + if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { + unsigned PY_LONG_LONG value, valuemask, shiftforsign; + PY_LONG_LONG result; + + value = (unsigned PY_LONG_LONG)read_raw_signed_data(data, ct->ct_size); + valuemask = (1ULL << cf->cf_bitsize) - 1ULL; + shiftforsign = 1ULL << (cf->cf_bitsize - 1); + value = ((value >> cf->cf_bitshift) + shiftforsign) & valuemask; + result = ((PY_LONG_LONG)value) - (PY_LONG_LONG)shiftforsign; + + if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) + return PyInt_FromLong((long)result); + else + return PyLong_FromLongLong(result); + } + else { + unsigned PY_LONG_LONG value, valuemask; + + value = read_raw_unsigned_data(data, ct->ct_size); + valuemask = (1ULL << cf->cf_bitsize) - 1ULL; + value = (value >> cf->cf_bitshift) & valuemask; + + if (ct->ct_flags & CT_PRIMITIVE_FITS_LONG) + return PyInt_FromLong((long)value); + else + return PyLong_FromUnsignedLongLong(value); + } +} +#endif + +static int _convert_overflow(PyObject *init, const char *ct_name) +{ + PyObject *s; + if (PyErr_Occurred()) /* already an exception pending */ + return -1; + s = PyObject_Str(init); + if (s == NULL) + return -1; + PyErr_Format(PyExc_OverflowError, "integer %s does not fit '%s'", + PyText_AS_UTF8(s), ct_name); + Py_DECREF(s); + return -1; +} + +static int _convert_to_char(PyObject *init) +{ + if (PyBytes_Check(init) && PyBytes_GET_SIZE(init) == 1) { + return (unsigned char)(PyBytes_AS_STRING(init)[0]); + } + if (CData_Check(init) && + (((CDataObject *)init)->c_type->ct_flags & CT_PRIMITIVE_CHAR)) { + char *data = ((CDataObject *)init)->c_data; + /*READ(data, 1)*/ + return *(unsigned char *)data; + } + PyErr_Format(PyExc_TypeError, + "initializer for ctype 'char' must be a "STR_OR_BYTES + " of length 1, not %.200s", Py_TYPE(init)->tp_name); + return -1; +} + +//1009 +static int _convert_error(PyObject *init, const char *ct_name, + const char *expected) +{ + if (CData_Check(init)) + PyErr_Format(PyExc_TypeError, + "initializer for ctype '%s' must be a %s, " + "not cdata '%s'", + ct_name, expected, + ((CDataObject *)init)->c_type->ct_name); + else + PyErr_Format(PyExc_TypeError, + "initializer for ctype '%s' must be a %s, " + "not %.200s", + ct_name, expected, Py_TYPE(init)->tp_name); + return -1; +} + +//1031 +static Py_ssize_t get_new_array_length(PyObject **pvalue) +{ + PyObject *value = *pvalue; + + if (PyList_Check(value) || PyTuple_Check(value)) { + return PySequence_Fast_GET_SIZE(value); + } + else if (PyBytes_Check(value)) { + /* from a string, we add the null terminator */ + return PyBytes_GET_SIZE(value) + 1; + } + else { + Py_ssize_t explicitlength; + explicitlength = PyNumber_AsSsize_t(value, PyExc_OverflowError); + if (explicitlength < 0) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_ValueError, "negative array length"); + return -1; + } + *pvalue = Py_None; + return explicitlength; + } +} + +//1061 +static int convert_field_from_object(char *data, CFieldObject *cf, + PyObject *value) +{ + data += cf->cf_offset; + if (cf->cf_bitshift >= 0) + return convert_from_object_bitfield(data, cf, value); + else + return convert_from_object(data, cf->cf_type, value); +} + +//1071 +static int convert_vfield_from_object(char *data, CFieldObject *cf, + PyObject *value, Py_ssize_t *optvarsize) +{ + /* a special case for var-sized C99 arrays */ + if ((cf->cf_type->ct_flags & CT_ARRAY) && cf->cf_type->ct_size < 0) { + Py_ssize_t varsizelength = get_new_array_length(&value); + if (varsizelength < 0) + return -1; + if (optvarsize != NULL) { + /* in this mode, the only purpose of this function is to compute + the real size of the structure from a var-sized C99 array */ + Py_ssize_t size, itemsize; + assert(data == NULL); + itemsize = cf->cf_type->ct_itemdescr->ct_size; + size = cf->cf_offset + itemsize * varsizelength; + if (size < 0 || + ((size - cf->cf_offset) / itemsize) != varsizelength) { + PyErr_SetString(PyExc_OverflowError, + "array size would overflow a Py_ssize_t"); + return -1; + } + if (size > *optvarsize) + *optvarsize = size; + return 0; + } + /* if 'value' was only an integer, get_new_array_length() returns + it and convert 'value' to be None. Detect if this was the case, + and if so, stop here, leaving the content uninitialized + (it should be zero-initialized from somewhere else). */ + if (value == Py_None) + return 0; + } + if (optvarsize == NULL) + return convert_field_from_object(data, cf, value); + else + return 0; +} + +//1110 +static int convert_array_from_object(char *data, CTypeDescrObject *ct, + PyObject *init) +{ + /* used by convert_from_object(), and also to decode lists/tuples/unicodes + passed as function arguments. 'ct' is an CT_ARRAY in the first case + and a CT_POINTER in the second case. */ + const char *expected; + CTypeDescrObject *ctitem = ct->ct_itemdescr; + + if (PyList_Check(init) || PyTuple_Check(init)) { + PyObject **items; + Py_ssize_t i, n; + n = PySequence_Fast_GET_SIZE(init); + if (ct->ct_length >= 0 && n > ct->ct_length) { + PyErr_Format(PyExc_IndexError, + "too many initializers for '%s' (got %zd)", + ct->ct_name, n); + return -1; + } + items = PySequence_Fast_ITEMS(init); + for (i=0; ict_size; + } + return 0; + } + else if ((ctitem->ct_flags & (CT_PRIMITIVE_CHAR | + CT_PRIMITIVE_SIGNED | + CT_PRIMITIVE_UNSIGNED)) + && (ctitem->ct_size == sizeof(char))) { + char *srcdata; + Py_ssize_t n; + if (!PyBytes_Check(init)) { + expected = STR_OR_BYTES" or list or tuple"; + goto cannot_convert; + } + n = PyBytes_GET_SIZE(init); + if (ct->ct_length >= 0 && n > ct->ct_length) { + PyErr_Format(PyExc_IndexError, + "initializer "STR_OR_BYTES" is too long for '%s' " + "(got %zd characters)", ct->ct_name, n); + return -1; + } + if (n != ct->ct_length) + n++; + srcdata = PyBytes_AS_STRING(init); + memcpy(data, srcdata, n); + return 0; + } + else { + expected = "list or tuple"; + goto cannot_convert; + } + + cannot_convert: + return _convert_error(init, ct->ct_name, expected); +} + +//1190 +static int convert_struct_from_object(char *data, CTypeDescrObject *ct, + PyObject *init, Py_ssize_t *optvarsize) +{ + const char *expected; + + if (ct->ct_flags & CT_UNION) { + Py_ssize_t n = PyObject_Size(init); + if (n < 0) + return -1; + if (n > 1) { + PyErr_Format(PyExc_ValueError, + "initializer for '%s': %zd items given, but " + "only one supported (use a dict if needed)", + ct->ct_name, n); + return -1; + } + } + if (PyList_Check(init) || PyTuple_Check(init)) { + PyObject **items = PySequence_Fast_ITEMS(init); + Py_ssize_t i, n = PySequence_Fast_GET_SIZE(init); + CFieldObject *cf = (CFieldObject *)ct->ct_extra; + + for (i=0; ict_name, n); + return -1; + } + if (convert_vfield_from_object(data, cf, items[i], optvarsize) < 0) + return -1; + cf = cf->cf_next; + } + return 0; + } + if (PyDict_Check(init)) { + PyObject *d_key, *d_value; + Py_ssize_t i = 0; + CFieldObject *cf; + + while (PyDict_Next(init, &i, &d_key, &d_value)) { + cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, d_key); + if (cf == NULL) { + PyErr_SetObject(PyExc_KeyError, d_key); + return -1; + } + if (convert_vfield_from_object(data, cf, d_value, optvarsize) < 0) + return -1; + } + return 0; + } + expected = optvarsize == NULL ? "list or tuple or dict or struct-cdata" + : "list or tuple or dict"; + return _convert_error(init, ct->ct_name, expected); +} + +#ifdef __GNUC__ +# if __GNUC__ >= 4 +/* Don't go inlining this huge function. Needed because occasionally + it gets inlined in places where is causes a warning: call to + __builtin___memcpy_chk will always overflow destination buffer + (which is places where the 'ct' should never represent such a large + primitive type anyway). */ +__attribute__((noinline)) +# endif +#endif +//1257 +static int convert_from_object(char *data, CTypeDescrObject *ct, PyObject *init) +{ + const char *expected; + char buf[sizeof(PY_LONG_LONG)]; + + /*if (ct->ct_size > 0)*/ + /*WRITE(data, ct->ct_size)*/ + + if (ct->ct_flags & CT_ARRAY) { + return convert_array_from_object(data, ct, init); + } + if (ct->ct_flags & CT_POINTER) { + char *ptrdata; + CTypeDescrObject *ctinit; + + if (!CData_Check(init)) { + expected = "cdata pointer"; + goto cannot_convert; + } + ctinit = ((CDataObject *)init)->c_type; + if (!(ctinit->ct_flags & CT_POINTER)) { + if (ctinit->ct_flags & CT_ARRAY) + ctinit = (CTypeDescrObject *)ctinit->ct_stuff; + else { + expected = "pointer or array"; + goto cannot_convert; + } + } + if (ctinit != ct) { + if ((ct->ct_flags & CT_CAST_ANYTHING) || + (ctinit->ct_flags & CT_CAST_ANYTHING)) + ; /* accept void* or char* as either source or target */ + else { + expected = "pointer to same type"; + goto cannot_convert; + } + } + ptrdata = ((CDataObject *)init)->c_data; + + *(char **)data = ptrdata; + return 0; + } + if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { + PY_LONG_LONG value = _my_PyLong_AsLongLong(init); + if (value == -1 && PyErr_Occurred()) + return -1; + write_raw_integer_data(buf, value, ct->ct_size); + if (value != read_raw_signed_data(buf, ct->ct_size)) + goto overflow; + write_raw_integer_data(data, value, ct->ct_size); + return 0; + } + if (ct->ct_flags & CT_PRIMITIVE_UNSIGNED) { + unsigned PY_LONG_LONG value = _my_PyLong_AsUnsignedLongLong(init, 1); + if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) + return -1; + if (ct->ct_flags & CT_IS_BOOL) + if (value & ~1) /* value != 0 && value != 1 */ + goto overflow; + write_raw_integer_data(buf, value, ct->ct_size); + if (value != read_raw_unsigned_data(buf, ct->ct_size)) + goto overflow; + write_raw_integer_data(data, value, ct->ct_size); + return 0; + } + if (ct->ct_flags & CT_PRIMITIVE_FLOAT) { + double value; + if ((ct->ct_flags & CT_IS_LONGDOUBLE) && + CData_Check(init) && + (((CDataObject *)init)->c_type->ct_flags & CT_IS_LONGDOUBLE)) { + long double lvalue; + char *initdata = ((CDataObject *)init)->c_data; + /*READ(initdata, sizeof(long double))*/ + lvalue = read_raw_longdouble_data(initdata); + write_raw_longdouble_data(data, lvalue); + return 0; + } + value = PyFloat_AsDouble(init); + if (value == -1.0 && PyErr_Occurred()) + return -1; + if (!(ct->ct_flags & CT_IS_LONGDOUBLE)) + write_raw_float_data(data, value, ct->ct_size); + else + write_raw_longdouble_data(data, (long double)value); + return 0; + } + if (ct->ct_flags & CT_PRIMITIVE_CHAR) { + int res; + assert(ct->ct_size == sizeof(char)); + res = _convert_to_char(init); + if (res < 0) + return -1; + data[0] = res; + return 0; + } + if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { + + if (CData_Check(init)) { + if (((CDataObject *)init)->c_type == ct && ct->ct_size >= 0) { + memcpy(data, ((CDataObject *)init)->c_data, ct->ct_size); + return 0; + } + } + return convert_struct_from_object(data, ct, init, NULL); + } + PyErr_Format(PyExc_SystemError, + "convert_from_object: '%s'", ct->ct_name); + return -1; + + overflow: + return _convert_overflow(init, ct->ct_name); + + cannot_convert: + return _convert_error(init, ct->ct_name, expected); +} + +//1383 +static int convert_from_object_bitfield(char *data, CFieldObject *cf, + PyObject *init) +{ + CTypeDescrObject *ct = cf->cf_type; + PY_LONG_LONG fmin, fmax, value = PyLong_AsLongLong(init); + unsigned PY_LONG_LONG rawfielddata, rawvalue, rawmask; + if (value == -1 && PyErr_Occurred()) + return -1; + + if (ct->ct_flags & CT_PRIMITIVE_SIGNED) { + fmin = -(1LL << (cf->cf_bitsize-1)); + fmax = (1LL << (cf->cf_bitsize-1)) - 1LL; + if (fmax == 0) + fmax = 1; /* special case to let "int x:1" receive "1" */ + } + else { + fmin = 0LL; + fmax = (PY_LONG_LONG)((1ULL << cf->cf_bitsize) - 1ULL); + } + if (value < fmin || value > fmax) { + /* phew, PyErr_Format does not support "%lld" in Python 2.6 */ + PyObject *svalue = NULL, *sfmin = NULL, *sfmax = NULL; + PyObject *lfmin = NULL, *lfmax = NULL; + svalue = PyObject_Str(init); + if (svalue == NULL) goto skip; + lfmin = PyLong_FromLongLong(fmin); + if (lfmin == NULL) goto skip; + sfmin = PyObject_Str(lfmin); + if (sfmin == NULL) goto skip; + lfmax = PyLong_FromLongLong(fmax); + if (lfmax == NULL) goto skip; + sfmax = PyObject_Str(lfmax); + if (sfmax == NULL) goto skip; + PyErr_Format(PyExc_OverflowError, + "value %s outside the range allowed by the " + "bit field width: %s <= x <= %s", + PyText_AS_UTF8(svalue), + PyText_AS_UTF8(sfmin), + PyText_AS_UTF8(sfmax)); + skip: + Py_XDECREF(svalue); + Py_XDECREF(sfmin); + Py_XDECREF(sfmax); + Py_XDECREF(lfmin); + Py_XDECREF(lfmax); + return -1; + } + + rawmask = ((1ULL << cf->cf_bitsize) - 1ULL) << cf->cf_bitshift; + rawvalue = ((unsigned PY_LONG_LONG)value) << cf->cf_bitshift; + /*WRITE(data, ct->ct_size)*/ + rawfielddata = read_raw_unsigned_data(data, ct->ct_size); + rawfielddata = (rawfielddata & ~rawmask) | (rawvalue & rawmask); + write_raw_integer_data(data, rawfielddata, ct->ct_size); + return 0; +} + +//1440 static Py_ssize_t get_array_length(CDataObject *cd) { if (cd->c_type->ct_length < 0) @@ -49,6 +816,7 @@ } +//1480 static void cdata_dealloc(CDataObject *cd) { if (cd->c_weakreflist != NULL) @@ -60,6 +828,7 @@ #endif } +//1491 static void cdataowninggc_dealloc(CDataObject *cd) { abort(); @@ -83,6 +852,7 @@ #endif } +//1534 static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg) { abort(); @@ -100,6 +870,7 @@ #endif } +//1548 static int cdataowninggc_clear(CDataObject *cd) { abort(); @@ -120,6 +891,7 @@ #endif } +//1599 static PyObject *cdata_repr(CDataObject *cd) { char *extra; @@ -174,6 +946,7 @@ return result; } +//1650 static PyObject *_cdata_repr2(CDataObject *cd, char *text, PyObject *x) { PyObject *res, *s = PyObject_Repr(x); @@ -185,6 +958,7 @@ return res; } +//1661 static PyObject *cdataowning_repr(CDataObject *cd) { Py_ssize_t size; @@ -223,6 +997,253 @@ } } +//1815 +static Py_ssize_t cdata_length(CDataObject *cd) +{ + if (cd->c_type->ct_flags & CT_ARRAY) { + return get_array_length(cd); + } + PyErr_Format(PyExc_TypeError, "cdata of type '%s' has no len()", + cd->c_type->ct_name); + return -1; +} + +//1826 +static char *_cdata_get_indexed_ptr(CDataObject *cd, PyObject *key) +{ + Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + + if (cd->c_type->ct_flags & CT_POINTER) { + if (CDataOwn_Check(cd) && i != 0) { + PyErr_Format(PyExc_IndexError, + "cdata '%s' can only be indexed by 0", + cd->c_type->ct_name); + return NULL; + } + } + else if (cd->c_type->ct_flags & CT_ARRAY) { + if (i < 0) { + PyErr_SetString(PyExc_IndexError, + "negative index not supported"); + return NULL; + } + if (i >= get_array_length(cd)) { + PyErr_Format(PyExc_IndexError, + "index too large for cdata '%s' (expected %zd < %zd)", + cd->c_type->ct_name, + i, get_array_length(cd)); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed", + cd->c_type->ct_name); + return NULL; + } + return cd->c_data + i * cd->c_type->ct_itemdescr->ct_size; +} + +//1866 +static CTypeDescrObject * +_cdata_getslicearg(CDataObject *cd, PySliceObject *slice, Py_ssize_t bounds[]) +{ + Py_ssize_t start, stop; + CTypeDescrObject *ct; + + start = PyInt_AsSsize_t(slice->start); + if (start == -1 && PyErr_Occurred()) { + if (slice->start == Py_None) + PyErr_SetString(PyExc_IndexError, "slice start must be specified"); + return NULL; + } + stop = PyInt_AsSsize_t(slice->stop); + if (stop == -1 && PyErr_Occurred()) { + if (slice->stop == Py_None) + PyErr_SetString(PyExc_IndexError, "slice stop must be specified"); + return NULL; + } + if (slice->step != Py_None) { + PyErr_SetString(PyExc_IndexError, "slice with step not supported"); + return NULL; + } + if (start > stop) { + PyErr_SetString(PyExc_IndexError, "slice start > stop"); + return NULL; + } + + ct = cd->c_type; + if (ct->ct_flags & CT_ARRAY) { + if (start < 0) { + PyErr_SetString(PyExc_IndexError, + "negative index not supported"); + return NULL; + } + if (stop > get_array_length(cd)) { + PyErr_Format(PyExc_IndexError, + "index too large (expected %zd <= %zd)", + stop, get_array_length(cd)); + return NULL; + } + ct = (CTypeDescrObject *)ct->ct_stuff; + } + else if (!(ct->ct_flags & CT_POINTER)) { + PyErr_Format(PyExc_TypeError, "cdata of type '%s' cannot be indexed", + ct->ct_name); + return NULL; + } + + bounds[0] = start; + bounds[1] = stop - start; + return ct; +} + +//1919 +static PyObject *cdata_slice(CDataObject *cd, PySliceObject *slice) +{ + Py_ssize_t bounds[2]; + CDataObject_own_length *scd; + CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds); + if (ct == NULL) + return NULL; + + if (ct->ct_stuff == NULL) { + if (fill_array_type(ct) < 0) + return NULL; + assert(ct->ct_stuff != NULL); + } + ct = (CTypeDescrObject *)ct->ct_stuff; + + scd = (CDataObject_own_length *)PyObject_Malloc( + offsetof(CDataObject_own_length, alignment)); + if (PyObject_Init((PyObject *)scd, &CData_Type) == NULL) + return NULL; + Py_INCREF(ct); + scd->head.c_type = ct; + scd->head.c_data = cd->c_data + ct->ct_itemdescr->ct_size * bounds[0]; + scd->head.c_weakreflist = NULL; + scd->length = bounds[1]; + return (PyObject *)scd; +} + +//1947 +static int cdata_ass_slice(CDataObject *cd, PySliceObject *slice, PyObject *v) +{ + Py_ssize_t bounds[2], i, length, itemsize; + PyObject *it, *item; + PyObject *(*iternext)(PyObject *); + char *cdata; + int err; + CTypeDescrObject *ct = _cdata_getslicearg(cd, slice, bounds); + if (ct == NULL) + return -1; + ct = ct->ct_itemdescr; + itemsize = ct->ct_size; + cdata = cd->c_data + itemsize * bounds[0]; + length = bounds[1]; + + if (CData_Check(v)) { + CTypeDescrObject *ctv = ((CDataObject *)v)->c_type; + if ((ctv->ct_flags & CT_ARRAY) && (ctv->ct_itemdescr == ct) && + (get_array_length((CDataObject *)v) == length)) { + /* fast path: copying from exactly the correct type */ + memmove(cdata, ((CDataObject *)v)->c_data, itemsize * length); + return 0; + } + } + + /* A fast path for [0:N] = b"somestring", which also adds + support for Python 3: otherwise, you get integers while enumerating + the string, and you can't set them to characters :-/ + */ + if (PyBytes_Check(v) && (ct->ct_flags & CT_PRIMITIVE_CHAR)) { + if (PyBytes_GET_SIZE(v) != length) { + PyErr_Format(PyExc_ValueError, + "need a string of length %zd, got %zd", + length, PyBytes_GET_SIZE(v)); + return -1; + } + memcpy(cdata, PyBytes_AS_STRING(v), length); + return 0; + } + + it = PyObject_GetIter(v); + if (it == NULL) + return -1; + iternext = *it->ob_type->tp_iternext; + + for (i = 0; i < length; i++) { + item = iternext(it); + if (item == NULL) { + if (!PyErr_Occurred()) + PyErr_Format(PyExc_ValueError, + "need %zd values to unpack, got %zd", + length, i); + goto error; + } + err = convert_from_object(cdata, ct, item); + Py_DECREF(item); + if (err < 0) + goto error; + + cdata += itemsize; + } + item = iternext(it); + if (item != NULL) { + Py_DECREF(item); + PyErr_Format(PyExc_ValueError, + "got more than %zd values to unpack", length); + } + error: + Py_DECREF(it); + return PyErr_Occurred() ? -1 : 0; +} + +//2044 +static PyObject *cdata_subscript(CDataObject *cd, PyObject *key) +{ + char *c; + if (PySlice_Check(key)) + return cdata_slice(cd, (PySliceObject *)key); + + c = _cdata_get_indexed_ptr(cd, key); + /* use 'mp_subscript' instead of 'sq_item' because we don't want + negative indexes to be corrected automatically */ + if (c == NULL && PyErr_Occurred()) + return NULL; + return convert_to_object(c, cd->c_type->ct_itemdescr); +} + +//2059 +static int cdata_ass_sub(CDataObject *cd, PyObject *key, PyObject *v) +{ + char *c; + CTypeDescrObject *ctitem; + if (PySlice_Check(key)) + return cdata_ass_slice(cd, (PySliceObject *)key, v); + + c = _cdata_get_indexed_ptr(cd, key); + ctitem = cd->c_type->ct_itemdescr; + /* use 'mp_ass_subscript' instead of 'sq_ass_item' because we don't want + negative indexes to be corrected automatically */ + if (c == NULL && PyErr_Occurred()) + return -1; + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "'del x[n]' not supported for cdata objects"); + return -1; + } + return convert_from_object(c, ctitem, v); +} + + +static PyMappingMethods CData_as_mapping = { + (lenfunc)cdata_length, /*mp_length*/ + (binaryfunc)cdata_subscript, /*mp_subscript*/ + (objobjargproc)cdata_ass_sub, /*mp_ass_subscript*/ +}; + static PyTypeObject CData_Type = { PyVarObject_HEAD_INIT(NULL, 0) "zeffir.CData", @@ -236,7 +1257,7 @@ (reprfunc)cdata_repr, /* tp_repr */ 0,//&CData_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ - 0,//&CData_as_mapping, /* tp_as_mapping */ + &CData_as_mapping, /* tp_as_mapping */ 0,//(hashfunc)cdata_hash, /* tp_hash */ 0,//(ternaryfunc)cdata_call, /* tp_call */ 0, /* tp_str */ diff --git a/zeffir/ctype.c b/zeffir/ctype.c --- a/zeffir/ctype.c +++ b/zeffir/ctype.c @@ -30,13 +30,12 @@ CTypeDescrObject *ct_itemdescr; /* ptrs and arrays: the item type */ PyObject *ct_stuff; /* structs: dict of the fields - //arrays: ctypedescr of the ptr type + arrays: ctypedescr of the ptr type function: tuple(abi, ctres, ctargs..) enum: pair {"name":x},{x:"name"} ptrs: lazily, ctypedescr of array */ - //void *ct_extra; /* structs: first field (not a ref!) - // function types: cif_description - // primitives: prebuilt "cif" object */ + void *ct_extra; /* structs: first field (not a ref!) + function types: cif_description */ PyObject *ct_weakreflist; /* weakref support */ @@ -75,7 +74,7 @@ static PyObject *ctypedescr_repr(CTypeDescrObject *ct) { - return PyString_FromFormat("", ct->ct_name); + return PyText_FromFormat("", ct->ct_name); } static void ctypedescr_dealloc(CTypeDescrObject *ct) diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -121,12 +121,12 @@ /* Returns the CTypeDescrObject from the user-supplied 'arg'. Does not return a new reference! */ - if ((accept & ACCEPT_STRING) && PyString_Check(arg)) { + if ((accept & ACCEPT_STRING) && PyText_Check(arg)) { PyObject *x = PyDict_GetItem(ffi->types_dict, arg); if (x != NULL && CTypeDescr_Check(x)) return (CTypeDescrObject *)x; - CTypeDescrObject *ct = parse_c_decl(ffi, PyString_AS_STRING(arg)); + CTypeDescrObject *ct = parse_c_decl(ffi, PyText_AS_UTF8(arg)); if (ct == NULL) return NULL; diff --git a/zeffir/lib_obj.c b/zeffir/lib_obj.c --- a/zeffir/lib_obj.c +++ b/zeffir/lib_obj.c @@ -20,9 +20,9 @@ static PyObject *lib_repr(ZefLibObject *lib) { - return PyString_FromFormat("", - lib->l_libname, - lib->l_dl_lib == NULL ? " (closed)" : ""); + return PyText_FromFormat("", + lib->l_libname, + lib->l_dl_lib == NULL ? " (closed)" : ""); } static PyObject *lib_findattr(ZefLibObject *lib, PyObject *name) @@ -40,7 +40,7 @@ "lib '%.200s' has no function," " global variable or constant '%.200s'", lib->l_libname, - PyString_Check(name) ? PyString_AS_STRING(name) : "?"); + PyText_Check(name) ? PyText_AS_UTF8(name) : "?"); return NULL; } return x; @@ -83,7 +83,7 @@ PyErr_Format(PyExc_AttributeError, "cannot write to function or constant '%.200s'", - PyString_Check(name) ? PyString_AS_STRING(name) : "?"); + PyText_Check(name) ? PyText_AS_UTF8(name) : "?"); return -1; } @@ -152,7 +152,7 @@ return NULL; lib->l_dl_lib = NULL; - lib->l_libname = PyString_AS_STRING(path); + lib->l_libname = PyString_AsString(path); Py_INCREF(path); lib->l_libname_obj = path; lib->l_dict = PyDict_New(); diff --git a/zeffir/py3support.h b/zeffir/py3support.h new file mode 100644 --- /dev/null +++ b/zeffir/py3support.h @@ -0,0 +1,28 @@ + +#if PY_MAJOR_VERSION >= 3 +# define STR_OR_BYTES "bytes" +# define PyText_Type PyUnicode_Type +# define PyText_Check PyUnicode_Check +# define PyTextAny_Check PyUnicode_Check +# define PyText_FromFormat PyUnicode_FromFormat +# define PyText_AsUTF8 _PyUnicode_AsString /* PyUnicode_AsUTF8 in Py3.3 */ +# define PyText_AS_UTF8 _PyUnicode_AsString +# define PyText_GetSize PyUnicode_GetSize +# define PyText_FromString PyUnicode_FromString +# define PyText_FromStringAndSize PyUnicode_FromStringAndSize +# define PyText_InternInPlace PyUnicode_InternInPlace +# define PyIntOrLong_Check PyLong_Check +#else +# define STR_OR_BYTES "str" +# define PyText_Type PyString_Type +# define PyText_Check PyString_Check +# define PyTextAny_Check(op) (PyString_Check(op) || PyUnicode_Check(op)) +# define PyText_FromFormat PyString_FromFormat +# define PyText_AsUTF8 PyString_AsString +# define PyText_AS_UTF8 PyString_AS_STRING +# define PyText_GetSize PyString_Size +# define PyText_FromString PyString_FromString +# define PyText_FromStringAndSize PyString_FromStringAndSize +# define PyText_InternInPlace PyString_InternInPlace +# define PyIntOrLong_Check(op) (PyInt_Check(op) || PyLong_Check(op)) +#endif diff --git a/zeffir/test/test_cdata.py b/zeffir/test/test_cdata.py --- a/zeffir/test/test_cdata.py +++ b/zeffir/test/test_cdata.py @@ -6,3 +6,10 @@ ffi = support.new_ffi() p = ffi.new("short *") assert repr(p) == "" + +def test_cdata_read_write(): + ffi = support.new_ffi() + p = ffi.new("short *") + assert p[0] == 0 + p[0] = 43 + assert p[0] == 43 diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c --- a/zeffir/zeffir.c +++ b/zeffir/zeffir.c @@ -9,6 +9,7 @@ /* Works by including all other .c files. */ /* Allows all function and global symbols to remain static. */ +#include "py3support.h" #include "zeffir.h" #include "ctype.c" #include "cdata.c" diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h --- a/zeffir/zeffir.h +++ b/zeffir/zeffir.h @@ -1,5 +1,6 @@ typedef struct _crx_type_s CTypeDescrObject; +typedef struct cfieldobject_s CFieldObject; typedef struct ZefLibObject_s ZefLibObject; typedef struct ZefFFIObject_s ZefFFIObject; @@ -15,3 +16,8 @@ static int lib_close(ZefLibObject *); static int load_creflect_main(ZefFFIObject *, ZefLibObject *); static CTypeDescrObject *parse_c_decl(ZefFFIObject *ffi, const char *str); + +static int convert_from_object(char *, CTypeDescrObject *, PyObject *); +static int convert_from_object_bitfield(char *, CFieldObject *, PyObject *); + +static int fill_array_type(CTypeDescrObject *ctptr); From noreply at buildbot.pypy.org Fri Dec 5 12:41:04 2014 From: noreply at buildbot.pypy.org (mattip) Date: Fri, 5 Dec 2014 12:41:04 +0100 (CET) Subject: [pypy-commit] pypy ufuncapi: fix failing test Message-ID: <20141205114104.CB3AF1D28F0@cobra.cs.uni-duesseldorf.de> Author: mattip Branch: ufuncapi Changeset: r74831:35709774642a Date: 2014-12-05 13:38 +0200 http://bitbucket.org/pypy/pypy/changeset/35709774642a/ Log: fix failing test diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py --- a/pypy/module/micronumpy/ufuncs.py +++ b/pypy/module/micronumpy/ufuncs.py @@ -638,10 +638,8 @@ for i in range(len(allargs)): _arg = allargs[i] assert isinstance(_arg, W_NDimArray) - start_dim = len(_arg.get_shape()) - len(iter_shape) - assert start_dim >= 0 + start_dim = len(iter_shape) steps += _arg.implementation.strides[start_dim:] - #print 'set_dims_and_steps with dims, steps',dims,steps func.set_dims_and_steps(space, dims, steps) else: # it is a function, ready to be called by the iterator, From noreply at buildbot.pypy.org Fri Dec 5 12:43:15 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 12:43:15 +0100 (CET) Subject: [pypy-commit] creflect default: re-enable the XXX'ed parts of ffi.new() Message-ID: <20141205114315.F1F4B1D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r159:c6e3bdeb49c5 Date: 2014-12-05 12:35 +0100 http://bitbucket.org/cffi/creflect/changeset/c6e3bdeb49c5/ Log: re-enable the XXX'ed parts of ffi.new() diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -349,8 +349,8 @@ ct->ct_size = arraysize; ct->ct_length = length; ct->ct_flags = CT_ARRAY; - Py_INCREF(ctptr); - ct->ct_stuff = (PyObject *)ctptr; + ct->ct_itemdescr = ctitem; Py_INCREF(ctitem); + ct->ct_stuff = (PyObject *)ctptr; Py_INCREF(ctptr); if (cb != NULL) { if (length < 0 && ctptr->ct_stuff == NULL) { diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -203,15 +203,13 @@ if (ctitem->ct_flags & CT_PRIMITIVE_CHAR) datasize *= 2; /* forcefully add another character: a null */ - /* XXX if ((ctitem->ct_flags & CT_WITH_VAR_ARRAY) && init != Py_None) { Py_ssize_t optvarsize = datasize; if (convert_struct_from_object(NULL,ctitem, init, &optvarsize) < 0) return NULL; datasize = optvarsize; - }*/ + } } - /* XXX else if (ct->ct_flags & CT_ARRAY) { dataoffset = offsetof(CDataObject_own_nolength, alignment); datasize = ct->ct_size; @@ -229,7 +227,7 @@ return NULL; } } - }*/ + } else { PyErr_Format(PyExc_TypeError, "expected a pointer or array ctype, got '%s'", @@ -247,12 +245,11 @@ memset(cd->c_data, 0, datasize); if (init != Py_None) { - /* XXX if (convert_from_object(cd->c_data, (ct->ct_flags & CT_POINTER) ? ct->ct_itemdescr : ct, init) < 0) { Py_DECREF(cd); return NULL; - }*/ + } } return (PyObject *)cd; } diff --git a/zeffir/test/test_cdata.py b/zeffir/test/test_cdata.py --- a/zeffir/test/test_cdata.py +++ b/zeffir/test/test_cdata.py @@ -13,3 +13,15 @@ assert p[0] == 0 p[0] = 43 assert p[0] == 43 + +def test_cdata_array_fixed(): + ffi = support.new_ffi() + p = ffi.new("int[5]") + assert p[4] == 0 + p[4] = 43 + assert p[4] == 43 + +def test_cdata_array_incomplete(): + ffi = support.new_ffi() + p = ffi.new("int[]", [10, 20, 30]) + assert p[2] == 30 From noreply at buildbot.pypy.org Fri Dec 5 12:43:17 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 12:43:17 +0100 (CET) Subject: [pypy-commit] creflect default: the next tests to pass Message-ID: <20141205114317.4824C1D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r160:adbaf54b8357 Date: 2014-12-05 12:43 +0100 http://bitbucket.org/cffi/creflect/changeset/adbaf54b8357/ Log: the next tests to pass diff --git a/zeffir/cfunc.c b/zeffir/cfunc.c --- a/zeffir/cfunc.c +++ b/zeffir/cfunc.c @@ -48,7 +48,8 @@ actualnargs = PyTuple_Size(args); if (actualnargs != nargs) { if (!PyErr_Occurred()) - PyErr_Format(PyExc_TypeError, "'%s' expects %d arguments, got %zd", + PyErr_Format(PyExc_TypeError, + "'%s()' expected %d arguments, but got %zd", zfs->zfs_funcname, nargs, actualnargs); return NULL; } diff --git a/zeffir/test/function.crx b/zeffir/test/function.crx --- a/zeffir/test/function.crx +++ b/zeffir/test/function.crx @@ -3,9 +3,18 @@ return x + 1; } +int add_from_array(int array[], int count) +{ + int result = 0; + while (count > 0) + result += array[--count]; + return result; +} + // CREFLECT: start int simple_function(int); +int add_from_array(int array[], int count); // CREFLECT: end diff --git a/zeffir/test/test_function.py b/zeffir/test/test_function.py --- a/zeffir/test/test_function.py +++ b/zeffir/test/test_function.py @@ -1,3 +1,4 @@ +import py import support @@ -6,3 +7,18 @@ res = lib.simple_function(42) assert type(res) is int assert res == 43 + +def test_function_with_pointer_arg(): + py.test.skip("in-progress") + ffi, lib = support.compile_and_open('function') + p = ffi.new("int[]", [30, 2, 10]) + res = lib.add_from_array(p, 3) + assert type(res) is int + assert res == 42 + +def test_function_with_array_arg(): + py.test.skip("in-progress") + ffi, lib = support.compile_and_open('function') + res = lib.add_from_array([30, 2, 10], 3) + assert type(res) is int + assert res == 42 From noreply at buildbot.pypy.org Fri Dec 5 15:48:23 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 15:48:23 +0100 (CET) Subject: [pypy-commit] creflect default: correct call argument types Message-ID: <20141205144823.27CF21D29F4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r161:081d71b47603 Date: 2014-12-05 15:43 +0100 http://bitbucket.org/cffi/creflect/changeset/081d71b47603/ Log: correct call argument types diff --git a/zeffir/cfunc.c b/zeffir/cfunc.c --- a/zeffir/cfunc.c +++ b/zeffir/cfunc.c @@ -5,12 +5,19 @@ int zfs_nargs; _crx_trampoline0_fn zfs_trampl; PyMethodDef zfs_md; - char zfs_funcname[1]; + size_t zfs_size_args; + CTypeDescrObject *zfs_ret; + CTypeDescrObject *zfs_args[1]; } ZefFuncSupportObject; static void zef_func_support_dealloc(ZefFuncSupportObject *zfs) { + int i; + for (i = zfs->zfs_nargs - 1; i >= 0; i--) + Py_DECREF(zfs->zfs_args[i]); + Py_DECREF(zfs->zfs_ret); + PyObject_Del(zfs); } @@ -37,33 +44,42 @@ Py_TPFLAGS_DEFAULT, /* tp_flags */ }; +#define ROUND_UP(n) (((n) + 7) & ~7) + static PyObject *zfs_call(PyObject *self, PyObject *args) { ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)self; int i, nargs = zfs->zfs_nargs; Py_ssize_t actualnargs; void *llargs[nargs]; - int llinput[nargs], lloutput; /* temp */ + char *llbuffer; + size_t lloffset; actualnargs = PyTuple_Size(args); if (actualnargs != nargs) { if (!PyErr_Occurred()) PyErr_Format(PyExc_TypeError, "'%s()' expected %d arguments, but got %zd", - zfs->zfs_funcname, nargs, actualnargs); + zfs->zfs_md.ml_name, nargs, actualnargs); return NULL; } + llbuffer = alloca(zfs->zfs_size_args); + lloffset = zfs->zfs_ret->ct_size; + for (i = 0; i < nargs; i++) { - llinput[i] = PyInt_AsLong(PyTuple_GET_ITEM(args, i)); - if (PyErr_Occurred()) + CTypeDescrObject *ct = zfs->zfs_args[i]; + PyObject *x = PyTuple_GET_ITEM(args, i); + lloffset = ROUND_UP(lloffset); + llargs[i] = llbuffer + lloffset; + if (convert_from_object(llbuffer + lloffset, ct, x) < 0) return NULL; - llargs[i] = &llinput[i]; + lloffset += ct->ct_size; } - zfs->zfs_trampl(llargs, &lloutput); + zfs->zfs_trampl(llargs, llbuffer); - return PyInt_FromLong(lloutput); + return convert_to_object(llbuffer, zfs->zfs_ret); } static PyObject *make_builtin_func(PyObject *libname_obj, @@ -71,7 +87,11 @@ _crx_qual_type args[], int nargs, _crx_trampoline0_fn trampl) { - size_t size = sizeof(ZefFuncSupportObject) + strlen(funcname); + int i; + char *p; + size_t size = (sizeof(ZefFuncSupportObject) + + (nargs - 1) * sizeof(CTypeDescrObject *) + + strlen(funcname) + 1); ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)PyObject_Malloc(size); if (zfs == NULL) return PyErr_NoMemory(); @@ -79,9 +99,26 @@ zfs->zfs_nargs = nargs; zfs->zfs_trampl = trampl; + zfs->zfs_ret = ret; + Py_INCREF(ret); + + assert(ret->ct_size >= 0); + size = ret->ct_size; + + for (i = 0; i < nargs; i++) { + CTypeDescrObject *ct = args[i].type; + if (ct->ct_flags & CT_ARRAY) + ct = (CTypeDescrObject *)ct->ct_stuff; /* array -> pointer */ + Py_INCREF(ct); + zfs->zfs_args[i] = ct; + assert(ct->ct_size >= 0); + size = ROUND_UP(size) + ct->ct_size; + } + zfs->zfs_size_args = size; + p = (char *)(zfs->zfs_args + nargs); memset(&zfs->zfs_md, 0, sizeof(PyMethodDef)); - zfs->zfs_md.ml_name = strcpy(zfs->zfs_funcname, funcname); + zfs->zfs_md.ml_name = strcpy(p, funcname); zfs->zfs_md.ml_meth = &zfs_call; zfs->zfs_md.ml_flags = METH_VARARGS; /*zfs->zfs_md.ml_doc = ... */ diff --git a/zeffir/test/test_function.py b/zeffir/test/test_function.py --- a/zeffir/test/test_function.py +++ b/zeffir/test/test_function.py @@ -9,7 +9,6 @@ assert res == 43 def test_function_with_pointer_arg(): - py.test.skip("in-progress") ffi, lib = support.compile_and_open('function') p = ffi.new("int[]", [30, 2, 10]) res = lib.add_from_array(p, 3) From noreply at buildbot.pypy.org Fri Dec 5 15:48:24 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 15:48:24 +0100 (CET) Subject: [pypy-commit] creflect default: more copying from _cffi_backend Message-ID: <20141205144824.4DC9F1D29F4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r162:157449ed6904 Date: 2014-12-05 15:48 +0100 http://bitbucket.org/cffi/creflect/changeset/157449ed6904/ Log: more copying from _cffi_backend diff --git a/zeffir/cfunc.c b/zeffir/cfunc.c --- a/zeffir/cfunc.c +++ b/zeffir/cfunc.c @@ -46,6 +46,67 @@ #define ROUND_UP(n) (((n) + 7) & ~7) +static Py_ssize_t _prepare_pointer_call_argument(CTypeDescrObject *ctptr, + PyObject *init, + char **output_data) +{ + /* 'ctptr' is here a pointer type 'ITEM *'. Accept as argument an + initializer for an array 'ITEM[]'. This includes the case of + passing a Python byte string to a 'char *' argument. + + This function returns -1 if an error occurred, + 0 if conversion succeeded (into *output_data), + or N > 0 if conversion would require N bytes of storage. + */ + Py_ssize_t length, datasize; + CTypeDescrObject *ctitem; + + if (CData_Check(init)) + goto convert_default; + + ctitem = ctptr->ct_itemdescr; + /* XXX some code duplication, how to avoid it? */ + if (PyBytes_Check(init)) { + /* from a string: just returning the string here is fine. + We assume that the C code won't modify the 'char *' data. */ + if ((ctptr->ct_flags & CT_CAST_ANYTHING) || + ((ctitem->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) + && (ctitem->ct_size == sizeof(char)))) { +#if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK) + length = PyBytes_GET_SIZE(init) + 1; +#else + *output_data = PyBytes_AS_STRING(init); + return 0; +#endif + } + else + goto convert_default; + } + else if (PyList_Check(init) || PyTuple_Check(init)) { + length = PySequence_Fast_GET_SIZE(init); + } + else { + /* refuse to receive just an integer (and interpret it + as the array size) */ + goto convert_default; + } + + if (ctitem->ct_size <= 0) + goto convert_default; + datasize = length * ctitem->ct_size; + if ((datasize / ctitem->ct_size) != length) { + PyErr_SetString(PyExc_OverflowError, + "array size would overflow a Py_ssize_t"); + return -1; + } + if (datasize <= 0) + datasize = 1; + return datasize; + + convert_default: + return convert_from_object((char *)output_data, ctptr, init); +} + static PyObject *zfs_call(PyObject *self, PyObject *args) { ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)self; @@ -69,11 +130,34 @@ for (i = 0; i < nargs; i++) { CTypeDescrObject *ct = zfs->zfs_args[i]; - PyObject *x = PyTuple_GET_ITEM(args, i); + PyObject *obj = PyTuple_GET_ITEM(args, i); + char *data; lloffset = ROUND_UP(lloffset); - llargs[i] = llbuffer + lloffset; - if (convert_from_object(llbuffer + lloffset, ct, x) < 0) - return NULL; + data = llbuffer + lloffset; + llargs[i] = data; + + if (ct->ct_flags & CT_POINTER) { + char *tmpbuf; + Py_ssize_t datasize = _prepare_pointer_call_argument( + ct, obj, (char **)data); + if (datasize == 0) { + /* successfully filled '*data' */ + } + else if (datasize < 0) { + return NULL; + } + else { + tmpbuf = alloca(datasize); + memset(tmpbuf, 0, datasize); + *(char **)data = tmpbuf; + if (convert_array_from_object(tmpbuf, ct, obj) < 0) + return NULL; + } + } + else { + if (convert_from_object(data, ct, obj) < 0) + return NULL; + } lloffset += ct->ct_size; } diff --git a/zeffir/test/test_function.py b/zeffir/test/test_function.py --- a/zeffir/test/test_function.py +++ b/zeffir/test/test_function.py @@ -16,7 +16,6 @@ assert res == 42 def test_function_with_array_arg(): - py.test.skip("in-progress") ffi, lib = support.compile_and_open('function') res = lib.add_from_array([30, 2, 10], 3) assert type(res) is int From noreply at buildbot.pypy.org Fri Dec 5 16:22:13 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 16:22:13 +0100 (CET) Subject: [pypy-commit] creflect default: globals of all types Message-ID: <20141205152213.15C0F1D2A0C@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r163:1c10444e58e6 Date: 2014-12-05 15:54 +0100 http://bitbucket.org/cffi/creflect/changeset/1c10444e58e6/ Log: globals of all types diff --git a/zeffir/cglob.c b/zeffir/cglob.c --- a/zeffir/cglob.c +++ b/zeffir/cglob.c @@ -51,3 +51,13 @@ assert(addr != NULL); return (PyObject *)zgs; } + +static PyObject *read_global_var(ZefGlobSupportObject *zgs) +{ + return convert_to_object(zgs->zgs_data, zgs->zgs_type); +} + +static int write_global_var(ZefGlobSupportObject *zgs, PyObject *obj) +{ + return convert_from_object(zgs->zgs_data, zgs->zgs_type, obj); +} diff --git a/zeffir/lib_obj.c b/zeffir/lib_obj.c --- a/zeffir/lib_obj.c +++ b/zeffir/lib_obj.c @@ -53,8 +53,7 @@ return NULL; if (ZefGlobSupport_Check(x)) { - // XXX! - return PyInt_FromLong(*(int *)(((ZefGlobSupportObject *)x)->zgs_data)); + return read_global_var((ZefGlobSupportObject *)x); } Py_INCREF(x); return x; @@ -73,12 +72,7 @@ } if (ZefGlobSupport_Check(x)) { - // XXX! - long y = PyInt_AsLong(val); - if (PyErr_Occurred()) - return -1; - *(int *)(((ZefGlobSupportObject *)x)->zgs_data) = y; - return 0; + return write_global_var((ZefGlobSupportObject *)x, val); } PyErr_Format(PyExc_AttributeError, diff --git a/zeffir/test/global.crx b/zeffir/test/global.crx --- a/zeffir/test/global.crx +++ b/zeffir/test/global.crx @@ -1,8 +1,10 @@ short myglob = 42; +short *myglobptr = &myglob; // CREFLECT: start short myglob; +short *myglobptr; // CREFLECT: end diff --git a/zeffir/test/test_global.py b/zeffir/test/test_global.py --- a/zeffir/test/test_global.py +++ b/zeffir/test/test_global.py @@ -13,5 +13,14 @@ assert type(res) is int assert res == -43 # - #py.test.raises(OverflowError, setattr, lib, 'myglob', 40000) - #py.test.raises(OverflowError, setattr, lib, 'myglob', -40000) + py.test.raises(OverflowError, setattr, lib, 'myglob', 40000) + py.test.raises(OverflowError, setattr, lib, 'myglob', -40000) + +def test_ptr_global(): + ffi, lib = support.compile_and_open('global') + p = lib.myglobptr + assert p[0] == 42 + # + q = ffi.new("short *", -555) + lib.myglobptr = q + assert lib.myglobptr[0] == -555 From noreply at buildbot.pypy.org Fri Dec 5 16:22:16 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 16:22:16 +0100 (CET) Subject: [pypy-commit] creflect default: simple structs work Message-ID: <20141205152216.B66731D2E18@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r164:fca0f1dca466 Date: 2014-12-05 16:22 +0100 http://bitbucket.org/cffi/creflect/changeset/fca0f1dca466/ Log: simple structs work diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -388,14 +388,42 @@ return _zef_array_type(cb, ctitem, (size_t)-1, NULL); } +static _crx_type_t *_zef_struct_or_union(_crx_builder_t *cb, const char *name, + int flag) +{ + if (PyErr_Occurred()) + return NULL; + + PyObject *name_obj; + CTypeDescrObject *ct; + + name_obj = PyString_FromString(name); + if (name_obj == NULL) + return NULL; + + ct = get_cached_type(cb, name_obj); + if (ct && (ct->ct_flags == flag)) + goto done; + + ct = ctypedescr_new(name_obj, PyString_GET_SIZE(name_obj)); + if (ct == NULL) + goto done; + + ct->ct_flags = flag; + + done: + Py_DECREF(name_obj); + return ct; +} + static _crx_type_t *zef_get_struct_type(_crx_builder_t *cb, const char *name) { - abort(); + return _zef_struct_or_union(cb, name, CT_STRUCT); } static _crx_type_t *zef_get_union_type(_crx_builder_t *cb, const char *name) { - abort(); + return _zef_struct_or_union(cb, name, CT_UNION); } static _crx_type_t *zef_get_enum_type(_crx_builder_t *cb, const char *name) @@ -426,11 +454,258 @@ return _zef_primitive(cb, -1, name, CT_UNKNOWN); } -static void zef_complete(_crx_builder_t *cb, _crx_type_t *t, +static CFieldObject *_add_field(PyObject *interned_fields, + const char *fname, CTypeDescrObject *ftype, + Py_ssize_t offset, int bitshift, int fbitsize) +{ + int err; + PyObject *fname_obj; + Py_ssize_t prev_size; + CFieldObject *cf = PyObject_New(CFieldObject, &CField_Type); + if (cf == NULL) + return NULL; + + Py_INCREF(ftype); + cf->cf_type = ftype; + cf->cf_offset = offset; + cf->cf_bitshift = bitshift; + cf->cf_bitsize = fbitsize; + + fname_obj = PyString_InternFromString(fname); + prev_size = PyDict_Size(interned_fields); + err = PyDict_SetItem(interned_fields, fname_obj, (PyObject *)cf); + Py_DECREF(fname_obj); + Py_DECREF(cf); + if (err < 0) + return NULL; + + if (PyDict_Size(interned_fields) != prev_size + 1) { + PyErr_Format(PyExc_KeyError, "duplicate field name '%s'", + PyText_AS_UTF8(fname)); + return NULL; + } + return cf; /* borrowed reference */ +} + +static void zef_complete(_crx_builder_t *cb, _crx_type_t *ct, size_t sz, size_t align, _crx_field_t fields[], int nfields) { - abort(); + PyObject *interned_fields; + CFieldObject **previous; + int i; + + assert(ct->ct_flags & (CT_STRUCT | CT_UNION)); + if (ct->ct_size >= 0) { + PyErr_Format(ZefError, "duplicate declaration of the fields of '%s'", + ct->ct_name); + return; + } + + interned_fields = PyDict_New(); + if (interned_fields == NULL) + return; + + previous = (CFieldObject **)&ct->ct_extra; + + for (i = 0; i < nfields; i++) { + _crx_field_t *f = &fields[i]; + CTypeDescrObject *ftype = f->type; + + if (ftype->ct_size < 0) { + if ((ftype->ct_flags & CT_ARRAY) /* && fbitsize < 0 + && (i == nb_fields - 1 || foffset != -1) */ ) { + ct->ct_flags |= CT_WITH_VAR_ARRAY; + } + else { + PyErr_Format(PyExc_TypeError, + "field '%s.%s' has ctype '%s' of unknown size", + ct->ct_name, f->name, ftype->ct_name); + goto error; + } + } + + if (f->numbits < 0) { + /* not a bitfield: common case */ + int bs_flag; + + if ((ftype->ct_flags & CT_ARRAY) && ftype->ct_length == 0) + bs_flag = BS_EMPTY_ARRAY; + else + bs_flag = BS_REGULAR; + +#if 0 /* XXX */ + if (PyText_GetSize(fname) == 0 && + ftype->ct_flags & (CT_STRUCT|CT_UNION)) { + /* a nested anonymous struct or union */ + CFieldObject *cfsrc = (CFieldObject *)ftype->ct_extra; + for (; cfsrc != NULL; cfsrc = cfsrc->cf_next) { + /* broken complexity in the call to get_field_name(), + but we'll assume you never do that with nested + anonymous structures with thousand of fields */ + *previous = _add_field(interned_fields, + get_field_name(ftype, cfsrc), + cfsrc->cf_type, + boffset / 8 + cfsrc->cf_offset, + cfsrc->cf_bitshift, + cfsrc->cf_bitsize); + if (*previous == NULL) + goto error; + previous = &(*previous)->cf_next; + } + /* always forbid such structures from being passed by value */ + ct->ct_flags |= CT_CUSTOM_FIELD_POS; + } + else +#endif + { + *previous = _add_field(interned_fields, f->name, ftype, + f->offset, bs_flag, -1); + if (*previous == NULL) + goto error; + previous = &(*previous)->cf_next; + } + } + else { + abort(); +#if 0 + /* this is the case of a bitfield */ + Py_ssize_t field_offset_bytes; + int bits_already_occupied, bitshift; + + if (foffset >= 0) { + PyErr_Format(PyExc_TypeError, + "field '%s.%s' is a bitfield, " + "but a fixed offset is specified", + ct->ct_name, PyText_AS_UTF8(fname)); + goto error; + } + + if (!(ftype->ct_flags & (CT_PRIMITIVE_SIGNED | + CT_PRIMITIVE_UNSIGNED | + CT_PRIMITIVE_CHAR))) { + PyErr_Format(PyExc_TypeError, + "field '%s.%s' declared as '%s' cannot be a bit field", + ct->ct_name, PyText_AS_UTF8(fname), + ftype->ct_name); + goto error; + } + if (fbitsize > 8 * ftype->ct_size) { + PyErr_Format(PyExc_TypeError, + "bit field '%s.%s' is declared '%s:%d', which " + "exceeds the width of the type", + ct->ct_name, PyText_AS_UTF8(fname), + ftype->ct_name, fbitsize); + goto error; + } + + /* compute the starting position of the theoretical field + that covers a complete 'ftype', inside of which we will + locate the real bitfield */ + field_offset_bytes = boffset / 8; + field_offset_bytes &= ~(falign - 1); + + if (fbitsize == 0) { + if (PyText_GetSize(fname) > 0) { + PyErr_Format(PyExc_TypeError, + "field '%s.%s' is declared with :0", + ct->ct_name, PyText_AS_UTF8(fname)); + goto error; + } + if (!(sflags & SF_MSVC_BITFIELDS)) { + /* GCC's notion of "ftype :0;" */ + + /* pad boffset to a value aligned for "ftype" */ + if (boffset > field_offset_bytes * 8) { + field_offset_bytes += falign; + assert(boffset < field_offset_bytes * 8); + } + boffset = field_offset_bytes * 8; + } + else { + /* MSVC's notion of "ftype :0;" */ + + /* Mostly ignored. It seems they only serve as + separator between other bitfields, to force them + into separate words. */ + } + prev_bitfield_size = 0; + } + else { + if (!(sflags & SF_MSVC_BITFIELDS)) { + /* GCC's algorithm */ + + /* Can the field start at the offset given by 'boffset'? It + can if it would entirely fit into an aligned ftype field. */ + bits_already_occupied = boffset - (field_offset_bytes * 8); + + if (bits_already_occupied + fbitsize > 8 * ftype->ct_size) { + /* it would not fit, we need to start at the next + allowed position */ + if ((sflags & SF_PACKED) && + (bits_already_occupied & 7)) { + PyErr_Format(PyExc_NotImplementedError, + "with 'packed', gcc would compile field " + "'%s.%s' to reuse some bits in the previous " + "field", ct->ct_name, PyText_AS_UTF8(fname)); + goto error; + } + field_offset_bytes += falign; + assert(boffset < field_offset_bytes * 8); + boffset = field_offset_bytes * 8; + bitshift = 0; + } + else { + bitshift = bits_already_occupied; + assert(bitshift >= 0); + } + boffset += fbitsize; + } + else { + /* MSVC's algorithm */ + + /* A bitfield is considered as taking the full width + of their declared type. It can share some bits + with the previous field only if it was also a + bitfield and used a type of the same size. */ + if (prev_bitfield_size == ftype->ct_size && + prev_bitfield_free >= fbitsize) { + /* yes: reuse */ + bitshift = 8 * prev_bitfield_size - prev_bitfield_free; + } + else { + /* no: start a new full field */ + boffset = (boffset + falign*8-1) & ~(falign*8-1); /*align*/ + boffset += ftype->ct_size * 8; + bitshift = 0; + prev_bitfield_size = ftype->ct_size; + prev_bitfield_free = 8 * prev_bitfield_size; + } + prev_bitfield_free -= fbitsize; + field_offset_bytes = boffset / 8 - ftype->ct_size; + } + + if (sflags & SF_GCC_BIG_ENDIAN) + bitshift = 8 * ftype->ct_size - fbitsize - bitshift; + + *previous = _add_field(interned_fields, fname, ftype, + field_offset_bytes, bitshift, fbitsize); + if (*previous == NULL) + goto error; + previous = &(*previous)->cf_next; + } +#endif + } + } + *previous = NULL; + + ct->ct_size = sz; + /* 'align' ignored for now */ + ct->ct_stuff = interned_fields; + return; + + error: + Py_DECREF(interned_fields); } static void zef_complete_enum(_crx_builder_t *cb, _crx_type_t *t, diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -6,17 +6,6 @@ PyObject *c_weakreflist; } CDataObject; -struct cfieldobject_s { - PyObject_HEAD - CTypeDescrObject *cf_type; - Py_ssize_t cf_offset; - short cf_bitshift; /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY */ - short cf_bitsize; - struct cfieldobject_s *cf_next; -}; -#define BS_REGULAR (-1) /* a regular field, not with bitshift */ -#define BS_EMPTY_ARRAY (-2) /* a field which is an array 'type[0]' */ - typedef union { unsigned char m_char; unsigned short m_short; @@ -52,6 +41,70 @@ /************************************************************/ +struct cfieldobject_s { + PyObject_HEAD + CTypeDescrObject *cf_type; + Py_ssize_t cf_offset; + short cf_bitshift; /* >= 0: bitshift; or BS_REGULAR or BS_EMPTY_ARRAY */ + short cf_bitsize; + struct cfieldobject_s *cf_next; +}; +#define BS_REGULAR (-1) /* a regular field, not with bitshift */ +#define BS_EMPTY_ARRAY (-2) /* a field which is an array 'type[0]' */ + +static void +cfield_dealloc(CFieldObject *cf) +{ + Py_DECREF(cf->cf_type); + PyObject_Del(cf); +} + +#undef OFF +#define OFF(x) offsetof(CFieldObject, x) + +static PyMemberDef cfield_members[] = { + {"type", T_OBJECT, OFF(cf_type), READONLY}, + {"offset", T_PYSSIZET, OFF(cf_offset), READONLY}, + {"bitshift", T_SHORT, OFF(cf_bitshift), READONLY}, + {"bitsize", T_SHORT, OFF(cf_bitsize), READONLY}, + {NULL} /* Sentinel */ +}; +#undef OFF + +static PyTypeObject CField_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "zeffir.CField", + sizeof(CFieldObject), + 0, + (destructor)cfield_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + cfield_members, /* tp_members */ +}; + +/************************************************************/ + static int CDataObject_Or_PyFloat_Check(PyObject *ob) { @@ -343,10 +396,10 @@ return NULL; } +static PyObject *convert_to_object_bitfield(char *data, CFieldObject *cf) +{ + abort(); #if 0 -static PyObject * -convert_to_object_bitfield(char *data, CFieldObject *cf) -{ CTypeDescrObject *ct = cf->cf_type; /*READ(data, ct->ct_size)*/ @@ -377,8 +430,8 @@ else return PyLong_FromUnsignedLongLong(value); } +#endif } -#endif static int _convert_overflow(PyObject *init, const char *ct_name) { @@ -1237,6 +1290,58 @@ return convert_from_object(c, ctitem, v); } +//2172 +static PyObject *cdata_getattro(CDataObject *cd, PyObject *attr) +{ + CFieldObject *cf; + CTypeDescrObject *ct = cd->c_type; + + if (ct->ct_flags & CT_POINTER) + ct = ct->ct_itemdescr; + + if ((ct->ct_flags & (CT_STRUCT|CT_UNION)) && ct->ct_stuff != NULL) { + cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr); + if (cf != NULL) { + /* read the field 'cf' */ + char *data = cd->c_data + cf->cf_offset; + if (cf->cf_bitshift == BS_REGULAR) + return convert_to_object(data, cf->cf_type); + else if (cf->cf_bitshift == BS_EMPTY_ARRAY) + return new_simple_cdata(data, + (CTypeDescrObject *)cf->cf_type->ct_stuff); + else + return convert_to_object_bitfield(data, cf); + } + } + return PyObject_GenericGetAttr((PyObject *)cd, attr); +} + +//2198 +static int cdata_setattro(CDataObject *cd, PyObject *attr, PyObject *value) +{ + CFieldObject *cf; + CTypeDescrObject *ct = cd->c_type; + + if (ct->ct_flags & CT_POINTER) + ct = ct->ct_itemdescr; + + if ((ct->ct_flags & (CT_STRUCT|CT_UNION)) && ct->ct_stuff != NULL) { + cf = (CFieldObject *)PyDict_GetItem(ct->ct_stuff, attr); + if (cf != NULL) { + /* write the field 'cf' */ + if (value != NULL) { + return convert_field_from_object(cd->c_data, cf, value); + } + else { + PyErr_SetString(PyExc_AttributeError, + "cannot delete struct field"); + return -1; + } + } + } + return PyObject_GenericSetAttr((PyObject *)cd, attr, value); +} + static PyMappingMethods CData_as_mapping = { (lenfunc)cdata_length, /*mp_length*/ @@ -1261,8 +1366,8 @@ 0,//(hashfunc)cdata_hash, /* tp_hash */ 0,//(ternaryfunc)cdata_call, /* tp_call */ 0, /* tp_str */ - 0,//(getattrofunc)cdata_getattro, /* tp_getattro */ - 0,//(setattrofunc)cdata_setattro, /* tp_setattro */ + (getattrofunc)cdata_getattro, /* tp_getattro */ + (setattrofunc)cdata_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ 0, /* tp_doc */ diff --git a/zeffir/test/struct.crx b/zeffir/test/struct.crx new file mode 100644 --- /dev/null +++ b/zeffir/test/struct.crx @@ -0,0 +1,13 @@ +typedef struct { + int a; + long b; +} mystruct_t; + + +// CREFLECT: start + +typedef struct { + int a, b; +} mystruct_t; + +// CREFLECT: end diff --git a/zeffir/test/test_struct.py b/zeffir/test/test_struct.py new file mode 100644 --- /dev/null +++ b/zeffir/test/test_struct.py @@ -0,0 +1,10 @@ +import support + + +def test_simple_struct(): + ffi, lib = support.compile_and_open('struct') + p = ffi.new('mystruct_t *', [-5, 0x600112233]) + assert p.a == -5 + assert p.b == 0x600112233 + p.b += 1 + assert p.b == 0x600112234 diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c --- a/zeffir/zeffir.c +++ b/zeffir/zeffir.c @@ -41,6 +41,8 @@ return; if (PyType_Ready(&CTypeDescr_Type) < 0) return; + if (PyType_Ready(&CField_Type) < 0) + return; if (PyType_Ready(&CData_Type) < 0) return; if (PyType_Ready(&CDataOwning_Type) < 0) diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h --- a/zeffir/zeffir.h +++ b/zeffir/zeffir.h @@ -6,7 +6,7 @@ static PyTypeObject ZefFFI_Type; static PyTypeObject CTypeDescr_Type; -//static PyTypeObject CField_Type; +static PyTypeObject CField_Type; static PyTypeObject CData_Type; static PyTypeObject CDataOwning_Type; static PyTypeObject CDataOwningGC_Type; From noreply at buildbot.pypy.org Fri Dec 5 16:56:00 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 16:56:00 +0100 (CET) Subject: [pypy-commit] creflect default: ffi.NULL Message-ID: <20141205155600.1A3751D2A0C@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r165:64bdd79c09b5 Date: 2014-12-05 16:47 +0100 http://bitbucket.org/cffi/creflect/changeset/64bdd79c09b5/ Log: ffi.NULL diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -6,7 +6,6 @@ _crx_builder_t cb; ZefLibObject *lib; PyObject *l_dict; - ZefFFIObject *ffi; PyObject *types_dict; } zeffir_builder_t; @@ -837,7 +836,6 @@ }, lib, /* lib */ lib->l_dict, /* l_dict */ - ffi, /* ffi */ ffi->types_dict, /* types_dict */ }; crxmain(&builder.cb); @@ -845,7 +843,7 @@ return PyErr_Occurred() ? -1 : 0; } -static CTypeDescrObject *parse_c_decl(ZefFFIObject *ffi, const char *str) +static CTypeDescrObject *parse_c_decl(PyObject *types_dict, const char *str) { zeffir_builder_t builder = { { @@ -875,8 +873,7 @@ }, NULL, /* lib */ NULL, /* l_dict */ - ffi, /* ffi */ - ffi->types_dict, /* types_dict */ + types_dict, /* types_dict */ }; _crx_qual_type result; diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -126,7 +126,8 @@ if (x != NULL && CTypeDescr_Check(x)) return (CTypeDescrObject *)x; - CTypeDescrObject *ct = parse_c_decl(ffi, PyText_AS_UTF8(arg)); + CTypeDescrObject *ct = parse_c_decl(ffi->types_dict, + PyText_AS_UTF8(arg)); if (ct == NULL) return NULL; diff --git a/zeffir/test/test_basic.py b/zeffir/test/test_basic.py --- a/zeffir/test/test_basic.py +++ b/zeffir/test/test_basic.py @@ -31,3 +31,8 @@ def test_types(): ffi = support.new_ffi() assert ffi.types == {} + +def test_NULL(): + ffi = support.new_ffi() + assert repr(ffi.NULL) == "" + assert repr(type(ffi).NULL) == "" diff --git a/zeffir/test/test_struct.py b/zeffir/test/test_struct.py --- a/zeffir/test/test_struct.py +++ b/zeffir/test/test_struct.py @@ -1,3 +1,4 @@ +import py import support @@ -8,3 +9,9 @@ assert p.b == 0x600112233 p.b += 1 assert p.b == 0x600112234 + +def test_addressof(): + py.test.skip("in-progress") + ffi, lib = support.compile_and_open('struct') + p = ffi.new('mystruct_t *') + ffi.addressof(p[0], 'a') diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c --- a/zeffir/zeffir.c +++ b/zeffir/zeffir.c @@ -70,6 +70,24 @@ if (PyModule_AddObject(m, "error", ZefError) < 0) return; + { + CTypeDescrObject *ctvoidp; + PyObject *cdnull; + PyObject *d1 = PyDict_New(); + if (d1 == NULL) + return; + + ctvoidp = parse_c_decl(d1, "void*"); + if (ctvoidp) { + cdnull = new_simple_cdata(NULL, ctvoidp); + if (cdnull) + PyDict_SetItemString(ZefFFI_Type.tp_dict, "NULL", cdnull); + } + Py_DECREF(d1); + if (PyErr_Occurred()) + return; + } + if (PyDict_SetItemString(ZefFFI_Type.tp_dict, "error", ZefError) < 0) return; } diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h --- a/zeffir/zeffir.h +++ b/zeffir/zeffir.h @@ -15,7 +15,7 @@ static int lib_close(ZefLibObject *); static int load_creflect_main(ZefFFIObject *, ZefLibObject *); -static CTypeDescrObject *parse_c_decl(ZefFFIObject *ffi, const char *str); +static CTypeDescrObject *parse_c_decl(PyObject *types_dict, const char *str); static int convert_from_object(char *, CTypeDescrObject *, PyObject *); static int convert_from_object_bitfield(char *, CFieldObject *, PyObject *); From noreply at buildbot.pypy.org Fri Dec 5 16:56:01 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 16:56:01 +0100 (CET) Subject: [pypy-commit] creflect default: ffi.string Message-ID: <20141205155601.6E8DA1D2A0C@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r166:030aea977e7e Date: 2014-12-05 16:52 +0100 http://bitbucket.org/cffi/creflect/changeset/030aea977e7e/ Log: ffi.string diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -255,12 +255,75 @@ return (PyObject *)cd; } +static PyObject *ffi_string(PyObject *self, PyObject *args) +{ + CDataObject *cd; + Py_ssize_t maxlen = -1; + if (!PyArg_ParseTuple(args, "O!|n:string", + &CData_Type, &cd, &maxlen)) + return NULL; + + if (cd->c_type->ct_itemdescr != NULL && + cd->c_type->ct_itemdescr->ct_flags & (CT_PRIMITIVE_CHAR | + CT_PRIMITIVE_SIGNED | + CT_PRIMITIVE_UNSIGNED)) { + Py_ssize_t length = maxlen; + if (cd->c_data == NULL) { + PyObject *s = cdata_repr(cd); + if (s != NULL) { + PyErr_Format(PyExc_RuntimeError, + "cannot use string() on %s", + PyText_AS_UTF8(s)); + Py_DECREF(s); + } + return NULL; + } + if (length < 0 && cd->c_type->ct_flags & CT_ARRAY) { + length = get_array_length(cd); + } + if (cd->c_type->ct_itemdescr->ct_size == sizeof(char)) { + const char *start = cd->c_data; + if (length < 0) { + /*READ(start, 1)*/ + length = strlen(start); + /*READ(start, length)*/ + } + else { + const char *end; + /*READ(start, length)*/ + end = (const char *)memchr(start, 0, length); + if (end != NULL) + length = end - start; + } + return PyBytes_FromStringAndSize(start, length); + } + } + else if (cd->c_type->ct_flags & CT_IS_ENUM) { + abort(); + //return convert_cdata_to_enum_string(cd, 0); + } + else if (cd->c_type->ct_flags & CT_IS_BOOL) { + /* fall through to TypeError */ + } + else if (cd->c_type->ct_flags & (CT_PRIMITIVE_CHAR | + CT_PRIMITIVE_SIGNED | + CT_PRIMITIVE_UNSIGNED)) { + /*READ(cd->c_data, cd->c_type->ct_size)*/ + if (cd->c_type->ct_size == sizeof(char)) + return PyBytes_FromStringAndSize(cd->c_data, 1); + } + PyErr_Format(PyExc_TypeError, "string(): unexpected cdata '%s' argument", + cd->c_type->ct_name); + return NULL; +} + static PyMethodDef ffi_methods[] = { {"close_library", ffi_close_library, METH_VARARGS | METH_STATIC}, {"load_library", (PyCFunction)ffi_load_library, METH_VARARGS | METH_KEYWORDS}, {"new", (PyCFunction)ffi_new, METH_VARARGS}, {"sizeof", (PyCFunction)ffi_sizeof, METH_O}, + {"string", (PyCFunction)ffi_string, METH_VARARGS}, {"typeof", (PyCFunction)ffi_typeof, METH_O}, {NULL} }; diff --git a/zeffir/test/test_basic.py b/zeffir/test/test_basic.py --- a/zeffir/test/test_basic.py +++ b/zeffir/test/test_basic.py @@ -36,3 +36,11 @@ ffi = support.new_ffi() assert repr(ffi.NULL) == "" assert repr(type(ffi).NULL) == "" + +def test_string(): + ffi = support.new_ffi() + p = ffi.new("char[]", "hello\x00world") + assert ffi.string(p) == "hello" + for i in range(50): + p = ffi.new("char[]", "12345678" * i) + assert ffi.string(p) == "12345678" * i From noreply at buildbot.pypy.org Fri Dec 5 16:56:02 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 16:56:02 +0100 (CET) Subject: [pypy-commit] creflect default: equality on cdata's Message-ID: <20141205155602.95F351D2CF0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r167:6aee42c289d3 Date: 2014-12-05 16:56 +0100 http://bitbucket.org/cffi/creflect/changeset/6aee42c289d3/ Log: equality on cdata's diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -1050,6 +1050,52 @@ } } +//1769 +static PyObject *cdata_richcompare(PyObject *v, PyObject *w, int op) +{ + int res; + PyObject *pyres; + char *v_cdata, *w_cdata; + + assert(CData_Check(v)); + if (!CData_Check(w)) { + pyres = Py_NotImplemented; + goto done; + } + + if ((op != Py_EQ && op != Py_NE) && + ((((CDataObject *)v)->c_type->ct_flags & CT_PRIMITIVE_ANY) || + (((CDataObject *)w)->c_type->ct_flags & CT_PRIMITIVE_ANY))) + goto Error; + + v_cdata = ((CDataObject *)v)->c_data; + w_cdata = ((CDataObject *)w)->c_data; + + switch (op) { + case Py_EQ: res = (v_cdata == w_cdata); break; + case Py_NE: res = (v_cdata != w_cdata); break; + case Py_LT: res = (v_cdata < w_cdata); break; + case Py_LE: res = (v_cdata <= w_cdata); break; + case Py_GT: res = (v_cdata > w_cdata); break; + case Py_GE: res = (v_cdata >= w_cdata); break; + default: res = -1; + } + pyres = res ? Py_True : Py_False; + done: + Py_INCREF(pyres); + return pyres; + + Error: + PyErr_SetString(PyExc_TypeError, + "cannot do comparison on a primitive cdata"); + return NULL; +} + +static long cdata_hash(CDataObject *cd) +{ + return _Py_HashPointer(cd->c_data); +} + //1815 static Py_ssize_t cdata_length(CDataObject *cd) { @@ -1363,7 +1409,7 @@ 0,//&CData_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ &CData_as_mapping, /* tp_as_mapping */ - 0,//(hashfunc)cdata_hash, /* tp_hash */ + (hashfunc)cdata_hash, /* tp_hash */ 0,//(ternaryfunc)cdata_call, /* tp_call */ 0, /* tp_str */ (getattrofunc)cdata_getattro, /* tp_getattro */ @@ -1373,7 +1419,7 @@ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0,//cdata_richcompare, /* tp_richcompare */ + cdata_richcompare, /* tp_richcompare */ offsetof(CDataObject, c_weakreflist), /* tp_weaklistoffset */ 0,//(getiterfunc)cdata_iter, /* tp_iter */ 0, /* tp_iternext */ diff --git a/zeffir/test/test_global.py b/zeffir/test/test_global.py --- a/zeffir/test/test_global.py +++ b/zeffir/test/test_global.py @@ -24,3 +24,9 @@ q = ffi.new("short *", -555) lib.myglobptr = q assert lib.myglobptr[0] == -555 + +def test_eq(): + ffi, lib = support.compile_and_open('global') + assert lib.myglobptr is not lib.myglobptr + assert lib.myglobptr == lib.myglobptr + assert hash(lib.myglobptr) == hash(lib.myglobptr) From noreply at buildbot.pypy.org Fri Dec 5 17:06:15 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 17:06:15 +0100 (CET) Subject: [pypy-commit] creflect default: functions returning void Message-ID: <20141205160615.B23F01D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r168:c56076ff1eb2 Date: 2014-12-05 17:06 +0100 http://bitbucket.org/cffi/creflect/changeset/c56076ff1eb2/ Log: functions returning void diff --git a/zeffir/cfunc.c b/zeffir/cfunc.c --- a/zeffir/cfunc.c +++ b/zeffir/cfunc.c @@ -115,6 +115,7 @@ void *llargs[nargs]; char *llbuffer; size_t lloffset; + int returns_void; actualnargs = PyTuple_Size(args); if (actualnargs != nargs) { @@ -126,7 +127,8 @@ } llbuffer = alloca(zfs->zfs_size_args); - lloffset = zfs->zfs_ret->ct_size; + returns_void = (zfs->zfs_ret->ct_flags & CT_VOID); + lloffset = returns_void ? 0 : zfs->zfs_ret->ct_size; for (i = 0; i < nargs; i++) { CTypeDescrObject *ct = zfs->zfs_args[i]; @@ -163,6 +165,10 @@ zfs->zfs_trampl(llargs, llbuffer); + if (returns_void) { + Py_INCREF(Py_None); + return Py_None; + } return convert_to_object(llbuffer, zfs->zfs_ret); } @@ -186,8 +192,8 @@ zfs->zfs_ret = ret; Py_INCREF(ret); - assert(ret->ct_size >= 0); - size = ret->ct_size; + size = (ret->ct_flags & CT_VOID) ? 0 : ret->ct_size; + assert(size >= 0); for (i = 0; i < nargs; i++) { CTypeDescrObject *ct = args[i].type; diff --git a/zeffir/test/function.crx b/zeffir/test/function.crx --- a/zeffir/test/function.crx +++ b/zeffir/test/function.crx @@ -11,10 +11,18 @@ return result; } +void returning_nothing(char *p) +{ + *p++ = 'O'; + *p++ = 'K'; + *p++ = 0; +} + // CREFLECT: start int simple_function(int); int add_from_array(int array[], int count); +void returning_nothing(char *); // CREFLECT: end diff --git a/zeffir/test/test_function.py b/zeffir/test/test_function.py --- a/zeffir/test/test_function.py +++ b/zeffir/test/test_function.py @@ -20,3 +20,9 @@ res = lib.add_from_array([30, 2, 10], 3) assert type(res) is int assert res == 42 + +def test_function_returning_nothing(): + ffi, lib = support.compile_and_open('function') + p = ffi.new("char[]", 10) + lib.returning_nothing(p) + assert ffi.string(p) == "OK" diff --git a/zeffir/test/test_global.py b/zeffir/test/test_global.py --- a/zeffir/test/test_global.py +++ b/zeffir/test/test_global.py @@ -30,3 +30,5 @@ assert lib.myglobptr is not lib.myglobptr assert lib.myglobptr == lib.myglobptr assert hash(lib.myglobptr) == hash(lib.myglobptr) + lib.myglobptr = ffi.NULL + assert lib.myglobptr == ffi.NULL From noreply at buildbot.pypy.org Fri Dec 5 17:16:00 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 17:16:00 +0100 (CET) Subject: [pypy-commit] creflect default: Demo files (direct ports from hg/cffi/demo) Message-ID: <20141205161600.498EA1D2A0C@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r169:fe2fdb378e56 Date: 2014-12-05 17:15 +0100 http://bitbucket.org/cffi/creflect/changeset/fe2fdb378e56/ Log: Demo files (direct ports from hg/cffi/demo) diff --git a/demo/gmp.crx b/demo/gmp.crx new file mode 100644 --- /dev/null +++ b/demo/gmp.crx @@ -0,0 +1,13 @@ +#include + + +/* CREFLECT: start */ + +typedef struct { } MP_INT; +typedef MP_INT mpz_t[1]; + +int mpz_init_set_str (MP_INT *dest_integer, char *src_cstring, int base); +void mpz_add (MP_INT *sum, MP_INT *addend1, MP_INT *addend2); +char * mpz_get_str (char *string, int base, MP_INT *integer); + +/* CREFLECT: end */ diff --git a/demo/gmp.py b/demo/gmp.py new file mode 100644 --- /dev/null +++ b/demo/gmp.py @@ -0,0 +1,15 @@ +import sys +import zeffir + +ffi = zeffir.FFI() +lib = ffi.load_library("gmp-creflect", relative_to=__file__) + +a = ffi.new("mpz_t") +b = ffi.new("mpz_t") + +lib.mpz_init_set_str(a, sys.argv[1], 10) # Assume decimal integers +lib.mpz_init_set_str(b, sys.argv[2], 10) # Assume decimal integers +lib.mpz_add(a, a, b) # a=a+b + +s = lib.mpz_get_str(ffi.NULL, 10, a) +print ffi.string(s) diff --git a/demo/readdir2.crx b/demo/readdir2.crx new file mode 100644 --- /dev/null +++ b/demo/readdir2.crx @@ -0,0 +1,29 @@ +#ifndef _ATFILE_SOURCE +# define _ATFILE_SOURCE +#endif +#ifndef _BSD_SOURCE +# define _BSD_SOURCE +#endif +#include +#include +#include + + +/* CREFLECT: start */ + +typedef ... DIR; + +struct dirent { + unsigned char d_type; /* type of file; not supported + by all file system types */ + char d_name[]; /* filename */ +}; + +int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); +int openat(int dirfd, const char *pathname, int flags); +DIR *fdopendir(int fd); +int closedir(DIR *dirp); + +#define DT_DIR ... + +/* CREFLECT: end */ diff --git a/demo/readdir2.py b/demo/readdir2.py new file mode 100644 --- /dev/null +++ b/demo/readdir2.py @@ -0,0 +1,32 @@ +import zeffir + +ffi = zeffir.FFI() +lib = ffi.load_library("readdir2-creflect", relative_to=__file__) + +p = ffi.new("struct dirent *") +print p + + +def walk(basefd, path): + print '{', path + dirfd = lib.openat(basefd, path, 0) + if dirfd < 0: + # error in openat() + return + dir = lib.fdopendir(dirfd) + dirent = ffi.new("struct dirent *") + result = ffi.new("struct dirent **") + while True: + if lib.readdir_r(dir, dirent, result): + # error in readdir_r() + break + if result[0] == ffi.NULL: + break + name = ffi.string(dirent.d_name) + print '%3d %s' % (dirent.d_type, name) + if dirent.d_type == lib.DT_DIR and name != '.' and name != '..': + walk(dirfd, name) + lib.closedir(dir) + print '}' + +walk(-1, "/tmp") From noreply at buildbot.pypy.org Fri Dec 5 17:31:13 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 17:31:13 +0100 (CET) Subject: [pypy-commit] creflect default: add a Makefile Message-ID: <20141205163113.5F2D61D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r170:fa167c323433 Date: 2014-12-05 17:25 +0100 http://bitbucket.org/cffi/creflect/changeset/fa167c323433/ Log: add a Makefile diff --git a/demo/Makefile b/demo/Makefile new file mode 100644 --- /dev/null +++ b/demo/Makefile @@ -0,0 +1,16 @@ +ALL = zeffir.so libreaddir2-creflect.so libgmp-creflect.so + +all: $(ALL) + +%-creflect.c: %.crx + PYTHONPATH=.. ../bin/creflect $*.crx $*-creflect.c + +lib%-creflect.so: %-creflect.c + gcc -g -shared -fPIC $*-creflect.c -o lib$*-creflect.so -I../creflect + +zeffir.so: ../zeffir/*.h ../zeffir/*.c + gcc -g -shared -fPIC ../zeffir/zeffir.c -o zeffir.so -I/usr/include/python2.7 + + +clean: + rm -f $(ALL) readdir2-creflect.c From noreply at buildbot.pypy.org Fri Dec 5 17:31:14 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 17:31:14 +0100 (CET) Subject: [pypy-commit] creflect default: fix Message-ID: <20141205163114.791421D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r171:60242be937cb Date: 2014-12-05 17:31 +0100 http://bitbucket.org/cffi/creflect/changeset/60242be937cb/ Log: fix diff --git a/demo/Makefile b/demo/Makefile --- a/demo/Makefile +++ b/demo/Makefile @@ -5,6 +5,9 @@ %-creflect.c: %.crx PYTHONPATH=.. ../bin/creflect $*.crx $*-creflect.c +libgmp-creflect.so: gmp-creflect.c + gcc -g -shared -fPIC gmp-creflect.c -o libgmp-creflect.so -lgmp -I../creflect + lib%-creflect.so: %-creflect.c gcc -g -shared -fPIC $*-creflect.c -o lib$*-creflect.so -I../creflect From noreply at buildbot.pypy.org Fri Dec 5 17:44:59 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Fri, 5 Dec 2014 17:44:59 +0100 (CET) Subject: [pypy-commit] pypy framestate: Add dummy analyze_signals pass to bc_reader.build_flow() Message-ID: <20141205164459.4E4941D28F0@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74832:3d32a761abce Date: 2014-12-03 13:50 +0000 http://bitbucket.org/pypy/pypy/changeset/3d32a761abce/ Log: Add dummy analyze_signals pass to bc_reader.build_flow() diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -214,9 +214,16 @@ block = self.curr_block graph.pos_index[instr.offset] = block, len(block.operations) instr.bc_flow(self) + self.analyze_signals(graph) self.check_graph() return graph + def analyze_signals(self, graph): + for block in graph.iterblocks(): + self.curr_block = block + for instr in block: + instr.do_signals(self) + def check_graph(self): for b in self.blocks: if not b._exits: @@ -263,6 +270,17 @@ instr = self.read(offset) yield instr + def iterblocks(self): + block = self.entry + seen = set() + stack = block._exits[:] + while stack: + block = stack.pop() + if block not in seen: + yield block + seen.add(block) + stack.extend(block._exits[:]) + def all_blocks(self): return set(x[0] for x in self.pos_index.values()) @@ -338,15 +356,18 @@ self.arg = arg self.offset = offset - def eval(self, ctx): - pass - def bc_flow(self, reader): reader.curr_block.operations.append(self) if self.has_jump(): reader.end_block() reader.get_block_at(self.arg) + def do_signals(self, reader): + pass + + def eval(self, ctx): + pass + def has_jump(self): return self.num in opcode.hasjrel or self.num in opcode.hasjabs From noreply at buildbot.pypy.org Fri Dec 5 17:45:00 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Fri, 5 Dec 2014 17:45:00 +0100 (CET) Subject: [pypy-commit] pypy framestate: begin implementing analyze_signals() Message-ID: <20141205164500.9DBA91D28F0@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74833:3fbf13809a73 Date: 2014-12-03 17:32 +0000 http://bitbucket.org/pypy/pypy/changeset/3fbf13809a73/ Log: begin implementing analyze_signals() diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -221,8 +221,12 @@ def analyze_signals(self, graph): for block in graph.iterblocks(): self.curr_block = block + block.init_blockstack() + self.blockstack = block.blockstack[:] for instr in block: instr.do_signals(self) + for exit in block._exits: + exit.set_blockstack(self.blockstack) def check_graph(self): for b in self.blocks: @@ -294,7 +298,7 @@ def __init__(self): self.parents = set() self._exits = [] - self.blockstack = [] + self.blockstack = None def __getitem__(self, i): return self.operations[i] @@ -320,6 +324,16 @@ def startpos(self): return self.operations[0].offset + def init_blockstack(self): + if self.blockstack is None: + self.blockstack = [] + + def set_blockstack(self, blockstack): + if self.blockstack is None: + self.blockstack = blockstack + else: + assert self.blockstack == blockstack + def split_at(self, i): if i == 0 or i == len(self.operations): return [self] @@ -546,7 +560,9 @@ def bc_flow(self, reader): reader.curr_block.operations.append(self) self.target = reader.get_block_at(self.arg) - reader.curr_block.blockstack.append(self.make_block(-1)) + + def do_signals(self, reader): + reader.blockstack.append(self.make_block(-1)) def eval(self, ctx): block = self.make_block(ctx.stackdepth) @@ -590,6 +606,16 @@ ctx.blockstack.append(block) ctx.pushvalue(w_result) + at bc_reader.register_opcode +class POP_BLOCK(BCInstruction): + def do_signals(self, reader): + reader.blockstack.pop() + + def eval(self, ctx): + block = ctx.blockstack.pop() + block.cleanupstack(ctx) # the block knows how to clean up the value stack + + _unary_ops = [ ('UNARY_POSITIVE', op.pos), ('UNARY_NEGATIVE', op.neg), diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -652,10 +652,6 @@ signal = self.popvalue() raise signal - def POP_BLOCK(self, oparg): - block = self.blockstack.pop() - block.cleanupstack(self) # the block knows how to clean up the value stack - def YIELD_VALUE(self, _): assert self.pycode.is_generator w_result = self.popvalue() From noreply at buildbot.pypy.org Fri Dec 5 17:45:01 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Fri, 5 Dec 2014 17:45:01 +0100 (CET) Subject: [pypy-commit] pypy framestate: move stuff around Message-ID: <20141205164501.E6A9F1D28F0@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74834:ac849f367719 Date: 2014-12-03 23:57 +0000 http://bitbucket.org/pypy/pypy/changeset/ac849f367719/ Log: move stuff around diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -312,15 +312,18 @@ return w_condition.value return self.recorder.guessbool(self, w_condition) - def record(self, spaceop): + def maybe_merge(self): recorder = self.recorder if getattr(recorder, 'final_state', None) is not None: self.mergeblock(recorder.crnt_block, recorder.final_state) raise StopFlowing + + def record(self, spaceop): spaceop.offset = self.last_offset - recorder.append(spaceop) + self.recorder.append(spaceop) def do_op(self, op): + self.maybe_merge() self.record(op) self.guessexception(op.canraise) return op.result @@ -410,14 +413,8 @@ if newstate is not None: break else: - newstate = currentstate.copy() - newblock = SpamBlock(newstate) - # unconditionally link the current block to the newblock - outputargs = currentstate.getoutputargs(newstate) - link = Link(outputargs, newblock) - currentblock.closeblock(link) + newblock = self.make_next_block(currentblock, currentstate) candidates.insert(0, newblock) - self.pendingblocks.append(newblock) return if newstate.matches(block.framestate): @@ -447,6 +444,16 @@ candidates.insert(0, newblock) self.pendingblocks.append(newblock) + def make_next_block(self, block, state): + newstate = state.copy() + newblock = SpamBlock(newstate) + # unconditionally link the current block to the newblock + outputargs = state.getoutputargs(newstate) + link = Link(outputargs, newblock) + block.closeblock(link) + self.pendingblocks.append(newblock) + return newblock + # hack for unrolling iterables, don't use this def replace_in_stack(self, oldvalue, newvalue): w_new = Constant(newvalue) From noreply at buildbot.pypy.org Fri Dec 5 17:45:03 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Fri, 5 Dec 2014 17:45:03 +0100 (CET) Subject: [pypy-commit] pypy framestate: kill pos_index Message-ID: <20141205164503.4EACD1D28F0@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74835:d3503f9756b8 Date: 2014-12-04 00:42 +0000 http://bitbucket.org/pypy/pypy/changeset/d3503f9756b8/ Log: kill pos_index diff --git a/rpython/flowspace/bytecode.py b/rpython/flowspace/bytecode.py --- a/rpython/flowspace/bytecode.py +++ b/rpython/flowspace/bytecode.py @@ -176,10 +176,6 @@ if offset < self.next_offset: i_block, i_instr = self.find_position(offset) split = self.blocks[i_block].split_at(i_instr) - if len(split) == 2: - new_block = split[1] - for i, instr in enumerate(new_block.operations): - self.graph.pos_index[instr.offset] = new_block, i self.blocks[i_block:i_block + 1] = split return split[-1] else: @@ -211,8 +207,6 @@ self.needs_new_block = False self.graph = graph = BytecodeGraph(self.blocks[0]) for instr in self._iter_instr(code): - block = self.curr_block - graph.pos_index[instr.offset] = block, len(block.operations) instr.bc_flow(self) self.analyze_signals(graph) self.check_graph() @@ -245,10 +239,9 @@ def __init__(self, startblock): self.entry = EntryBlock() self.entry.set_exits([startblock]) - self.pos_index = {} def read(self, pos): - bc_block, i = self.pos_index[pos] + bc_block, i = pos return bc_block[i] def next_pos(self): @@ -261,17 +254,9 @@ else: return block, i - def get_position(self, offset): - return self.pos_index[offset] - - def get_offset(self, position): - block, i = position - return block[i].offset - def iter_instr(self): while True: - offset = self.get_offset(self.curr_position) - instr = self.read(offset) + instr = self.read(self.curr_position) yield instr def iterblocks(self): @@ -286,7 +271,7 @@ stack.extend(block._exits[:]) def all_blocks(self): - return set(x[0] for x in self.pos_index.values()) + return list(self.iterblocks()) def dump(self): blocks = sorted(self.all_blocks(), key=lambda b: b.startpos) From noreply at buildbot.pypy.org Fri Dec 5 17:45:04 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Fri, 5 Dec 2014 17:45:04 +0100 (CET) Subject: [pypy-commit] pypy framestate: rm force keyword from ctx.guessexception() Message-ID: <20141205164504.8976D1D28F0@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74836:1c2990ad5a58 Date: 2014-12-04 19:28 +0000 http://bitbucket.org/pypy/pypy/changeset/1c2990ad5a58/ Log: rm force keyword from ctx.guessexception() diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -328,14 +328,14 @@ self.guessexception(op.canraise) return op.result - def guessexception(self, exceptions, force=False): + def guessexception(self, exceptions): """ Catch possible exceptions implicitly. """ if not exceptions: return - if not force and not any(isinstance(block, (ExceptBlock, FinallyBlock)) - for block in self.blockstack): + if not any(isinstance(block, (ExceptBlock, FinallyBlock)) + for block in self.blockstack): # The implicit exception wouldn't be caught and would later get # removed, so don't bother creating it. return diff --git a/rpython/flowspace/operation.py b/rpython/flowspace/operation.py --- a/rpython/flowspace/operation.py +++ b/rpython/flowspace/operation.py @@ -517,7 +517,7 @@ ctx.replace_in_stack(it, next_unroller) return const(v) w_item = ctx.do_op(self) - ctx.guessexception([StopIteration, RuntimeError], force=True) + ctx.recorder.guessexception(ctx, StopIteration, RuntimeError) return w_item class GetAttr(SingleDispatchMixin, HLOperation): From noreply at buildbot.pypy.org Fri Dec 5 17:45:05 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Fri, 5 Dec 2014 17:45:05 +0100 (CET) Subject: [pypy-commit] pypy framestate: extract method ctx.has_exc_handler() Message-ID: <20141205164505.C99541D28F0@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74837:1488ee7e209b Date: 2014-12-05 15:23 +0000 http://bitbucket.org/pypy/pypy/changeset/1488ee7e209b/ Log: extract method ctx.has_exc_handler() diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -334,12 +334,13 @@ """ if not exceptions: return - if not any(isinstance(block, (ExceptBlock, FinallyBlock)) - for block in self.blockstack): - # The implicit exception wouldn't be caught and would later get - # removed, so don't bother creating it. - return - self.recorder.guessexception(self, *exceptions) + # Implicit exceptions are ignored unless they are caught explicitly + if self.has_exc_handler(): + self.recorder.guessexception(self, *exceptions) + + def has_exc_handler(self): + return any(isinstance(block, (ExceptBlock, FinallyBlock)) + for block in self.blockstack) def build_flow(self): graph = self.graph From noreply at buildbot.pypy.org Fri Dec 5 17:45:07 2014 From: noreply at buildbot.pypy.org (rlamy) Date: Fri, 5 Dec 2014 17:45:07 +0100 (CET) Subject: [pypy-commit] pypy framestate: move handling of escaping FlowSignals to nomoreblocks() Message-ID: <20141205164507.1AE3B1D28F0@cobra.cs.uni-duesseldorf.de> Author: Ronan Lamy Branch: framestate Changeset: r74838:7c14497ac340 Date: 2014-12-05 16:44 +0000 http://bitbucket.org/pypy/pypy/changeset/7c14497ac340/ Log: move handling of escaping FlowSignals to nomoreblocks() diff --git a/rpython/flowspace/flowcontext.py b/rpython/flowspace/flowcontext.py --- a/rpython/flowspace/flowcontext.py +++ b/rpython/flowspace/flowcontext.py @@ -368,35 +368,8 @@ next_position = next_block, 0 bc_graph.curr_position = next_position self.recorder.final_state = self.getstate(next_position) - - except RaiseImplicit as e: - w_exc = e.w_exc - if isinstance(w_exc.w_type, Constant): - exc_cls = w_exc.w_type.value - else: - exc_cls = Exception - msg = "implicit %s shouldn't occur" % exc_cls.__name__ - w_type = Constant(AssertionError) - w_value = Constant(AssertionError(msg)) - link = Link([w_type, w_value], self.graph.exceptblock) - self.recorder.crnt_block.closeblock(link) - - except Raise as e: - w_exc = e.w_exc - if w_exc.w_type == const(ImportError): - msg = 'import statement always raises %s' % e - raise ImportError(msg) - link = Link([w_exc.w_type, w_exc.w_value], self.graph.exceptblock) - self.recorder.crnt_block.closeblock(link) - except StopFlowing: pass - - except Return as exc: - w_result = exc.w_value - link = Link([w_result], self.graph.returnblock) - self.recorder.crnt_block.closeblock(link) - except FlowingError as exc: if exc.ctx is None: exc.ctx = self @@ -474,7 +447,7 @@ if isinstance(signal, block.handles): return block.handle(self, signal) block.cleanupstack(self) - return signal.nomoreblocks() + return signal.nomoreblocks(self) def getlocalvarname(self, index): return self.pycode.co_varnames[index] @@ -1049,7 +1022,7 @@ WHY_CONTINUE, Continue WHY_YIELD not needed """ - def nomoreblocks(self): + def nomoreblocks(self, ctx): raise BytecodeCorruption("misplaced bytecode - should not return") def __eq__(self, other): @@ -1063,8 +1036,10 @@ def __init__(self, w_value): self.w_value = w_value - def nomoreblocks(self): - raise Return(self.w_value) + def nomoreblocks(self, ctx): + w_result = self.w_value + link = Link([w_result], ctx.graph.returnblock) + ctx.recorder.crnt_block.closeblock(link) @property def args(self): @@ -1081,8 +1056,14 @@ def __init__(self, w_exc): self.w_exc = w_exc - def nomoreblocks(self): - raise self + def nomoreblocks(self, ctx): + w_exc = self.w_exc + if w_exc.w_type == const(ImportError): + msg = 'import statement always raises %s' % self + raise ImportError(msg) + link = Link([w_exc.w_type, w_exc.w_value], ctx.graph.exceptblock) + ctx.recorder.crnt_block.closeblock(link) + raise StopFlowing @property def args(self): @@ -1094,6 +1075,18 @@ class RaiseImplicit(Raise): """Signals an exception raised implicitly""" + def nomoreblocks(self, ctx): + w_exc = self.w_exc + if isinstance(w_exc.w_type, Constant): + exc_cls = w_exc.w_type.value + else: + exc_cls = Exception + msg = "implicit %s shouldn't occur" % exc_cls.__name__ + w_type = Constant(AssertionError) + w_value = Constant(AssertionError(msg)) + link = Link([w_type, w_value], ctx.graph.exceptblock) + ctx.recorder.crnt_block.closeblock(link) + raise StopFlowing class Break(FlowSignal): From noreply at buildbot.pypy.org Fri Dec 5 18:22:58 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 18:22:58 +0100 (CET) Subject: [pypy-commit] cffi default: typo Message-ID: <20141205172258.5C18C1D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r1586:dac8897a6503 Date: 2014-12-05 18:23 +0100 http://bitbucket.org/cffi/cffi/changeset/dac8897a6503/ Log: typo diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -4765,7 +4765,7 @@ CFieldObject *cf; Py_ssize_t offset; - if (!PyArg_ParseTuple(args, "O!O:typeof", + if (!PyArg_ParseTuple(args, "O!O:typeoffsetof", &CTypeDescr_Type, &ct, &fieldname)) return NULL; From noreply at buildbot.pypy.org Fri Dec 5 18:27:28 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 18:27:28 +0100 (CET) Subject: [pypy-commit] creflect default: ffi.offsetof Message-ID: <20141205172728.9F06C1D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r172:233cdddde8f1 Date: 2014-12-05 18:27 +0100 http://bitbucket.org/cffi/creflect/changeset/233cdddde8f1/ Log: ffi.offsetof diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -255,7 +255,7 @@ return (PyObject *)cd; } -static PyObject *ffi_string(PyObject *self, PyObject *args) +static PyObject *ffi_string(ZefFFIObject *self, PyObject *args) { CDataObject *cd; Py_ssize_t maxlen = -1; @@ -317,10 +317,49 @@ return NULL; } +static PyObject *ffi_offsetof(ZefFFIObject *self, PyObject *args) +{ + PyObject *arg; + char *fieldname; + CTypeDescrObject *ct; + CFieldObject *cf; + + if (!PyArg_ParseTuple(args, "Os:offsetof", &arg, &fieldname)) + return NULL; + + ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE); + if (ct == NULL) + return NULL; + + if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) { + PyErr_Format(PyExc_TypeError, + "expected a struct or union ctype, got '%s'", + ct->ct_name); + return NULL; + } + if (ct->ct_stuff == NULL) { + PyErr_Format(PyExc_TypeError, "'%s' is incomplete", ct->ct_name); + return NULL; + } + + cf = (CFieldObject *)PyDict_GetItemString(ct->ct_stuff, fieldname); + if (cf == NULL) { + PyErr_Format(PyExc_KeyError, "'%s' has got no field '%s'", + ct->ct_name, fieldname); + return NULL; + } + if (cf->cf_bitshift >= 0) { + PyErr_SetString(PyExc_TypeError, "not supported for bitfields"); + return NULL; + } + return PyInt_FromSsize_t(cf->cf_offset); +} + static PyMethodDef ffi_methods[] = { {"close_library", ffi_close_library, METH_VARARGS | METH_STATIC}, {"load_library", (PyCFunction)ffi_load_library, METH_VARARGS | METH_KEYWORDS}, + {"offsetof", (PyCFunction)ffi_offsetof, METH_VARARGS}, {"new", (PyCFunction)ffi_new, METH_VARARGS}, {"sizeof", (PyCFunction)ffi_sizeof, METH_O}, {"string", (PyCFunction)ffi_string, METH_VARARGS}, diff --git a/zeffir/test/test_struct.py b/zeffir/test/test_struct.py --- a/zeffir/test/test_struct.py +++ b/zeffir/test/test_struct.py @@ -10,8 +10,7 @@ p.b += 1 assert p.b == 0x600112234 -def test_addressof(): - py.test.skip("in-progress") +def test_offsetof(): ffi, lib = support.compile_and_open('struct') - p = ffi.new('mystruct_t *') - ffi.addressof(p[0], 'a') + assert ffi.offsetof("mystruct_t", "a") == 0 + assert ffi.offsetof("mystruct_t", "b") == ffi.sizeof("long") From noreply at buildbot.pypy.org Fri Dec 5 18:49:34 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 18:49:34 +0100 (CET) Subject: [pypy-commit] creflect default: ffi.addressof Message-ID: <20141205174934.31DFF1D29F4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r173:832fea94ecfa Date: 2014-12-05 18:40 +0100 http://bitbucket.org/cffi/creflect/changeset/832fea94ecfa/ Log: ffi.addressof diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -317,6 +317,26 @@ return NULL; } +static CFieldObject *_ffi_field(CTypeDescrObject *ct, const char *fieldname) +{ + CFieldObject *cf; + if (ct->ct_stuff == NULL) { + PyErr_Format(PyExc_TypeError, "'%s' is incomplete", ct->ct_name); + return NULL; + } + cf = (CFieldObject *)PyDict_GetItemString(ct->ct_stuff, fieldname); + if (cf == NULL) { + PyErr_Format(PyExc_KeyError, "'%s' has got no field '%s'", + ct->ct_name, fieldname); + return NULL; + } + if (cf->cf_bitshift >= 0) { + PyErr_SetString(PyExc_TypeError, "not supported for bitfields"); + return NULL; + } + return cf; +} + static PyObject *ffi_offsetof(ZefFFIObject *self, PyObject *args) { PyObject *arg; @@ -337,25 +357,47 @@ ct->ct_name); return NULL; } - if (ct->ct_stuff == NULL) { - PyErr_Format(PyExc_TypeError, "'%s' is incomplete", ct->ct_name); + cf = _ffi_field(ct, fieldname); + if (cf == NULL) + return NULL; + return PyInt_FromSsize_t(cf->cf_offset); +} + +static PyObject *ffi_addressof(ZefFFIObject *self, PyObject *args) +{ + char *fieldname = NULL; + CDataObject *cd; + CTypeDescrObject *ct; + Py_ssize_t offset; + + if (!PyArg_ParseTuple(args, "O!|z:addressof", &CData_Type, &cd, &fieldname)) + return NULL; + + ct = cd->c_type; + if (fieldname != NULL && ct->ct_flags & CT_POINTER) + ct = ct->ct_itemdescr; + + if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) { + PyErr_Format(PyExc_TypeError, + "expected a struct or union cdata, got '%s'", + ct->ct_name); return NULL; } - cf = (CFieldObject *)PyDict_GetItemString(ct->ct_stuff, fieldname); - if (cf == NULL) { - PyErr_Format(PyExc_KeyError, "'%s' has got no field '%s'", - ct->ct_name, fieldname); - return NULL; + if (fieldname == NULL) { + offset = 0; } - if (cf->cf_bitshift >= 0) { - PyErr_SetString(PyExc_TypeError, "not supported for bitfields"); - return NULL; + else { + CFieldObject *cf = _ffi_field(ct, fieldname); + if (cf == NULL) + return NULL; + offset = cf->cf_offset; } - return PyInt_FromSsize_t(cf->cf_offset); + return new_simple_cdata(cd->c_data + offset, ct); } static PyMethodDef ffi_methods[] = { + {"addressof", (PyCFunction)ffi_addressof,METH_VARARGS}, {"close_library", ffi_close_library, METH_VARARGS | METH_STATIC}, {"load_library", (PyCFunction)ffi_load_library, METH_VARARGS | METH_KEYWORDS}, diff --git a/zeffir/test/test_struct.py b/zeffir/test/test_struct.py --- a/zeffir/test/test_struct.py +++ b/zeffir/test/test_struct.py @@ -14,3 +14,15 @@ ffi, lib = support.compile_and_open('struct') assert ffi.offsetof("mystruct_t", "a") == 0 assert ffi.offsetof("mystruct_t", "b") == ffi.sizeof("long") + +def test_addressof(): + ffi, lib = support.compile_and_open('struct') + p = ffi.new("mystruct_t *") + assert ffi.addressof(p[0]) == p + assert ffi.addressof(p[0], None) == p + assert ffi.addressof(p[0], "a") == p + assert ffi.addressof(p[0], "b") != p + assert ffi.addressof(p[0], "b") == ffi.addressof(p, "b") + assert ffi.addressof(p, "a") == p + py.test.raises(TypeError, ffi.addressof, p) + py.test.raises(TypeError, ffi.addressof, p, None) From noreply at buildbot.pypy.org Fri Dec 5 18:49:35 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 18:49:35 +0100 (CET) Subject: [pypy-commit] creflect default: addressof(Lib, "some_global_var") Message-ID: <20141205174935.7A2B61D29F4@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r174:a9718f1fb634 Date: 2014-12-05 18:49 +0100 http://bitbucket.org/cffi/creflect/changeset/a9718f1fb634/ Log: addressof(Lib, "some_global_var") diff --git a/zeffir/cglob.c b/zeffir/cglob.c --- a/zeffir/cglob.c +++ b/zeffir/cglob.c @@ -61,3 +61,8 @@ { return convert_from_object(zgs->zgs_data, zgs->zgs_type, obj); } + +static PyObject *addressof_global_var(ZefGlobSupportObject *zgs) +{ + return new_simple_cdata(zgs->zgs_data, zgs->zgs_type); +} diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -365,35 +365,69 @@ static PyObject *ffi_addressof(ZefFFIObject *self, PyObject *args) { + PyObject *obj; char *fieldname = NULL; - CDataObject *cd; - CTypeDescrObject *ct; - Py_ssize_t offset; - if (!PyArg_ParseTuple(args, "O!|z:addressof", &CData_Type, &cd, &fieldname)) + if (!PyArg_ParseTuple(args, "O|z:addressof", &obj, &fieldname)) return NULL; - ct = cd->c_type; - if (fieldname != NULL && ct->ct_flags & CT_POINTER) - ct = ct->ct_itemdescr; + if (CData_Check(obj)) { + CDataObject *cd = (CDataObject *)obj; + CTypeDescrObject *ct; + Py_ssize_t offset; - if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) { + ct = cd->c_type; + if (fieldname != NULL && ct->ct_flags & CT_POINTER) + ct = ct->ct_itemdescr; + + if (!(ct->ct_flags & (CT_STRUCT|CT_UNION))) { + PyErr_Format(PyExc_TypeError, + "expected a struct or union cdata, got '%s'", + ct->ct_name); + return NULL; + } + + if (fieldname == NULL) { + offset = 0; + } + else { + CFieldObject *cf = _ffi_field(ct, fieldname); + if (cf == NULL) + return NULL; + offset = cf->cf_offset; + } + return new_simple_cdata(cd->c_data + offset, ct); + } + else if (ZefLib_Check(obj)) { + PyObject *attr, *name; + + if (fieldname == NULL) { + PyErr_SetString(PyExc_TypeError, "addressof(Lib, fieldname) " + "cannot be used with only one argument"); + return NULL; + } + name = PyString_FromString(fieldname); + if (name == NULL) + return NULL; + attr = lib_findattr((ZefLibObject *)obj, name); + Py_DECREF(name); + if (attr == NULL) + return NULL; + + if (ZefGlobSupport_Check(attr)) + return addressof_global_var((ZefGlobSupportObject *)attr); + PyErr_Format(PyExc_TypeError, - "expected a struct or union cdata, got '%s'", - ct->ct_name); + "cannot take the address of constant '%s'", + fieldname); return NULL; } - - if (fieldname == NULL) { - offset = 0; + else { + PyErr_SetString(PyExc_TypeError, "addressof() first argument must be " + "a cdata struct or union, a pointer to one, or a Lib " + "object"); + return NULL; } - else { - CFieldObject *cf = _ffi_field(ct, fieldname); - if (cf == NULL) - return NULL; - offset = cf->cf_offset; - } - return new_simple_cdata(cd->c_data + offset, ct); } static PyMethodDef ffi_methods[] = { diff --git a/zeffir/lib_obj.c b/zeffir/lib_obj.c --- a/zeffir/lib_obj.c +++ b/zeffir/lib_obj.c @@ -12,6 +12,8 @@ PyObject *l_libname_obj; /* same, as a PyObject */ }; +#define ZefLib_Check(ob) ((Py_TYPE(ob) == &ZefLib_Type)) + static void lib_dealloc(ZefLibObject *lib) { (void)lib_close(lib); diff --git a/zeffir/test/test_global.py b/zeffir/test/test_global.py --- a/zeffir/test/test_global.py +++ b/zeffir/test/test_global.py @@ -32,3 +32,10 @@ assert hash(lib.myglobptr) == hash(lib.myglobptr) lib.myglobptr = ffi.NULL assert lib.myglobptr == ffi.NULL + +def test_addressof(): + ffi, lib = support.compile_and_open('global') + p = ffi.addressof(lib, 'myglob') + assert p == lib.myglobptr + lib.myglobptr = ffi.NULL + assert p != lib.myglobptr From noreply at buildbot.pypy.org Fri Dec 5 19:09:23 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 19:09:23 +0100 (CET) Subject: [pypy-commit] creflect default: more fixes to addressof() Message-ID: <20141205180923.AB3621D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r175:6fc30b084312 Date: 2014-12-05 19:09 +0100 http://bitbucket.org/cffi/creflect/changeset/6fc30b084312/ Log: more fixes to addressof() diff --git a/zeffir/cfunc.c b/zeffir/cfunc.c --- a/zeffir/cfunc.c +++ b/zeffir/cfunc.c @@ -11,6 +11,8 @@ } ZefFuncSupportObject; +#define ZefFuncSupport_Check(ob) (Py_TYPE(ob) == &ZefFuncSupport_Type) + static void zef_func_support_dealloc(ZefFuncSupportObject *zfs) { int i; diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -400,6 +400,7 @@ } else if (ZefLib_Check(obj)) { PyObject *attr, *name; + char *reason; if (fieldname == NULL) { PyErr_SetString(PyExc_TypeError, "addressof(Lib, fieldname) " @@ -409,17 +410,23 @@ name = PyString_FromString(fieldname); if (name == NULL) return NULL; - attr = lib_findattr((ZefLibObject *)obj, name); + attr = lib_findattr((ZefLibObject *)obj, name, ZefError); Py_DECREF(name); if (attr == NULL) return NULL; - if (ZefGlobSupport_Check(attr)) + if (ZefGlobSupport_Check(attr)) { return addressof_global_var((ZefGlobSupportObject *)attr); + } - PyErr_Format(PyExc_TypeError, - "cannot take the address of constant '%s'", - fieldname); + if (PyCFunction_Check(attr)) + reason = "declare that function as a function pointer instead"; + else + reason = "numeric constants don't have addresses"; + + PyErr_Format(PyExc_NotImplementedError, + "cannot take the address of '%s' (%s)", + fieldname, reason); return NULL; } else { diff --git a/zeffir/lib_obj.c b/zeffir/lib_obj.c --- a/zeffir/lib_obj.c +++ b/zeffir/lib_obj.c @@ -27,7 +27,7 @@ lib->l_dl_lib == NULL ? " (closed)" : ""); } -static PyObject *lib_findattr(ZefLibObject *lib, PyObject *name) +static PyObject *lib_findattr(ZefLibObject *lib, PyObject *name, PyObject *exc) { /* does not return a new reference! */ @@ -38,7 +38,7 @@ PyObject *x = PyDict_GetItem(lib->l_dict, name); if (x == NULL) { - PyErr_Format(PyExc_AttributeError, + PyErr_Format(exc, "lib '%.200s' has no function," " global variable or constant '%.200s'", lib->l_libname, @@ -50,7 +50,7 @@ static PyObject *lib_getattr(ZefLibObject *lib, PyObject *name) { - PyObject *x = lib_findattr(lib, name); + PyObject *x = lib_findattr(lib, name, PyExc_AttributeError); if (x == NULL) return NULL; @@ -63,7 +63,7 @@ static int lib_setattr(ZefLibObject *lib, PyObject *name, PyObject *val) { - PyObject *x = lib_findattr(lib, name); + PyObject *x = lib_findattr(lib, name, PyExc_AttributeError); if (x == NULL) return -1; diff --git a/zeffir/test/test_basic.py b/zeffir/test/test_basic.py --- a/zeffir/test/test_basic.py +++ b/zeffir/test/test_basic.py @@ -44,3 +44,7 @@ for i in range(50): p = ffi.new("char[]", "12345678" * i) assert ffi.string(p) == "12345678" * i + +def test_addressof_missing_glob(): + ffi, lib = support.compile_and_open('basic') + py.test.raises(ffi.error, ffi.addressof, lib, "some_missing_name") diff --git a/zeffir/test/test_function.py b/zeffir/test/test_function.py --- a/zeffir/test/test_function.py +++ b/zeffir/test/test_function.py @@ -26,3 +26,7 @@ p = ffi.new("char[]", 10) lib.returning_nothing(p) assert ffi.string(p) == "OK" + +def test_addressof_function(): + ffi, lib = support.compile_and_open('function') + py.test.raises(NotImplementedError, ffi.addressof, lib, 'simple_function') diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c --- a/zeffir/zeffir.c +++ b/zeffir/zeffir.c @@ -15,8 +15,8 @@ #include "cdata.c" #include "cglob.c" #include "lib_obj.c" +#include "cfunc.c" #include "ffi_obj.c" -#include "cfunc.c" #include "builder.c" #include "../creflect/creflect_cdecl.c" From noreply at buildbot.pypy.org Fri Dec 5 19:38:48 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 19:38:48 +0100 (CET) Subject: [pypy-commit] creflect default: fix ffi.addressof(). Also allows ffi.new("struct_type") directly, Message-ID: <20141205183848.68C971D2DD3@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r176:620bef5903b4 Date: 2014-12-05 19:39 +0100 http://bitbucket.org/cffi/creflect/changeset/620bef5903b4/ Log: fix ffi.addressof(). Also allows ffi.new("struct_type") directly, as an extension that seems to make sense for now diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -45,13 +45,18 @@ return result; } -static CTypeDescrObject *get_cached_type(_crx_builder_t *cb, PyObject *name_obj) +static PyObject *get_types_dict(_crx_builder_t *cb) +{ + return ((zeffir_builder_t *)cb)->types_dict; +} + +static CTypeDescrObject *get_cached_type(PyObject *types_dict, + PyObject *name_obj) { /* Look up the type called 'name_obj' and check that it's a type with the right flags. Returns either the type or NULL, without changing the reference counts. Never raises an exception. */ - PyObject *types_dict = ((zeffir_builder_t *)cb)->types_dict; PyObject *x; assert(name_obj != NULL); @@ -62,13 +67,13 @@ return (CTypeDescrObject *)x; } -static void put_cached_type(_crx_builder_t *cb, PyObject *name_obj, +static int put_cached_type(PyObject *types_dict, PyObject *name_obj, CTypeDescrObject *ct) { - PyObject *types_dict = ((zeffir_builder_t *)cb)->types_dict; - PyDict_SetItem(types_dict, name_obj, (PyObject *)ct); + int err = PyDict_SetItem(types_dict, name_obj, (PyObject *)ct); Py_DECREF(ct); /* still a reference in the dict, unless PyDict_SetItem failed */ + return err; } static _crx_type_t *_zef_primitive(_crx_builder_t *cb, Py_ssize_t size, @@ -84,7 +89,7 @@ if (name_obj == NULL) return NULL; - ct = get_cached_type(cb, name_obj); + ct = get_cached_type(get_types_dict(cb), name_obj); if (ct && (ct->ct_flags == flags) && (ct->ct_size == size)) goto done; @@ -95,7 +100,8 @@ ct->ct_size = size; ct->ct_flags = flags; - put_cached_type(cb, name_obj, ct); + if (put_cached_type(get_types_dict(cb), name_obj, ct) < 0) + ct = NULL; done: Py_DECREF(name_obj); @@ -207,7 +213,7 @@ == extra_len); } - ct = get_cached_type(cb, name_obj); + ct = get_cached_type(get_types_dict(cb), name_obj); if (ct && (ct->ct_flags == CT_FUNCTION)) goto done; @@ -219,7 +225,7 @@ ct->ct_flags = CT_FUNCTION; /* XXX more... */ - put_cached_type(cb, name_obj, ct); + put_cached_type(get_types_dict(cb), name_obj, ct); done: Py_DECREF(name_obj); @@ -241,12 +247,9 @@ return _zef_function(cb, ret, args, nargs, 1); } -static _crx_type_t *zef_get_pointer_type(_crx_builder_t *cb, - _crx_type_t *totype, int toquals) +static CTypeDescrObject *fetch_pointer_type(PyObject *types_dict, + CTypeDescrObject *totype) { - if (PyErr_Occurred()) - return NULL; - const char *extra; PyObject *name_obj; CTypeDescrObject *ct; @@ -260,7 +263,7 @@ if (name_obj == NULL) return NULL; - ct = get_cached_type(cb, name_obj); + ct = get_cached_type(types_dict, name_obj); if (ct && (ct->ct_flags & CT_POINTER)) goto done; @@ -280,13 +283,22 @@ totype->ct_size == sizeof(char))) ct->ct_flags |= CT_CAST_ANYTHING; /* 'void *' or 'char *' only */ - put_cached_type(cb, name_obj, ct); + put_cached_type(types_dict, name_obj, ct); done: Py_DECREF(name_obj); return ct; } +static _crx_type_t *zef_get_pointer_type(_crx_builder_t *cb, + _crx_type_t *totype, int toquals) +{ + if (PyErr_Occurred()) + return NULL; + + return fetch_pointer_type(get_types_dict(cb), totype); +} + static _crx_type_t *_zef_array_type(_crx_builder_t *cb, _crx_type_t *ctitem, size_t len, CTypeDescrObject *ctptr) { @@ -318,7 +330,7 @@ return NULL; if (cb != NULL) { - ct = get_cached_type(cb, name_obj); + ct = get_cached_type(get_types_dict(cb), name_obj); if (ct && (ct->ct_flags & CT_ARRAY)) goto done; } @@ -356,7 +368,7 @@ Py_INCREF(ct); ctptr->ct_stuff = (PyObject *)ct; } - put_cached_type(cb, name_obj, ct); + put_cached_type(get_types_dict(cb), name_obj, ct); } else { assert(length < 0); @@ -400,7 +412,7 @@ if (name_obj == NULL) return NULL; - ct = get_cached_type(cb, name_obj); + ct = get_cached_type(get_types_dict(cb), name_obj); if (ct && (ct->ct_flags == flag)) goto done; @@ -442,7 +454,7 @@ if (name_obj == NULL) return result; - result.type = get_cached_type(cb, name_obj); + result.type = get_cached_type(get_types_dict(cb), name_obj); if (result.type == NULL) PyErr_Format(ZefError, "undefined type: '%s'", name); return result; diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -1207,6 +1207,7 @@ if (ct == NULL) return NULL; + assert(ct->ct_flags & CT_POINTER); if (ct->ct_stuff == NULL) { if (fill_array_type(ct) < 0) return NULL; diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -191,9 +191,9 @@ return NULL; explicitlength = -1; - if (ct->ct_flags & CT_POINTER) { + if (ct->ct_flags & (CT_POINTER | CT_STRUCT | CT_UNION)) { dataoffset = offsetof(CDataObject_own_nolength, alignment); - ctitem = ct->ct_itemdescr; + ctitem = (ct->ct_flags & CT_POINTER) ? ct->ct_itemdescr : ct; datasize = ctitem->ct_size; if (datasize < 0) { PyErr_Format(PyExc_TypeError, @@ -395,7 +395,11 @@ if (cf == NULL) return NULL; offset = cf->cf_offset; + ct = cf->cf_type; } + ct = fetch_pointer_type(self->types_dict, ct); + if (ct == NULL) + return NULL; return new_simple_cdata(cd->c_data + offset, ct); } else if (ZefLib_Check(obj)) { diff --git a/zeffir/test/struct.crx b/zeffir/test/struct.crx --- a/zeffir/test/struct.crx +++ b/zeffir/test/struct.crx @@ -3,6 +3,11 @@ long b; } mystruct_t; +typedef struct { + int foo[5]; + //int bar[]; +} myarrstr_t; + // CREFLECT: start @@ -10,4 +15,9 @@ int a, b; } mystruct_t; +typedef struct { + int foo[5]; + //int bar[]; +} myarrstr_t; + // CREFLECT: end diff --git a/zeffir/test/test_struct.py b/zeffir/test/test_struct.py --- a/zeffir/test/test_struct.py +++ b/zeffir/test/test_struct.py @@ -6,6 +6,7 @@ ffi, lib = support.compile_and_open('struct') p = ffi.new('mystruct_t *', [-5, 0x600112233]) assert p.a == -5 + assert p[0].a == -5 assert p.b == 0x600112233 p.b += 1 assert p.b == 0x600112234 @@ -19,10 +20,27 @@ ffi, lib = support.compile_and_open('struct') p = ffi.new("mystruct_t *") assert ffi.addressof(p[0]) == p + assert ffi.typeof(ffi.addressof(p[0])) == ffi.typeof("mystruct_t *") assert ffi.addressof(p[0], None) == p assert ffi.addressof(p[0], "a") == p + assert ffi.typeof(ffi.addressof(p[0], "a")) == ffi.typeof("int *") assert ffi.addressof(p[0], "b") != p assert ffi.addressof(p[0], "b") == ffi.addressof(p, "b") + assert ffi.typeof(ffi.addressof(p[0], "b")) == ffi.typeof("long *") assert ffi.addressof(p, "a") == p py.test.raises(TypeError, ffi.addressof, p) py.test.raises(TypeError, ffi.addressof, p, None) + # + p = ffi.new("myarrstr_t *") + assert ffi.typeof(ffi.addressof(p, "foo")) == ffi.typeof("int(*)[5]") + assert ffi.typeof(p.foo) == ffi.typeof("int[5]") + #assert ffi.typeof(ffi.addressof(p, "bar")) == ffi.typeof("int(*)[]") + +def test_new_nonptr_struct(): + ffi, lib = support.compile_and_open('struct') + s = ffi.new("mystruct_t", [-5, 0x600112233]) + assert s.a == -5 + assert s.b == 0x600112233 + s.b += 1 + assert s.b == 0x600112234 + assert ffi.addressof(s)[0] == s diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h --- a/zeffir/zeffir.h +++ b/zeffir/zeffir.h @@ -21,3 +21,5 @@ static int convert_from_object_bitfield(char *, CFieldObject *, PyObject *); static int fill_array_type(CTypeDescrObject *ctptr); +static CTypeDescrObject *fetch_pointer_type(PyObject *types_dict, + CTypeDescrObject *totype); From noreply at buildbot.pypy.org Fri Dec 5 19:44:44 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 19:44:44 +0100 (CET) Subject: [pypy-commit] creflect default: test and fix for structs-with-incomplete-array Message-ID: <20141205184444.488D51D257D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r177:c652e11796b0 Date: 2014-12-05 19:45 +0100 http://bitbucket.org/cffi/creflect/changeset/c652e11796b0/ Log: test and fix for structs-with-incomplete-array diff --git a/creflect/model.py b/creflect/model.py --- a/creflect/model.py +++ b/creflect/model.py @@ -471,7 +471,7 @@ else: star_p1 = None t1, q1 = self.item.inspect_type(block, inspect, qualifiers) - if star_p1 is not None: + if star_p1 is not None and self.length is not None: expr = 'cb->get_array_type(cb, %s, sizeof(%s) / sizeof(*%s))' % ( t1, star_p1, star_p1) else: diff --git a/creflect/test/codegen/struct-004b.c b/creflect/test/codegen/struct-004b.c new file mode 100644 --- /dev/null +++ b/creflect/test/codegen/struct-004b.c @@ -0,0 +1,54 @@ +struct foo_s { + int nn; + int aa[]; +}; + +# ____________________________________________________________ + +void teststruct_004b(_crx_builder_t *cb) +{ + _crx_type_t *t1, *t2, *t3, *t4; + _crx_field_t d1[2]; + t1 = cb->get_struct_type(cb, "foo_s"); + { + struct foo_s *p1; + char b[sizeof(p1->nn)]; + size_t o = ((char *)&((struct foo_s *)0)->nn) - (char *)0; /* check that 'struct foo_s::nn' is not an array */ + p1 = (void *)(((char *)b) - o); + (void)(p1->nn << 1); /* check that 'struct foo_s::nn' is an integer type */ + p1->nn = -1; /* check that 'struct foo_s::nn' is not declared 'const' */ + t2 = _CRX_INT_TYPE(cb, p1->nn, _crx_sc_int); + d1[0].name = "nn"; + d1[0].type = t2; + d1[0].qualifiers = 0; + d1[0].offset = o; + d1[0].numbits = -1; + d1[0].bitshift = -1; + } + { + struct foo_s *p1; + char b[sizeof(*p1->aa)]; /* check that 'struct foo_s::aa[]' is a valid type */ + size_t o = offsetof(struct foo_s, aa[0]); /* check that 'struct foo_s::aa' is an array */ + p1 = (void *)(((char *)b) - o); + if ((void *)&p1->aa != (void *)p1->aa) { + cb->error(cb, "type 'struct foo_s::aa' is not an array, but a pointer type"); + return; + } + (void)(*p1->aa << 1); /* check that 'struct foo_s::aa[]' is an integer type */ + *p1->aa = -1; /* check that 'struct foo_s::aa[]' is not declared 'const' */ + t3 = _CRX_INT_TYPE(cb, *p1->aa, _crx_sc_int); + t4 = cb->get_incomplete_array_type(cb, t3); + d1[1].name = "aa"; + d1[1].type = t4; + d1[1].qualifiers = 0; + d1[1].offset = o; + d1[1].numbits = -1; + d1[1].bitshift = -1; + } + cb->complete(cb, t1, sizeof(struct foo_s), + ((char *)&((struct{char a; struct foo_s b;} *)0)->b) - (char *)0, + d1, 2); +#expect STRUCT foo_s: +#expect | nn: int +#expect | aa: ARRAY[] int +} From noreply at buildbot.pypy.org Fri Dec 5 19:46:04 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 19:46:04 +0100 (CET) Subject: [pypy-commit] creflect default: uncomment these tests, now passing Message-ID: <20141205184604.AF42E1D257D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r178:a3463cd2c8f0 Date: 2014-12-05 19:46 +0100 http://bitbucket.org/cffi/creflect/changeset/a3463cd2c8f0/ Log: uncomment these tests, now passing diff --git a/zeffir/test/struct.crx b/zeffir/test/struct.crx --- a/zeffir/test/struct.crx +++ b/zeffir/test/struct.crx @@ -5,7 +5,8 @@ typedef struct { int foo[5]; - //int bar[]; + int bar[7]; + int baz[]; } myarrstr_t; @@ -17,7 +18,8 @@ typedef struct { int foo[5]; - //int bar[]; + int bar[]; + int baz[]; } myarrstr_t; // CREFLECT: end diff --git a/zeffir/test/test_struct.py b/zeffir/test/test_struct.py --- a/zeffir/test/test_struct.py +++ b/zeffir/test/test_struct.py @@ -32,9 +32,12 @@ py.test.raises(TypeError, ffi.addressof, p, None) # p = ffi.new("myarrstr_t *") + assert ffi.typeof(p.foo) == ffi.typeof("int[5]") + assert ffi.typeof(p.bar) == ffi.typeof("int *") + assert ffi.typeof(p.baz) == ffi.typeof("int *") assert ffi.typeof(ffi.addressof(p, "foo")) == ffi.typeof("int(*)[5]") - assert ffi.typeof(p.foo) == ffi.typeof("int[5]") - #assert ffi.typeof(ffi.addressof(p, "bar")) == ffi.typeof("int(*)[]") + assert ffi.typeof(ffi.addressof(p, "bar")) == ffi.typeof("int(*)[]") + assert ffi.typeof(ffi.addressof(p, "baz")) == ffi.typeof("int(*)[]") def test_new_nonptr_struct(): ffi, lib = support.compile_and_open('struct') From noreply at buildbot.pypy.org Fri Dec 5 21:08:44 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 21:08:44 +0100 (CET) Subject: [pypy-commit] creflect default: fix the error message Message-ID: <20141205200844.9C58C1D2E18@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r179:8cf4c557d1f1 Date: 2014-12-05 20:49 +0100 http://bitbucket.org/cffi/creflect/changeset/8cf4c557d1f1/ Log: fix the error message diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -231,8 +231,8 @@ } else { PyErr_Format(PyExc_TypeError, - "expected a pointer or array ctype, got '%s'", - ct->ct_name); + "expected a pointer, struct, union, or array ctype, " + "got '%s'", ct->ct_name); return NULL; } From noreply at buildbot.pypy.org Fri Dec 5 21:08:45 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 21:08:45 +0100 (CET) Subject: [pypy-commit] creflect default: copy the logic for ffi.cast() Message-ID: <20141205200845.BA32C1D2E18@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r180:9eb2b89d1adc Date: 2014-12-05 21:09 +0100 http://bitbucket.org/cffi/creflect/changeset/9eb2b89d1adc/ Log: copy the logic for ffi.cast() diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -255,6 +255,208 @@ 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; + + ct = _ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CTYPE); + 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 + 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; +} + static PyObject *ffi_string(ZefFFIObject *self, PyObject *args) { CDataObject *cd; @@ -443,6 +645,7 @@ 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}, {"load_library", (PyCFunction)ffi_load_library, METH_VARARGS | METH_KEYWORDS}, diff --git a/zeffir/test/test_basic.py b/zeffir/test/test_basic.py --- a/zeffir/test/test_basic.py +++ b/zeffir/test/test_basic.py @@ -48,3 +48,9 @@ def test_addressof_missing_glob(): ffi, lib = support.compile_and_open('basic') py.test.raises(ffi.error, ffi.addressof, lib, "some_missing_name") + +def test_cast(): + ffi = support.new_ffi() + p = ffi.new("char[]", "----abcd") + q = ffi.cast("int *", p) + assert q[1] in [0x61626364, 0x64636261] From noreply at buildbot.pypy.org Fri Dec 5 21:19:54 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Fri, 5 Dec 2014 21:19:54 +0100 (CET) Subject: [pypy-commit] pypy default: cleanup references to numpypy Message-ID: <20141205201954.694511D257D@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74839:642a5d4965d6 Date: 2014-12-05 15:12 -0500 http://bitbucket.org/pypy/pypy/changeset/642a5d4965d6/ Log: cleanup references to numpypy diff too long, truncating to 2000 out of 3730 lines diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py --- a/pypy/module/micronumpy/boxes.py +++ b/pypy/module/micronumpy/boxes.py @@ -59,9 +59,9 @@ _mixin_ = True def reduce(self, space): - numpypy = space.getbuiltinmodule("_numpypy") - assert isinstance(numpypy, MixedModule) - multiarray = numpypy.get("multiarray") + _numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(_numpypy, MixedModule) + multiarray = _numpypy.get("multiarray") assert isinstance(multiarray, MixedModule) scalar = multiarray.get("scalar") diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -1139,9 +1139,9 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.module.micronumpy.concrete import SliceArray - numpypy = space.getbuiltinmodule("_numpypy") - assert isinstance(numpypy, MixedModule) - multiarray = numpypy.get("multiarray") + _numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(_numpypy, MixedModule) + multiarray = _numpypy.get("multiarray") assert isinstance(multiarray, MixedModule) reconstruct = multiarray.get("_reconstruct") parameters = space.newtuple([self.getclass(space), space.newtuple( diff --git a/pypy/module/micronumpy/test/test_arrayops.py b/pypy/module/micronumpy/test/test_arrayops.py --- a/pypy/module/micronumpy/test/test_arrayops.py +++ b/pypy/module/micronumpy/test/test_arrayops.py @@ -3,13 +3,13 @@ class AppTestNumSupport(BaseNumpyAppTest): def test_zeros(self): - from numpypy import zeros + from numpy import zeros a = zeros(3) assert len(a) == 3 assert a[0] == a[1] == a[2] == 0 def test_empty(self): - from numpypy import empty + from numpy import empty import gc for i in range(1000): a = empty(3) @@ -26,26 +26,26 @@ "empty() returned a zeroed out array every time") def test_where(self): - from numpypy import where, ones, zeros, array + from numpy import where, ones, zeros, array a = [1, 2, 3, 0, -3] a = where(array(a) > 0, ones(5), zeros(5)) assert (a == [1, 1, 1, 0, 0]).all() def test_where_differing_dtypes(self): - from numpypy import array, ones, zeros, where + from numpy import array, ones, zeros, where a = [1, 2, 3, 0, -3] a = where(array(a) > 0, ones(5, dtype=int), zeros(5, dtype=float)) assert (a == [1, 1, 1, 0, 0]).all() def test_where_broadcast(self): - from numpypy import array, where + from numpy import array, where a = where(array([[1, 2, 3], [4, 5, 6]]) > 3, [1, 1, 1], 2) assert (a == [[2, 2, 2], [1, 1, 1]]).all() a = where(True, [1, 1, 1], 2) assert (a == [1, 1, 1]).all() def test_where_errors(self): - from numpypy import where, array + from numpy import where, array raises(ValueError, "where([1, 2, 3], [3, 4, 5])") raises(ValueError, "where([1, 2, 3], [3, 4, 5], [6, 7])") assert where(True, 1, 2) == array(1) @@ -58,14 +58,14 @@ # xxx def test_where_invalidates(self): - from numpypy import where, ones, zeros, array + from numpy import where, ones, zeros, array a = array([1, 2, 3, 0, -3]) b = where(a > 0, ones(5), zeros(5)) a[0] = 0 assert (b == [1, 1, 1, 0, 0]).all() def test_dot_basic(self): - from numpypy import array, dot, arange + from numpy import array, dot, arange a = array(range(5)) assert dot(a, a) == 30.0 @@ -100,7 +100,7 @@ assert (dot([[1,2],[3,4]],[5,6]) == [17, 39]).all() def test_dot_constant(self): - from numpypy import array, dot + from numpy import array, dot a = array(range(5)) b = a.dot(2.5) for i in xrange(5): @@ -111,7 +111,7 @@ assert c == 12.0 def test_dot_out(self): - from numpypy import arange, dot + from numpy import arange, dot a = arange(12).reshape(3, 4) b = arange(12).reshape(4, 3) out = arange(9).reshape(3, 3) @@ -124,19 +124,19 @@ 'right type, nr dimensions, and be a C-Array)') def test_choose_basic(self): - from numpypy import array + from numpy import array a, b, c = array([1, 2, 3]), array([4, 5, 6]), array([7, 8, 9]) r = array([2, 1, 0]).choose([a, b, c]) assert (r == [7, 5, 3]).all() def test_choose_broadcast(self): - from numpypy import array + from numpy import array a, b, c = array([1, 2, 3]), [4, 5, 6], 13 r = array([2, 1, 0]).choose([a, b, c]) assert (r == [13, 5, 3]).all() def test_choose_out(self): - from numpypy import array + from numpy import array a, b, c = array([1, 2, 3]), [4, 5, 6], 13 r = array([2, 1, 0]).choose([a, b, c], out=None) assert (r == [13, 5, 3]).all() @@ -146,7 +146,7 @@ assert (a == [13, 5, 3]).all() def test_choose_modes(self): - from numpypy import array + from numpy import array a, b, c = array([1, 2, 3]), [4, 5, 6], 13 raises(ValueError, "array([3, 1, 0]).choose([a, b, c])") raises(ValueError, "array([3, 1, 0]).choose([a, b, c], mode='raises')") @@ -158,20 +158,20 @@ assert (r == [4, 5, 3]).all() def test_choose_dtype(self): - from numpypy import array + from numpy import array a, b, c = array([1.2, 2, 3]), [4, 5, 6], 13 r = array([2, 1, 0]).choose([a, b, c]) assert r.dtype == float def test_choose_dtype_out(self): - from numpypy import array + from numpy import array a, b, c = array([1, 2, 3]), [4, 5, 6], 13 x = array([0, 0, 0], dtype='i2') r = array([2, 1, 0]).choose([a, b, c], out=x) assert r.dtype == 'i2' def test_put_basic(self): - from numpypy import arange, array + from numpy import arange, array a = arange(5) a.put([0, 2], [-44, -55]) assert (a == array([-44, 1, -55, 3, 4])).all() @@ -183,7 +183,7 @@ assert (a == array([0, 7, 2, 3, 4])).all() def test_put_modes(self): - from numpypy import array, arange + from numpy import array, arange a = arange(5) a.put(22, -5, mode='clip') assert (a == array([0, 1, 2, 3, -5])).all() diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -14,15 +14,12 @@ else: from . import dummy_module as numpy sys.modules['numpy'] = numpy - sys.modules['numpypy'] = numpy else: import os path = os.path.dirname(__file__) + '/dummy_module.py' cls.space.appexec([cls.space.wrap(path)], """(path): import imp - numpy = imp.load_source('numpy', path) - import sys - sys.modules['numpypy'] = numpy + imp.load_source('numpy', path) """) cls.w_non_native_prefix = cls.space.wrap(NPY.OPPBYTE) cls.w_native_prefix = cls.space.wrap(NPY.NATBYTE) diff --git a/pypy/module/micronumpy/test/test_complex.py b/pypy/module/micronumpy/test/test_complex.py --- a/pypy/module/micronumpy/test/test_complex.py +++ b/pypy/module/micronumpy/test/test_complex.py @@ -132,13 +132,13 @@ cls.w_c_pow = cls.space.wrap(interp2app(cls_c_pow)) def test_fabs(self): - from numpypy import fabs, dtype + from numpy import fabs, dtype a = dtype('complex128').type(complex(-5., 5.)) raises(TypeError, fabs, a) def test_fmax(self): - from numpypy import fmax, array + from numpy import fmax, array nnan, nan, inf, ninf = float('-nan'), float('nan'), float('inf'), float('-inf') a = array((complex(ninf, 10), complex(10, ninf), complex( inf, 10), complex(10, inf), @@ -165,7 +165,7 @@ assert (fmax(a, b) == res).all() def test_fmin(self): - from numpypy import fmin, array + from numpy import fmin, array nnan, nan, inf, ninf = float('-nan'), float('nan'), float('inf'), float('-inf') a = array((complex(ninf, 10), complex(10, ninf), complex( inf, 10), complex(10, inf), @@ -192,11 +192,11 @@ assert (fmin(a, b) == res).all() def test_signbit(self): - from numpypy import signbit + from numpy import signbit raises(TypeError, signbit, complex(1,1)) def test_reciprocal(self): - from numpypy import array, reciprocal + from numpy import array, reciprocal inf = float('inf') nan = float('nan') #complex @@ -218,21 +218,21 @@ assert (a[0].imag - e.imag) < rel_err def test_floorceiltrunc(self): - from numpypy import array, floor, ceil, trunc + from numpy import array, floor, ceil, trunc a = array([ complex(-1.4, -1.4), complex(-1.5, -1.5)]) raises(TypeError, floor, a) raises(TypeError, ceil, a) raises(TypeError, trunc, a) def test_copysign(self): - from numpypy import copysign, dtype + from numpy import copysign, dtype complex128 = dtype('complex128').type a = complex128(complex(-5., 5.)) b = complex128(complex(0., 0.)) raises(TypeError, copysign, a, b) def test_exp2(self): - from numpypy import array, exp2 + from numpy import array, exp2 inf = float('inf') ninf = -float('inf') nan = float('nan') @@ -268,7 +268,7 @@ def test_expm1(self): import math, cmath - from numpypy import array, expm1 + from numpy import array, expm1 inf = float('inf') ninf = -float('inf') nan = float('nan') @@ -307,7 +307,7 @@ self.rAlmostEqual(t1, t2, rel_err=rel_err, msg=msg) def test_not_complex(self): - from numpypy import (radians, deg2rad, degrees, rad2deg, + from numpy import (radians, deg2rad, degrees, rad2deg, logaddexp, logaddexp2, fmod, arctan2) raises(TypeError, radians, complex(90,90)) @@ -320,7 +320,7 @@ raises (TypeError, fmod, complex(90,90), 3) def test_isnan_isinf(self): - from numpypy import isnan, isinf, array + from numpy import isnan, isinf, array assert (isnan(array([0.2+2j, complex(float('inf'),0), complex(0,float('inf')), complex(0,float('nan')), complex(float('nan'), 0)], dtype=complex)) == \ @@ -333,7 +333,7 @@ def test_square(self): - from numpypy import square + from numpy import square assert square(complex(3, 4)) == complex(3,4) * complex(3, 4) def test_power_simple(self): @@ -364,8 +364,8 @@ self.rAlmostEqual(float(n_r_a[i].imag), float(p_r[i].imag), msg=msg) def test_conjugate(self): - from numpypy import conj, conjugate, dtype - import numpypy as np + from numpy import conj, conjugate, dtype + import numpy as np c0 = dtype('complex128').type(complex(2.5, 0)) c1 = dtype('complex64').type(complex(1, 2)) @@ -390,7 +390,7 @@ def test_logn(self): import math, cmath # log and log10 are tested in math (1:1 from rcomplex) - from numpypy import log2, array, log1p + from numpy import log2, array, log1p inf = float('inf') ninf = -float('inf') nan = float('nan') @@ -447,7 +447,7 @@ self.rAlmostEqual(t1, t2, rel_err=rel_err, msg=msg) def test_logical_ops(self): - from numpypy import logical_and, logical_or, logical_xor, logical_not + from numpy import logical_and, logical_or, logical_xor, logical_not c1 = complex(1, 1) c3 = complex(3, 0) @@ -461,7 +461,7 @@ assert (logical_not([c1, c0]) == [False, True]).all() def test_minimum(self): - from numpypy import array, minimum + from numpy import array, minimum a = array([-5.0+5j, -5.0-5j, -0.0-10j, 1.0+10j]) b = array([ 3.0+10.0j, 3.0, -2.0+2.0j, -3.0+4.0j]) @@ -470,7 +470,7 @@ assert c[i] == min(a[i], b[i]) def test_maximum(self): - from numpypy import array, maximum + from numpy import array, maximum a = array([-5.0+5j, -5.0-5j, -0.0-10j, 1.0+10j]) b = array([ 3.0+10.0j, 3.0, -2.0+2.0j, -3.0+4.0j]) @@ -480,10 +480,10 @@ def test_basic(self): import sys - from numpypy import (dtype, add, array, dtype, + from numpy import (dtype, add, array, dtype, subtract as sub, multiply, divide, negative, absolute as abs, floor_divide, real, imag, sign) - from numpypy import (equal, not_equal, greater, greater_equal, less, + from numpy import (equal, not_equal, greater, greater_equal, less, less_equal, isnan) assert real(4.0) == 4.0 assert imag(0.0) == 0.0 @@ -579,7 +579,7 @@ assert repr(abs(inf_c)) == 'inf' assert repr(abs(complex(float('nan'), float('nan')))) == 'nan' # numpy actually raises an AttributeError, - # but numpypy raises a TypeError + # but numpy.raises a TypeError if '__pypy__' in sys.builtin_module_names: exct, excm = TypeError, 'readonly attribute' else: @@ -592,7 +592,7 @@ assert(imag(c2) == 4.0) def test_conj(self): - from numpypy import array + from numpy import array a = array([1 + 2j, 1 - 2j]) assert (a.conj() == [1 - 2j, 1 + 2j]).all() @@ -603,7 +603,7 @@ if self.isWindows: skip('windows does not support c99 complex') import sys - import numpypy as np + import numpy as np rAlmostEqual = self.rAlmostEqual for t, testcases in ( @@ -658,6 +658,6 @@ sys.stderr.write('\n') def test_complexbox_to_pycomplex(self): - from numpypy import dtype + from numpy import dtype x = dtype('complex128').type(3.4j) assert complex(x) == 3.4j diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -23,7 +23,7 @@ from numpy.core.multiarray import typeinfo except ImportError: # running on dummy module - from numpypy import typeinfo + from numpy import typeinfo assert typeinfo['Number'] == np.number assert typeinfo['LONGLONG'] == ('q', 9, 64, 8, 9223372036854775807L, -9223372036854775808L, np.longlong) @@ -39,7 +39,7 @@ np.dtype('int').type) def test_dtype_basic(self): - from numpypy import dtype + from numpy import dtype import sys d = dtype('?') @@ -104,7 +104,7 @@ assert d.shape == () def test_dtype_eq(self): - from numpypy import dtype + from numpy import dtype assert dtype("int8") == "int8" assert "int8" == dtype("int8") @@ -112,7 +112,7 @@ assert dtype(bool) == bool def test_dtype_aliases(self): - from numpypy import dtype + from numpy import dtype assert dtype('bool8') is dtype('bool') assert dtype('byte') is dtype('int8') assert dtype('ubyte') is dtype('uint8') @@ -132,7 +132,7 @@ assert dtype('clongdouble').num in (15, 16) def test_dtype_with_types(self): - from numpypy import dtype + from numpy import dtype assert dtype(bool).num == 0 if self.ptr_size == 4: @@ -156,7 +156,7 @@ assert dtype('complex').num == 15 def test_array_dtype_attr(self): - from numpypy import array, dtype + from numpy import array, dtype a = array(range(5), long) assert a.dtype is dtype(long) @@ -182,7 +182,7 @@ assert np.dtype('S5').isbuiltin == 0 def test_repr_str(self): - from numpypy import dtype + from numpy import dtype b = dtype(int).newbyteorder().newbyteorder().byteorder assert '.dtype' in repr(dtype) d = dtype('?') @@ -208,7 +208,7 @@ assert str(d) == "|V16" def test_bool_array(self): - from numpypy import array, False_, True_ + from numpy import array, False_, True_ a = array([0, 1, 2, 2.5], dtype='?') assert a[0] is False_ @@ -216,7 +216,7 @@ assert a[i] is True_ def test_copy_array_with_dtype(self): - from numpypy import array, longlong, False_ + from numpy import array, longlong, False_ a = array([0, 1, 2, 3], dtype=long) # int on 64-bit, long in 32-bit @@ -230,35 +230,35 @@ assert b[0] is False_ def test_zeros_bool(self): - from numpypy import zeros, False_ + from numpy import zeros, False_ a = zeros(10, dtype=bool) for i in range(10): assert a[i] is False_ def test_ones_bool(self): - from numpypy import ones, True_ + from numpy import ones, True_ a = ones(10, dtype=bool) for i in range(10): assert a[i] is True_ def test_zeros_long(self): - from numpypy import zeros, longlong + from numpy import zeros, longlong a = zeros(10, dtype=long) for i in range(10): assert isinstance(a[i], longlong) assert a[1] == 0 def test_ones_long(self): - from numpypy import ones, longlong + from numpy import ones, longlong a = ones(10, dtype=long) for i in range(10): assert isinstance(a[i], longlong) assert a[1] == 1 def test_overflow(self): - from numpypy import array, dtype + from numpy import array, dtype assert array([128], 'b')[0] == -128 assert array([256], 'B')[0] == 0 assert array([32768], 'h')[0] == -32768 @@ -273,7 +273,7 @@ raises(OverflowError, "array([2**64], 'Q')") def test_bool_binop_types(self): - from numpypy import array, dtype + from numpy import array, dtype types = [ '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd', 'e' @@ -285,7 +285,7 @@ assert (a + array([0], t)).dtype is dtype(t) def test_binop_types(self): - from numpypy import array, dtype + from numpy import array, dtype tests = [('b','B','h'), ('b','h','h'), ('b','H','i'), ('b','i','i'), ('b','l','l'), ('b','q','q'), ('b','Q','d'), ('B','h','h'), ('B','H','H'), ('B','i','i'), ('B','I','I'), ('B','l','l'), @@ -309,7 +309,7 @@ assert (d1, d2) == (d1, d2) and d3 is dtype(dout) def test_add(self): - import numpypy as np + import numpy as np for dtype in ["int8", "int16", "I"]: a = np.array(range(5), dtype=dtype) b = a + a @@ -325,22 +325,22 @@ assert len(d) == 2 def test_shape(self): - from numpypy import dtype + from numpy import dtype assert dtype(long).shape == () def test_cant_subclass(self): - from numpypy import dtype + from numpy import dtype # You can't subclass dtype raises(TypeError, type, "Foo", (dtype,), {}) def test_can_subclass(self): - import numpypy - class xyz(numpypy.void): + import numpy + class xyz(numpy.void): pass assert True def test_index(self): - import numpypy as np + import numpy as np for dtype in [np.int8, np.int16, np.int32, np.int64]: a = np.array(range(10), dtype=dtype) b = np.array([0] * 10, dtype=dtype) @@ -348,7 +348,7 @@ a[idx] += 1 def test_hash(self): - import numpypy as numpy + import numpy for tp, value in [ (numpy.int8, 4), (numpy.int16, 5), @@ -395,7 +395,7 @@ def test_pickle(self): import numpy as np - from numpypy import array, dtype + from numpy import array, dtype from cPickle import loads, dumps a = array([1,2,3]) if self.ptr_size == 8: @@ -408,7 +408,7 @@ assert np.dtype(('' @@ -480,7 +480,7 @@ class AppTestTypes(BaseAppTestDtypes): def test_abstract_types(self): - import numpypy as numpy + import numpy raises(TypeError, numpy.generic, 0) raises(TypeError, numpy.number, 0) @@ -526,16 +526,16 @@ #assert a.dtype is numpy.dtype('|V4') def test_new(self): - import numpypy as np + import numpy as np assert np.int_(4) == 4 assert np.float_(3.4) == 3.4 def test_pow(self): - from numpypy import int_ + from numpy import int_ assert int_(4) ** 2 == 16 def test_bool(self): - import numpypy as numpy + import numpy assert numpy.bool_.mro() == [numpy.bool_, numpy.generic, object] assert numpy.bool_(3) is numpy.True_ @@ -550,7 +550,7 @@ assert numpy.bool_("False") is numpy.True_ def test_int8(self): - import numpypy as numpy + import numpy assert numpy.int8.mro() == [numpy.int8, numpy.signedinteger, numpy.integer, numpy.number, @@ -574,7 +574,7 @@ assert numpy.int8('128') == -128 def test_uint8(self): - import numpypy as numpy + import numpy assert numpy.uint8.mro() == [numpy.uint8, numpy.unsignedinteger, numpy.integer, numpy.number, @@ -599,7 +599,7 @@ assert numpy.uint8('256') == 0 def test_int16(self): - import numpypy as numpy + import numpy x = numpy.int16(3) assert x == 3 @@ -641,7 +641,7 @@ assert numpy.uint32('4294967296') == 0 def test_int_(self): - import numpypy as numpy + import numpy assert numpy.int_ is numpy.dtype(int).type assert numpy.int_.mro() == [numpy.int_, numpy.signedinteger, @@ -752,7 +752,7 @@ def test_complex_format(self): import sys - import numpypy as numpy + import numpy for complex_ in (numpy.complex128, numpy.complex64,): for real, imag, should in [ @@ -792,7 +792,7 @@ assert "{:g}".format(numpy.complex_(0.5+1.5j)) == '{:g}'.format(0.5+1.5j) def test_complex(self): - import numpypy as numpy + import numpy assert numpy.complex_ is numpy.complex128 assert numpy.csingle is numpy.complex64 @@ -812,7 +812,7 @@ assert d.char == 'F' def test_subclass_type(self): - import numpypy as numpy + import numpy class X(numpy.float64): def m(self): @@ -826,12 +826,12 @@ assert b.dtype.type is numpy.float64 def test_long_as_index(self): - from numpypy import int_, float64 + from numpy import int_, float64 assert (1, 2, 3)[int_(1)] == 2 raises(TypeError, lambda: (1, 2, 3)[float64(1)]) def test_int(self): - from numpypy import int32, int64, int_ + from numpy import int32, int64, int_ import sys assert issubclass(int_, int) if sys.maxint == (1<<31) - 1: @@ -842,7 +842,7 @@ assert int_ is int64 def test_various_types(self): - import numpypy as numpy + import numpy assert numpy.int16 is numpy.short assert numpy.int8 is numpy.byte @@ -864,7 +864,7 @@ assert not issubclass(numpy.longfloat, numpy.float64) def test_mro(self): - import numpypy as numpy + import numpy assert numpy.int16.__mro__ == (numpy.int16, numpy.signedinteger, numpy.integer, numpy.number, @@ -873,7 +873,7 @@ def test_operators(self): from operator import truediv - from numpypy import float64, int_, True_, False_ + from numpy import float64, int_, True_, False_ assert 5 / int_(2) == int_(2) assert truediv(int_(3), int_(2)) == float64(1.5) assert truediv(3, int_(2)) == float64(1.5) @@ -899,7 +899,7 @@ def test_alternate_constructs(self): import numpy as np - from numpypy import dtype + from numpy import dtype nnp = self.non_native_prefix byteorder = self.native_prefix assert dtype('i8') == dtype(byteorder + 'i8') == dtype('=i8') == dtype(long) @@ -922,7 +922,7 @@ assert d.str == '|S0' def test_dtype_str(self): - from numpypy import dtype + from numpy import dtype byteorder = self.native_prefix assert dtype('i8').str == byteorder + 'i8' assert dtype('i8').isnative == False def test_any_all_nonzero(self): - import numpypy as numpy + import numpy x = numpy.bool_(True) assert x.any() is numpy.True_ assert x.all() is numpy.True_ @@ -1000,7 +1000,7 @@ assert x.__nonzero__() is True def test_ravel(self): - from numpypy import float64, int8, array + from numpy import float64, int8, array x = float64(42.5).ravel() assert x.dtype == float64 assert (x == array([42.5])).all() @@ -1023,7 +1023,7 @@ class AppTestStrUnicodeDtypes(BaseNumpyAppTest): def test_mro(self): - from numpypy import str_, unicode_, character, flexible, generic + from numpy import str_, unicode_, character, flexible, generic import sys if '__pypy__' in sys.builtin_module_names: assert str_.mro() == [str_, character, flexible, generic, @@ -1037,7 +1037,7 @@ flexible, generic, object] def test_str_dtype(self): - from numpypy import dtype, str_ + from numpy import dtype, str_ raises(TypeError, "dtype('Sx')") for t in ['S8', '|S8', '=S8']: @@ -1058,7 +1058,7 @@ assert d.str == '|S1' def test_unicode_dtype(self): - from numpypy import dtype, unicode_ + from numpy import dtype, unicode_ raises(TypeError, "dtype('Ux')") d = dtype('U8') @@ -1070,11 +1070,11 @@ assert d.num == 19 def test_string_boxes(self): - from numpypy import str_ + from numpy import str_ assert isinstance(str_(3), str_) def test_unicode_boxes(self): - from numpypy import unicode_ + from numpy import unicode_ import sys if '__pypy__' in sys.builtin_module_names: exc = raises(NotImplementedError, unicode_, 3) @@ -1085,7 +1085,7 @@ def test_character_dtype(self): import numpy as np - from numpypy import array, character + from numpy import array, character x = array([["A", "B"], ["C", "D"]], character) assert (x == [["A", "B"], ["C", "D"]]).all() d = np.dtype('c') @@ -1098,7 +1098,7 @@ spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) def test_create(self): - from numpypy import dtype, void + from numpy import dtype, void raises(ValueError, "dtype([('x', int), ('x', float)])") d = dtype([("x", "> a == [2, 1, 0, 0, 0]).all() def test_pow(self): - from numpypy import array + from numpy import array a = array(range(5), float) b = a ** a for i in range(5): @@ -1277,7 +1277,7 @@ assert (a ** 2 == a * a).all() def test_pow_other(self): - from numpypy import array + from numpy import array a = array(range(5), float) b = array([2, 2, 2, 2, 2]) c = a ** b @@ -1285,14 +1285,14 @@ assert c[i] == i ** 2 def test_pow_constant(self): - from numpypy import array + from numpy import array a = array(range(5), float) b = a ** 2 for i in range(5): assert b[i] == i ** 2 def test_mod(self): - from numpypy import array + from numpy import array a = array(range(1, 6)) b = a % a for i in range(5): @@ -1305,7 +1305,7 @@ assert b[i] == 1 def test_mod_other(self): - from numpypy import array + from numpy import array a = array(range(5)) b = array([2, 2, 2, 2, 2]) c = a % b @@ -1313,38 +1313,38 @@ assert c[i] == i % 2 def test_mod_constant(self): - from numpypy import array + from numpy import array a = array(range(5)) b = a % 2 for i in range(5): assert b[i] == i % 2 def test_rand(self): - from numpypy import arange + from numpy import arange a = arange(5) assert (3 & a == [0, 1, 2, 3, 0]).all() def test_ror(self): - from numpypy import arange + from numpy import arange a = arange(5) assert (3 | a == [3, 3, 3, 3, 7]).all() def test_xor(self): - from numpypy import arange + from numpy import arange a = arange(5) assert (a ^ 3 == [3, 2, 1, 0, 7]).all() def test_rxor(self): - from numpypy import arange + from numpy import arange a = arange(5) assert (3 ^ a == [3, 2, 1, 0, 7]).all() def test_pos(self): - from numpypy import array + from numpy import array a = array([1., -2., 3., -4., -5.]) b = +a for i in range(5): @@ -1355,7 +1355,7 @@ assert a[i] == i def test_neg(self): - from numpypy import array + from numpy import array a = array([1., -2., 3., -4., -5.]) b = -a for i in range(5): @@ -1366,7 +1366,7 @@ assert a[i] == -i def test_abs(self): - from numpypy import array + from numpy import array a = array([1., -2., 3., -4., -5.]) b = abs(a) for i in range(5): @@ -1377,7 +1377,7 @@ assert a[i + 5] == abs(i) def test_auto_force(self): - from numpypy import array + from numpy import array a = array(range(5)) b = a - 1 a[2] = 3 @@ -1391,7 +1391,7 @@ assert c[1] == 4 def test_getslice(self): - from numpypy import array + from numpy import array a = array(5) exc = raises(ValueError, "a[:]") assert exc.value[0] == "cannot slice a 0-d array" @@ -1408,7 +1408,7 @@ assert s[0] == 5 def test_getslice_step(self): - from numpypy import array + from numpy import array a = array(range(10)) s = a[1:9:2] assert len(s) == 4 @@ -1416,7 +1416,7 @@ assert s[i] == a[2 * i + 1] def test_slice_update(self): - from numpypy import array + from numpy import array a = array(range(5)) s = a[0:3] s[1] = 10 @@ -1426,7 +1426,7 @@ def test_slice_invaidate(self): # check that slice shares invalidation list with - from numpypy import array + from numpy import array a = array(range(5)) s = a[0:2] b = array([10, 11]) @@ -1440,7 +1440,7 @@ assert d[1] == 12 def test_sum(self): - from numpypy import array, zeros, float16, complex64, str_ + from numpy import array, zeros, float16, complex64, str_ a = array(range(5)) assert a.sum() == 10 assert a[:4].sum() == 6 @@ -1470,7 +1470,7 @@ assert list(zeros((0, 2)).sum(axis=1)) == [] def test_reduce_nd(self): - from numpypy import arange, array + from numpy import arange, array a = arange(15).reshape(5, 3) assert a.sum() == 105 assert a.sum(keepdims=True) == 105 @@ -1504,7 +1504,7 @@ assert (array([[1,2],[3,4]]).prod(1) == [2, 12]).all() def test_prod(self): - from numpypy import array, dtype + from numpy import array, dtype a = array(range(1, 6)) assert a.prod() == 120.0 assert a.prod(keepdims=True) == 120.0 @@ -1520,7 +1520,7 @@ assert a.prod().dtype is dtype(dt) def test_max(self): - from numpypy import array, zeros + from numpy import array, zeros a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) assert a.max() == 5.7 assert a.max().shape == () @@ -1533,12 +1533,12 @@ assert list(zeros((0, 2)).max(axis=1)) == [] def test_max_add(self): - from numpypy import array + from numpy import array a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) assert (a + a).max() == 11.4 def test_min(self): - from numpypy import array, zeros + from numpy import array, zeros a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) assert a.min() == -3.0 assert a.min().shape == () @@ -1551,7 +1551,7 @@ assert list(zeros((0, 2)).min(axis=1)) == [] def test_argmax(self): - from numpypy import array + from numpy import array a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) r = a.argmax() assert r == 2 @@ -1580,7 +1580,7 @@ raises(NotImplementedError, a.argmax, axis=0) def test_argmin(self): - from numpypy import array + from numpy import array a = array([-1.2, 3.4, 5.7, -3.0, 2.7]) assert a.argmin() == 3 assert a.argmin(axis=None, out=None) == 3 @@ -1591,7 +1591,7 @@ raises(NotImplementedError, a.argmin, axis=0) def test_all(self): - from numpypy import array + from numpy import array a = array(range(5)) assert a.all() == False a[0] = 3.0 @@ -1602,7 +1602,7 @@ assert b.all() == True def test_any(self): - from numpypy import array, zeros + from numpy import array, zeros a = array(range(5)) assert a.any() == True assert a.any(keepdims=True) == True @@ -1613,7 +1613,7 @@ assert c.any() == False def test_dtype_guessing(self): - from numpypy import array, dtype + from numpy import array, dtype import sys assert array([True]).dtype is dtype(bool) assert array([True, False]).dtype is dtype(bool) @@ -1639,7 +1639,7 @@ def test_comparison(self): import operator - from numpypy import array, dtype + from numpy import array, dtype a = array(range(5)) b = array(range(5), float) @@ -1658,7 +1658,7 @@ assert c[i] == func(b[i], 3) def test___nonzero__(self): - from numpypy import array + from numpy import array a = array([1, 2]) raises(ValueError, bool, a) raises(ValueError, bool, a == a) @@ -1668,7 +1668,7 @@ assert not bool(array([0])) def test_slice_assignment(self): - from numpypy import array + from numpy import array a = array(range(5)) a[::-1] = a assert (a == [4, 3, 2, 1, 0]).all() @@ -1678,7 +1678,7 @@ assert (a == [8, 6, 4, 2, 0]).all() def test_virtual_views(self): - from numpypy import arange + from numpy import arange a = arange(15) c = (a + a) d = c[::2] @@ -1696,7 +1696,7 @@ assert b[1] == 2 def test_realimag_views(self): - from numpypy import arange, array + from numpy import arange, array a = array(1.5) assert a.real == 1.5 assert a.imag == 0.0 @@ -1743,7 +1743,7 @@ assert arange(4, dtype=' Author: Brian Kearns Branch: Changeset: r74840:0123a8ee6ab6 Date: 2014-12-05 15:16 -0500 http://bitbucket.org/pypy/pypy/changeset/0123a8ee6ab6/ Log: remove old test_lib_pypy tests of numpypy diff --git a/pypy/module/test_lib_pypy/numpypy/__init__.py b/pypy/module/test_lib_pypy/numpypy/__init__.py deleted file mode 100644 diff --git a/pypy/module/test_lib_pypy/numpypy/core/test_fromnumeric.py b/pypy/module/test_lib_pypy/numpypy/core/test_fromnumeric.py deleted file mode 100644 --- a/pypy/module/test_lib_pypy/numpypy/core/test_fromnumeric.py +++ /dev/null @@ -1,202 +0,0 @@ -from pypy.module.test_lib_pypy.numpypy.test_base import BaseNumpyAppTest - - -class AppTestFromNumeric(BaseNumpyAppTest): - def test_argmax(self): - # tests taken from numpy/core/fromnumeric.py docstring - from numpypy import arange, argmax - a = arange(6).reshape((2,3)) - assert argmax(a) == 5 - # assert (argmax(a, axis=0) == array([1, 1, 1])).all() - # assert (argmax(a, axis=1) == array([2, 2])).all() - b = arange(6) - b[1] = 5 - assert argmax(b) == 1 - - def test_argmin(self): - # tests adapted from test_argmax - from numpypy import arange, argmin - a = arange(6).reshape((2,3)) - assert argmin(a) == 0 - #assert (argmin(a, axis=0) == array([0, 0, 0])).all() - #assert (argmin(a, axis=1) == array([0, 0])).all() - b = arange(6) - b[1] = 0 - assert argmin(b) == 0 - - def test_ravel(self): - import numpypy as np - a = np.ravel(np.float64(1)) - assert np.array_equal(a, [1.]) - a = np.ravel(np.array([[1, 2, 3], [4, 5, 6]])) - assert np.array_equal(a, [1, 2, 3, 4, 5, 6]) - - def test_shape(self): - # tests taken from numpy/core/fromnumeric.py docstring - from numpypy import identity, shape - assert shape(identity(3)) == (3, 3) - assert shape([[1, 2]]) == (1, 2) - assert shape([0]) == (1,) - assert shape(0) == () - # a = array([(1, 2), (3, 4)], dtype=[('x', 'i4'), ('y', 'i4')]) - # assert shape(a) == (2,) - - def test_clip(self): - import numpypy as np - a = np.arange(10) - b = np.clip(a, 1, 8) - assert (b == [1, 1, 2, 3, 4, 5, 6, 7, 8, 8]).all() - assert (a == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]).all() - b = np.clip(a, 3, 6, out=a) - assert (b == [3, 3, 3, 3, 4, 5, 6, 6, 6, 6]).all() - assert (a == [3, 3, 3, 3, 4, 5, 6, 6, 6, 6]).all() - a = np.arange(10) - b = np.clip(a, [3,4,1,1,1,4,4,4,4,4], 8) - assert (b == [3, 4, 2, 3, 4, 5, 6, 7, 8, 8]).all() - assert (a == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]).all() - - def test_sum(self): - # tests taken from numpy/core/fromnumeric.py docstring - from numpypy import sum, ones, zeros, array - assert sum([0.5, 1.5])== 2.0 - assert sum([[0, 1], [0, 5]]) == 6 - # assert sum([0.5, 0.7, 0.2, 1.5], dtype=int32) == 1 - assert (sum([[0, 1], [0, 5]], axis=0) == array([0, 6])).all() - assert (sum([[0, 1], [0, 5]], axis=1) == array([1, 5])).all() - # If the accumulator is too small, overflow occurs: - # assert ones(128, dtype=int8).sum(dtype=int8) == -128 - - assert sum(range(10)) == 45 - assert sum(array(range(10))) == 45 - assert list(sum(zeros((0, 2)), axis=1)) == [] - - a = array([[1, 2], [3, 4]]) - out = array([[0, 0], [0, 0]]) - c = sum(a, axis=0, out=out[0]) - assert (c == [4, 6]).all() - assert (c == out[0]).all() - assert (c != out[1]).all() - - def test_amin(self): - # tests taken from numpy/core/fromnumeric.py docstring - from numpypy import array, arange, amin, zeros - a = arange(4).reshape((2,2)) - assert amin(a) == 0 - # # Minima along the first axis - # assert (amin(a, axis=0) == array([0, 1])).all() - # # Minima along the second axis - # assert (amin(a, axis=1) == array([0, 2])).all() - # # NaN behaviour - # b = arange(5, dtype=float) - # b[2] = NaN - # assert amin(b) == nan - # assert nanmin(b) == 0.0 - - assert amin(range(10)) == 0 - assert amin(array(range(10))) == 0 - assert list(amin(zeros((0, 2)), axis=1)) == [] - - a = array([[1, 2], [3, 4]]) - out = array([[0, 0], [0, 0]]) - c = amin(a, axis=1, out=out[0]) - assert (c == [1, 3]).all() - assert (c == out[0]).all() - assert (c != out[1]).all() - - def test_amax(self): - # tests taken from numpy/core/fromnumeric.py docstring - from numpypy import array, arange, amax, zeros - a = arange(4).reshape((2,2)) - assert amax(a) == 3 - # assert (amax(a, axis=0) == array([2, 3])).all() - # assert (amax(a, axis=1) == array([1, 3])).all() - # # NaN behaviour - # b = arange(5, dtype=float) - # b[2] = NaN - # assert amax(b) == nan - # assert nanmax(b) == 4.0 - - assert amax(range(10)) == 9 - assert amax(array(range(10))) == 9 - assert list(amax(zeros((0, 2)), axis=1)) == [] - - a = array([[1, 2], [3, 4]]) - out = array([[0, 0], [0, 0]]) - c = amax(a, axis=1, out=out[0]) - assert (c == [2, 4]).all() - assert (c == out[0]).all() - assert (c != out[1]).all() - - def test_alen(self): - # tests taken from numpy/core/fromnumeric.py docstring - from numpypy import array, zeros, alen - a = zeros((7,4,5)) - assert a.shape[0] == 7 - assert alen(a) == 7 - - def test_ndim(self): - # tests taken from numpy/core/fromnumeric.py docstring - from numpypy import array, ndim - assert ndim([[1,2,3],[4,5,6]]) == 2 - assert ndim(array([[1,2,3],[4,5,6]])) == 2 - assert ndim(1) == 0 - - def test_rank(self): - # tests taken from numpy/core/fromnumeric.py docstring - from numpypy import array, rank - assert rank([[1,2,3],[4,5,6]]) == 2 - assert rank(array([[1,2,3],[4,5,6]])) == 2 - assert rank(1) == 0 - - def test_var(self): - from numpypy import array, var - a = array([[1,2],[3,4]]) - assert var(a) == 1.25 - assert (var(a,0) == array([ 1., 1.])).all() - assert (var(a,1) == array([ 0.25, 0.25])).all() - - def test_std(self): - from numpypy import array, std - a = array([[1, 2], [3, 4]]) - assert std(a) == 1.1180339887498949 - assert (std(a, axis=0) == array([ 1., 1.])).all() - assert (std(a, axis=1) == array([ 0.5, 0.5])).all() - - def test_mean(self): - from numpypy import array, mean, arange - assert mean(array(range(5))) == 2.0 - assert mean(range(5)) == 2.0 - assert (mean(arange(10).reshape(5, 2), axis=0) == [4, 5]).all() - assert (mean(arange(10).reshape(5, 2), axis=1) == [0.5, 2.5, 4.5, 6.5, 8.5]).all() - - def test_reshape(self): - from numpypy import arange, array, dtype, reshape - a = arange(12) - b = reshape(a, (3, 4)) - assert b.shape == (3, 4) - a = range(12) - b = reshape(a, (3, 4)) - assert b.shape == (3, 4) - a = array(range(105)).reshape(3, 5, 7) - assert reshape(a, (1, -1)).shape == (1, 105) - assert reshape(a, (1, 1, -1)).shape == (1, 1, 105) - assert reshape(a, (-1, 1, 1)).shape == (105, 1, 1) - - def test_transpose(self): - from numpypy import arange, array, transpose, ones - x = arange(4).reshape((2,2)) - assert (transpose(x) == array([[0, 2],[1, 3]])).all() - # Once axes argument is implemented, add more tests - import sys - if '__pypy__' in sys.builtin_module_names: - raises(NotImplementedError, "transpose(x, axes=(1, 0, 2))") - # x = ones((1, 2, 3)) - # assert transpose(x, (1, 0, 2)).shape == (2, 1, 3) - - def test_fromnumeric(self): - from numpypy import array, swapaxes - x = array([[1,2,3]]) - assert (swapaxes(x,0,1) == array([[1], [2], [3]])).all() - x = array([[[0,1],[2,3]],[[4,5],[6,7]]]) - assert (swapaxes(x,0,2) == array([[[0, 4], [2, 6]], - [[1, 5], [3, 7]]])).all() diff --git a/pypy/module/test_lib_pypy/numpypy/core/test_numeric.py b/pypy/module/test_lib_pypy/numpypy/core/test_numeric.py deleted file mode 100644 --- a/pypy/module/test_lib_pypy/numpypy/core/test_numeric.py +++ /dev/null @@ -1,250 +0,0 @@ -from pypy.module.test_lib_pypy.numpypy.test_base import BaseNumpyAppTest - - -class AppTestBaseRepr(BaseNumpyAppTest): - def test_base3(self): - from numpypy import base_repr - assert base_repr(3**5, 3) == '100000' - - def test_positive(self): - from numpypy import base_repr - assert base_repr(12, 10) == '12' - assert base_repr(12, 10, 4) == '000012' - assert base_repr(12, 4) == '30' - assert base_repr(3731624803700888, 36) == '10QR0ROFCEW' - - def test_negative(self): - from numpypy import base_repr - assert base_repr(-12, 10) == '-12' - assert base_repr(-12, 10, 4) == '-000012' - assert base_repr(-12, 4) == '-30' - - -class AppTestRepr(BaseNumpyAppTest): - def test_repr(self): - from numpypy import array - assert repr(array([1, 2, 3, 4])) == 'array([1, 2, 3, 4])' - - def test_repr_2(self): - from numpypy import array, zeros - int_size = array(5).dtype.itemsize - a = array(range(5), float) - assert repr(a) == "array([ 0., 1., 2., 3., 4.])" - a = array([], float) - assert repr(a) == "array([], dtype=float64)" - a = zeros(1001) - assert repr(a) == "array([ 0., 0., 0., ..., 0., 0., 0.])" - a = array(range(5), int) - if a.dtype.itemsize == int_size: - assert repr(a) == "array([0, 1, 2, 3, 4])" - else: - assert repr(a) == "array([0, 1, 2, 3, 4], dtype=int64)" - a = array(range(5), 'int32') - if a.dtype.itemsize == int_size: - assert repr(a) == "array([0, 1, 2, 3, 4])" - else: - assert repr(a) == "array([0, 1, 2, 3, 4], dtype=int32)" - a = array([], long) - assert repr(a) == "array([], dtype=int64)" - a = array([True, False, True, False], "?") - assert repr(a) == "array([ True, False, True, False], dtype=bool)" - a = zeros([]) - assert repr(a) == "array(0.0)" - a = array(0.2) - assert repr(a) == "array(0.2)" - a = array([2]) - assert repr(a) == "array([2])" - - def test_repr_multi(self): - from numpypy import arange, zeros, array - a = zeros((3, 4)) - assert repr(a) == '''array([[ 0., 0., 0., 0.], - [ 0., 0., 0., 0.], - [ 0., 0., 0., 0.]])''' - a = zeros((2, 3, 4)) - assert repr(a) == '''array([[[ 0., 0., 0., 0.], - [ 0., 0., 0., 0.], - [ 0., 0., 0., 0.]], - - [[ 0., 0., 0., 0.], - [ 0., 0., 0., 0.], - [ 0., 0., 0., 0.]]])''' - a = arange(1002).reshape((2, 501)) - assert repr(a) == '''array([[ 0, 1, 2, ..., 498, 499, 500], - [ 501, 502, 503, ..., 999, 1000, 1001]])''' - assert repr(a.T) == '''array([[ 0, 501], - [ 1, 502], - [ 2, 503], - ..., - [ 498, 999], - [ 499, 1000], - [ 500, 1001]])''' - a = arange(2).reshape((2,1)) - assert repr(a) == '''array([[0], - [1]])''' - - def test_repr_slice(self): - from numpypy import array, zeros - a = array(range(5), float) - b = a[1::2] - assert repr(b) == "array([ 1., 3.])" - a = zeros(2002) - b = a[::2] - assert repr(b) == "array([ 0., 0., 0., ..., 0., 0., 0.])" - a = array((range(5), range(5, 10)), dtype="int16") - b = a[1, 2:] - assert repr(b) == "array([7, 8, 9], dtype=int16)" - # an empty slice prints its shape - b = a[2:1, ] - assert repr(b) == "array([], shape=(0, 5), dtype=int16)" - - def test_str(self): - from numpypy import array, zeros - a = array(range(5), float) - assert str(a) == "[ 0. 1. 2. 3. 4.]" - assert str((2 * a)[:]) == "[ 0. 2. 4. 6. 8.]" - a = zeros(1001) - assert str(a) == "[ 0. 0. 0. ..., 0. 0. 0.]" - - a = array(range(5), dtype=long) - assert str(a) == "[0 1 2 3 4]" - a = array([True, False, True, False], dtype="?") - assert str(a) == "[ True False True False]" - - a = array(range(5), dtype="int8") - assert str(a) == "[0 1 2 3 4]" - - a = array(range(5), dtype="int16") - assert str(a) == "[0 1 2 3 4]" - - a = array((range(5), range(5, 10)), dtype="int16") - assert str(a) == "[[0 1 2 3 4]\n [5 6 7 8 9]]" - - a = array(3, dtype=int) - assert str(a) == "3" - - a = zeros((400, 400), dtype=int) - assert str(a) == '[[0 0 0 ..., 0 0 0]\n [0 0 0 ..., 0 0 0]\n [0 0 0 ..., 0 0 0]\n ..., \n [0 0 0 ..., 0 0 0]\n [0 0 0 ..., 0 0 0]\n [0 0 0 ..., 0 0 0]]' - a = zeros((2, 2, 2)) - r = str(a) - assert r == '[[[ 0. 0.]\n [ 0. 0.]]\n\n [[ 0. 0.]\n [ 0. 0.]]]' - - def test_str_slice(self): - from numpypy import array, zeros - a = array(range(5), float) - b = a[1::2] - assert str(b) == "[ 1. 3.]" - a = zeros(2002) - b = a[::2] - assert str(b) == "[ 0. 0. 0. ..., 0. 0. 0.]" - a = array((range(5), range(5, 10)), dtype="int16") - b = a[1, 2:] - assert str(b) == "[7 8 9]" - b = a[2:1, ] - assert str(b) == "[]" - - def test_equal(self): - from numpypy import array, array_equal - - a = [1, 2, 3] - b = [1, 2, 3] - - assert array_equal(a, b) - assert array_equal(a, array(b)) - assert array_equal(array(a), b) - assert array_equal(array(a), array(b)) - - def test_not_equal(self): - from numpypy import array, array_equal - - a = [1, 2, 3] - b = [1, 2, 4] - - assert not array_equal(a, b) - assert not array_equal(a, array(b)) - assert not array_equal(array(a), b) - assert not array_equal(array(a), array(b)) - - def test_mismatched_shape(self): - from numpypy import array, array_equal - - a = [1, 2, 3] - b = [[1, 2, 3], [1, 2, 3]] - - assert not array_equal(a, b) - assert not array_equal(a, array(b)) - assert not array_equal(array(a), b) - assert not array_equal(array(a), array(b)) - - def test_equiv(self): - import numpypy as np - - assert np.array_equiv([1, 2], [1, 2]) - assert not np.array_equiv([1, 2], [1, 3]) - assert np.array_equiv([1, 2], [[1, 2], [1, 2]]) - assert not np.array_equiv([1, 2], [[1, 2, 1, 2], [1, 2, 1, 2]]) - assert not np.array_equiv([1, 2], [[1, 2], [1, 3]]) - - -class AppTestNumeric(BaseNumpyAppTest): - def test_argwhere(self): - import numpypy as np - x = np.arange(6).reshape(2,3) - a = np.argwhere(x>1) - assert np.array_equal(a, - [[0, 2], - [1, 0], - [1, 1], - [1, 2]] - ) - - def test_flatnonzero(self): - import numpypy as np - x = np.arange(-2, 3) - a = np.flatnonzero(x) - assert np.array_equal(a, [0, 1, 3, 4]) - - def test_outer(self): - from numpypy import array, outer - a = [1, 2, 3] - b = [4, 5, 6] - res = outer(a, b) - expected = array([[ 4, 5, 6], - [ 8, 10, 12], - [12, 15, 18]]) - assert (res == expected).all() - - def test_vdot(self): - import numpypy as np - a = np.array([1+2j,3+4j]) - b = np.array([5+6j,7+8j]) - c = np.vdot(a, b) - assert c == (70-8j) - c = np.vdot(b, a) - assert c == (70+8j) - - a = np.array([[1, 4], [5, 6]]) - b = np.array([[4, 1], [2, 2]]) - c = np.vdot(a, b) - assert c == 30 - c = np.vdot(b, a) - assert c == 30 - - def test_identity(self): - from numpypy import array, int32, float64, dtype, identity - a = identity(0) - assert len(a) == 0 - assert a.dtype == dtype('float64') - assert a.shape == (0, 0) - b = identity(1, dtype=int32) - assert len(b) == 1 - assert b[0][0] == 1 - assert b.shape == (1, 1) - assert b.dtype == dtype('int32') - c = identity(2) - assert c.shape == (2, 2) - assert (c == [[1, 0], [0, 1]]).all() - d = identity(3, dtype='int32') - assert d.shape == (3, 3) - assert d.dtype == dtype('int32') - assert (d == [[1, 0, 0], [0, 1, 0], [0, 0, 1]]).all() diff --git a/pypy/module/test_lib_pypy/numpypy/core/test_shape_base.py b/pypy/module/test_lib_pypy/numpypy/core/test_shape_base.py deleted file mode 100644 --- a/pypy/module/test_lib_pypy/numpypy/core/test_shape_base.py +++ /dev/null @@ -1,131 +0,0 @@ -from pypy.module.test_lib_pypy.numpypy.test_base import BaseNumpyAppTest - - -class AppTestShapeBase(BaseNumpyAppTest): - - def test_atleast_1d(self): - from numpypy import array, array_equal - import numpypy as np - a = np.atleast_1d(1.0) - assert np.array_equal(a, [1.]) - - x = np.arange(9.0).reshape(3, 3) - a = np.atleast_1d(x) - assert np.array_equal(a, [[0., 1., 2.], - [3., 4., 5.], - [6., 7., 8.]]) - assert np.atleast_1d(x) is x - - a = np.atleast_1d(1, [3, 4]) - assert len(a) == 2 - assert array_equal(a[0], [1]) - assert array_equal(a[1], [3, 4]) - - def test_atleast_2d(self): - import numpypy as np - a = np.atleast_2d(3.0) - assert np.array_equal(a, [[3.]]) - - x = np.arange(3.0) - a = np.atleast_2d(x) - assert np.array_equal(a, [[0., 1., 2.]]) - - a = np.atleast_2d(1, [1, 2], [[1, 2]]) - assert len(a) == 3 - assert np.array_equal(a[0], [[1]]) - assert np.array_equal(a[1], [[1, 2]]) - assert np.array_equal(a[2], [[1, 2]]) - - def test_atleast_3d(self): - import numpypy as np - - a = np.atleast_3d(3.0) - assert np.array_equal(a, [[[3.]]]) - - x = np.arange(3.0) - assert np.atleast_3d(x).shape == (1, 3, 1) - - x = np.arange(12.0).reshape(4, 3) - assert np.atleast_3d(x).shape == (4, 3, 1) - - a = np.atleast_3d([1, 2]) - assert np.array_equal(a, [[[1], - [2]]]) - assert a.shape == (1, 2, 1) - - a = np.atleast_3d([[1, 2]]) - assert np.array_equal(a, [[[1], - [2]]]) - assert a.shape == (1, 2, 1) - - a = np.atleast_3d([[[1, 2]]]) - assert np.array_equal(a, [[[1, 2]]]) - assert a.shape == (1, 1, 2) - - def test_vstack(self): - import numpypy as np - - a = np.array([1, 2, 3]) - b = np.array([2, 3, 4]) - c = np.vstack((a, b)) - assert np.array_equal(c, [[1, 2, 3], - [2, 3, 4]]) - - a = np.array([[1], [2], [3]]) - b = np.array([[2], [3], [4]]) - c = np.vstack((a, b)) - assert np.array_equal(c, [[1], - [2], - [3], - [2], - [3], - [4]]) - - for shape1, shape2 in [[(2, 1), (3, 1)], - [(2, 4), [3, 4]]]: - a, b = np.ones(shape1), np.ones(shape2) - assert np.all(np.vstack((a, b)) == - np.ones((a.shape[0] + b.shape[0], - a.shape[1]))) - - #skip("https://bugs.pypy.org/issue1394") - for shape1, shape2 in [[(3, 2, 4), (7, 2, 4)], - [(0, 2, 7), (10, 2, 7)], - [(0, 2, 7), (0, 2, 7)]]: - a, b = np.ones(shape1), np.ones(shape2) - assert np.all(np.vstack((a, b)) == - np.ones((a.shape[0] + b.shape[0], - a.shape[1], - a.shape[2]))) - - def test_hstack(self): - import numpypy as np - a = np.array((1, 2, 3)) - b = np.array((2, 3, 4)) - c = np.hstack((a, b)) - assert np.array_equal(c, [1, 2, 3, 2, 3, 4]) - - a = np.array([[1], [2], [3]]) - b = np.array([[2], [3], [4]]) - c = np.hstack((a, b)) - assert np.array_equal(c, [[1, 2], - [2, 3], - [3, 4]]) - - for shape1, shape2 in [[(1, 2), (1, 3)], - [(4, 2), (4, 3)]]: - a, b = np.ones(shape1), np.ones(shape2) - assert np.all(np.hstack((a, b)) == - np.ones((a.shape[0], - a.shape[1] + b.shape[1]))) - - #skip("https://bugs.pypy.org/issue1394") - for shape1, shape2 in [[(2, 3, 4), (2, 7, 4)], - [(1, 4, 7), (1, 10, 7)], - [(1, 4, 7), (1, 0, 7)], - [(1, 0, 7), (1, 0, 7)]]: - a, b = np.ones(shape1), np.ones(shape2) - assert np.all(np.hstack((a, b)) == - np.ones((a.shape[0], - a.shape[1] + b.shape[1], - a.shape[2]))) diff --git a/pypy/module/test_lib_pypy/numpypy/lib/test_function_base.py b/pypy/module/test_lib_pypy/numpypy/lib/test_function_base.py deleted file mode 100644 --- a/pypy/module/test_lib_pypy/numpypy/lib/test_function_base.py +++ /dev/null @@ -1,7 +0,0 @@ -from pypy.module.test_lib_pypy.numpypy.test_base import BaseNumpyAppTest - -class AppTestFunctionBase(BaseNumpyAppTest): - def test_average(self): - from numpypy import array, average - assert average(range(10)) == 4.5 - assert average(array(range(10))) == 4.5 diff --git a/pypy/module/test_lib_pypy/numpypy/lib/test_shape_base_lib.py b/pypy/module/test_lib_pypy/numpypy/lib/test_shape_base_lib.py deleted file mode 100644 --- a/pypy/module/test_lib_pypy/numpypy/lib/test_shape_base_lib.py +++ /dev/null @@ -1,34 +0,0 @@ -from pypy.module.test_lib_pypy.numpypy.test_base import BaseNumpyAppTest - -class AppTestShapeBase(BaseNumpyAppTest): - def test_dstack(self): - import numpypy as np - a = np.array((1, 2, 3)) - b = np.array((2, 3, 4)) - c = np.dstack((a, b)) - assert np.array_equal(c, [[[1, 2], [2, 3], [3, 4]]]) - - a = np.array([[1], [2], [3]]) - b = np.array([[2], [3], [4]]) - c = np.dstack((a, b)) - assert np.array_equal(c, [[[1, 2]], [[2, 3]], [[3, 4]]]) - - #skip("https://bugs.pypy.org/issue1394") - for shape1, shape2 in [[(4, 2, 3), (4, 2, 7)], - [(7, 2, 0), (7, 2, 10)], - [(7, 2, 0), (7, 2, 0)]]: - a, b = np.ones(shape1), np.ones(shape2) - assert np.all(np.dstack((a, b)) == - np.ones((a.shape[0], - a.shape[1], - a.shape[2] + b.shape[2]))) - - for shape1, shape2 in [[(4, 2, 3, 5), (4, 2, 7, 5)], - [(7, 2, 0, 5), (7, 2, 10, 5)], - [(7, 2, 0, 5), (7, 2, 0, 5)]]: - a, b = np.ones(shape1), np.ones(shape2) - assert np.all(np.dstack((a, b)) == - np.ones((a.shape[0], - a.shape[1], - a.shape[2] + b.shape[2], - a.shape[3]))) diff --git a/pypy/module/test_lib_pypy/numpypy/lib/test_twodim_base.py b/pypy/module/test_lib_pypy/numpypy/lib/test_twodim_base.py deleted file mode 100644 --- a/pypy/module/test_lib_pypy/numpypy/lib/test_twodim_base.py +++ /dev/null @@ -1,30 +0,0 @@ -from pypy.module.test_lib_pypy.numpypy.test_base import BaseNumpyAppTest - -class AppTestTwoDimBase(BaseNumpyAppTest): - def test_eye(self): - from numpypy import eye, int32, dtype - a = eye(0) - assert len(a) == 0 - assert a.dtype == dtype('float64') - assert a.shape == (0, 0) - b = eye(1, dtype=int32) - assert len(b) == 1 - assert b[0][0] == 1 - assert b.shape == (1, 1) - assert b.dtype == dtype('int32') - c = eye(2) - assert c.shape == (2, 2) - assert (c == [[1, 0], [0, 1]]).all() - d = eye(3, dtype='int32') - assert d.shape == (3, 3) - assert d.dtype == dtype('int32') - assert (d == [[1, 0, 0], [0, 1, 0], [0, 0, 1]]).all() - e = eye(3, 4) - assert e.shape == (3, 4) - assert (e == [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]]).all() - f = eye(2, 4, k=3) - assert f.shape == (2, 4) - assert (f == [[0, 0, 0, 1], [0, 0, 0, 0]]).all() - g = eye(3, 4, k=-1) - assert g.shape == (3, 4) - assert (g == [[0, 0, 0, 0], [1, 0, 0, 0], [0, 1, 0, 0]]).all() diff --git a/pypy/module/test_lib_pypy/numpypy/test_base.py b/pypy/module/test_lib_pypy/numpypy/test_base.py deleted file mode 100644 --- a/pypy/module/test_lib_pypy/numpypy/test_base.py +++ /dev/null @@ -1,12 +0,0 @@ -class BaseNumpyAppTest(object): - @classmethod - def setup_class(cls): - if cls.runappdirect: - try: - import numpy - except ImportError: - skip("no numpy found") - import sys - sys.modules['numpypy'] = numpy - else: - skip("app-level tests") diff --git a/pypy/module/test_lib_pypy/numpypy/test_numpy.py b/pypy/module/test_lib_pypy/numpypy/test_numpy.py deleted file mode 100644 --- a/pypy/module/test_lib_pypy/numpypy/test_numpy.py +++ /dev/null @@ -1,67 +0,0 @@ -from pypy.conftest import option -import py, sys -from pypy.module.test_lib_pypy.numpypy.test_base import BaseNumpyAppTest - -class AppTestNumpy(BaseNumpyAppTest): - def test_min_max_after_import(self): - import __builtin__ - from __builtin__ import * - - from numpypy import * - assert min is __builtin__.min - assert max is __builtin__.max - - assert min(1, 100) == 1 - assert min(100, 1) == 1 - - assert max(1, 100) == 100 - assert max(100, 1) == 100 - - assert min(4, 3, 2, 1) == 1 - assert max(1, 2, 3, 4) == 4 - - from numpypy import min, max, amin, amax - assert min is not __builtin__.min - assert max is not __builtin__.max - assert min is amin - assert max is amax - - def test_builtin_aliases(self): - import __builtin__ - import numpypy - from numpypy import * - - for name in ['bool', 'int', 'long', 'float', 'complex', 'object', - 'unicode', 'str']: - assert name not in locals() - assert getattr(numpypy, name) is getattr(__builtin__, name) - - def test_typeinfo(self): - import numpypy - assert 'typeinfo' not in dir(numpypy) - assert 'typeinfo' in dir(numpypy.core.multiarray) - - def test_set_string_function(self): - import numpypy - assert numpypy.set_string_function is not \ - numpypy.core.multiarray.set_string_function - - def test_constants(self): - import math - import numpypy - assert numpypy.PZERO == numpypy.NZERO == 0.0 - assert math.isinf(numpypy.inf) - assert math.isnan(numpypy.nan) - - def test___all__(self): - import numpypy - assert '__all__' in dir(numpypy) - assert 'numpypy' not in dir(numpypy) - - def test_get_include(self): - import numpypy, os, sys - assert 'get_include' in dir(numpypy) - path = numpypy.get_include() - if not hasattr(sys, 'pypy_translation_info'): - skip("pypy white-box test") - assert os.path.exists(path + '/numpy/arrayobject.h') From noreply at buildbot.pypy.org Fri Dec 5 21:34:27 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 21:34:27 +0100 (CET) Subject: [pypy-commit] creflect default: ffi.getctype() Message-ID: <20141205203427.F185C1D28F0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r181:f1168b43ad59 Date: 2014-12-05 21:34 +0100 http://bitbucket.org/cffi/creflect/changeset/f1168b43ad59/ Log: ffi.getctype() diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -643,10 +643,53 @@ } } +static PyObject *ffi_getctype(ZefFFIObject *self, PyObject *args) +{ + PyObject *cdecl, *res; + char *p, *replace_with = ""; + int add_paren, add_space; + CTypeDescrObject *ct; + size_t replace_with_len; + + if (!PyArg_ParseTuple(args, "O|s:getctype", &cdecl, &replace_with)) + return NULL; + + ct = _ffi_type(self, cdecl, ACCEPT_STRING|ACCEPT_CTYPE); + if (ct == NULL) + return NULL; + + while (replace_with[0] != 0 && isspace(replace_with[0])) + replace_with++; + replace_with_len = strlen(replace_with); + while (replace_with_len > 0 && isspace(replace_with[replace_with_len - 1])) + replace_with_len--; + + add_paren = (replace_with[0] == '*' && + ((ct->ct_flags & (CT_ARRAY | CT_FUNCTION)) != 0)); + add_space = (!add_paren && replace_with_len > 0 && + replace_with[0] != '[' && replace_with[0] != '('); + + res = combine_type_name_l(ct, replace_with_len + add_space + 2 * add_paren); + if (res == NULL) + return NULL; + + p = PyString_AS_STRING(res) + ct->ct_name_position; + if (add_paren) + *p++ = '('; + if (add_space) + *p++ = ' '; + memcpy(p, replace_with, replace_with_len); + if (add_paren) + p[replace_with_len] = ')'; + return res; +} + + 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}, + {"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_basic.py b/zeffir/test/test_basic.py --- a/zeffir/test/test_basic.py +++ b/zeffir/test/test_basic.py @@ -54,3 +54,21 @@ p = ffi.new("char[]", "----abcd") q = ffi.cast("int *", p) assert q[1] in [0x61626364, 0x64636261] + +def test_getctype(): + ffi = support.new_ffi() + assert ffi.getctype("int") == "int" + assert ffi.getctype("int", 'x') == "int x" + assert ffi.getctype("int*") == "int *" + assert ffi.getctype("int*", '') == "int *" + assert ffi.getctype("int*", 'x') == "int * x" + assert ffi.getctype("int", '*') == "int *" + assert ffi.getctype("int", ' * x ') == "int * x" + assert ffi.getctype(ffi.typeof("int*"), '*') == "int * *" + assert ffi.getctype("int", '[5]') == "int[5]" + assert ffi.getctype("int[5]", '[6]') == "int[6][5]" + assert ffi.getctype("int[5]", '(*)') == "int(*)[5]" + # special-case for convenience: automatically put '()' around '*' + assert ffi.getctype("int[5]", '*') == "int(*)[5]" + assert ffi.getctype("int[5]", '*foo') == "int(*foo)[5]" + assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]" diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h --- a/zeffir/zeffir.h +++ b/zeffir/zeffir.h @@ -23,3 +23,5 @@ static int fill_array_type(CTypeDescrObject *ctptr); static CTypeDescrObject *fetch_pointer_type(PyObject *types_dict, CTypeDescrObject *totype); +static PyObject *combine_type_name_l(CTypeDescrObject *ct, + size_t extra_text_len); From noreply at buildbot.pypy.org Fri Dec 5 21:41:57 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 21:41:57 +0100 (CET) Subject: [pypy-commit] creflect default: copy cdata_as_number from _cffi_backend Message-ID: <20141205204157.4DA911D2A0C@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r182:7f8cb0c71de4 Date: 2014-12-05 21:42 +0100 http://bitbucket.org/cffi/creflect/changeset/7f8cb0c71de4/ Log: copy cdata_as_number from _cffi_backend diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -1050,6 +1050,85 @@ } } +//1699 +static int cdata_nonzero(CDataObject *cd) +{ + return cd->c_data != NULL; +} + + +//1751 +static PyObject *cdata_float(CDataObject *cd) +{ + if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { + double value; + /*READ(cd->c_data, cd->c_type->ct_size)*/ + if (!(cd->c_type->ct_flags & CT_IS_LONGDOUBLE)) { + value = read_raw_float_data(cd->c_data, cd->c_type->ct_size); + } + else { + value = (double)read_raw_longdouble_data(cd->c_data); + } + return PyFloat_FromDouble(value); + } + PyErr_Format(PyExc_TypeError, "float() not supported on cdata '%s'", + cd->c_type->ct_name); + return NULL; +} + +//1700 +static PyObject *cdata_int(CDataObject *cd) +{ + if ((cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_FITS_LONG)) + == (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_FITS_LONG)) { + /* this case is to handle enums, but also serves as a slight + performance improvement for some other primitive types */ + long value; + /*READ(cd->c_data, cd->c_type->ct_size)*/ + value = (long)read_raw_signed_data(cd->c_data, cd->c_type->ct_size); + return PyInt_FromLong(value); + } + if (cd->c_type->ct_flags & (CT_PRIMITIVE_SIGNED|CT_PRIMITIVE_UNSIGNED)) { + return convert_to_object(cd->c_data, cd->c_type); + } + else if (cd->c_type->ct_flags & CT_PRIMITIVE_CHAR) { + /*READ(cd->c_data, cd->c_type->ct_size)*/ + if (cd->c_type->ct_size == sizeof(char)) + return PyInt_FromLong((unsigned char)cd->c_data[0]); +#ifdef HAVE_WCHAR_H + else + return PyInt_FromLong((long)*(wchar_t *)cd->c_data); +#endif + } + else if (cd->c_type->ct_flags & CT_PRIMITIVE_FLOAT) { + PyObject *o = cdata_float(cd); +#if PY_MAJOR_VERSION < 3 + PyObject *r = o ? PyNumber_Int(o) : NULL; +#else + PyObject *r = o ? PyNumber_Long(o) : NULL; +#endif + Py_XDECREF(o); + return r; + } + PyErr_Format(PyExc_TypeError, "int() not supported on cdata '%s'", + cd->c_type->ct_name); + return NULL; +} + +#if PY_MAJOR_VERSION < 3 +//1739 +static PyObject *cdata_long(CDataObject *cd) +{ + PyObject *res = cdata_int(cd); + if (res != NULL && PyInt_CheckExact(res)) { + PyObject *o = PyLong_FromLong(PyInt_AS_LONG(res)); + Py_DECREF(res); + res = o; + } + return res; +} +#endif + //1769 static PyObject *cdata_richcompare(PyObject *v, PyObject *w, int op) { @@ -1337,6 +1416,97 @@ return convert_from_object(c, ctitem, v); } +//2081 +static PyObject *_cdata_add_or_sub(PyObject *v, PyObject *w, int sign) +{ + Py_ssize_t i, itemsize; + CDataObject *cd; + CTypeDescrObject *ctptr; + + if (!CData_Check(v)) { + PyObject *swap; + assert(CData_Check(w)); + if (sign != 1) + goto not_implemented; + swap = v; + v = w; + w = swap; + } + + i = PyNumber_AsSsize_t(w, PyExc_OverflowError); + if (i == -1 && PyErr_Occurred()) + return NULL; + i *= sign; + + cd = (CDataObject *)v; + if (cd->c_type->ct_flags & CT_POINTER) + ctptr = cd->c_type; + else if (cd->c_type->ct_flags & CT_ARRAY) { + ctptr = (CTypeDescrObject *)cd->c_type->ct_stuff; + } + else { + PyErr_Format(PyExc_TypeError, "cannot add a cdata '%s' and a number", + cd->c_type->ct_name); + return NULL; + } + itemsize = ctptr->ct_itemdescr->ct_size; + if (itemsize < 0) { + if (ctptr->ct_flags & CT_IS_VOID_PTR) { + itemsize = 1; + } + else { + PyErr_Format(PyExc_TypeError, + "ctype '%s' points to items of unknown size", + cd->c_type->ct_name); + return NULL; + } + } + return new_simple_cdata(cd->c_data + i * itemsize, ctptr); + + not_implemented: + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +//2133 +static PyObject *cdata_add(PyObject *v, PyObject *w) +{ + return _cdata_add_or_sub(v, w, +1); +} + +//2139 +static PyObject *cdata_sub(PyObject *v, PyObject *w) +{ + if (CData_Check(v) && CData_Check(w)) { + CDataObject *cdv = (CDataObject *)v; + CDataObject *cdw = (CDataObject *)w; + CTypeDescrObject *ct = cdw->c_type; + Py_ssize_t diff, itemsize; + + if (ct->ct_flags & CT_ARRAY) /* ptr_to_T - array_of_T: ok */ + ct = (CTypeDescrObject *)ct->ct_stuff; + + if (ct != cdv->c_type || !(ct->ct_flags & CT_POINTER) || + (ct->ct_itemdescr->ct_size <= 0 && + !(ct->ct_flags & CT_IS_VOID_PTR))) { + PyErr_Format(PyExc_TypeError, + "cannot subtract cdata '%s' and cdata '%s'", + cdv->c_type->ct_name, ct->ct_name); + return NULL; + } + itemsize = ct->ct_itemdescr->ct_size; + if (itemsize <= 0) itemsize = 1; + diff = (cdv->c_data - cdw->c_data) / itemsize; +#if PY_MAJOR_VERSION < 3 + return PyInt_FromSsize_t(diff); +#else + return PyLong_FromSsize_t(diff); +#endif + } + + return _cdata_add_or_sub(v, w, -1); +} + //2172 static PyObject *cdata_getattro(CDataObject *cd, PyObject *attr) { @@ -1390,6 +1560,40 @@ } +static PyNumberMethods CData_as_number = { + (binaryfunc)cdata_add, /*nb_add*/ + (binaryfunc)cdata_sub, /*nb_subtract*/ + 0, /*nb_multiply*/ +#if PY_MAJOR_VERSION < 3 + 0, /*nb_divide*/ +#endif + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + 0, /*nb_negative*/ + 0, /*nb_positive*/ + 0, /*nb_absolute*/ + (inquiry)cdata_nonzero, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ +#if PY_MAJOR_VERSION < 3 + 0, /*nb_coerce*/ +#endif + (unaryfunc)cdata_int, /*nb_int*/ +#if PY_MAJOR_VERSION < 3 + (unaryfunc)cdata_long, /*nb_long*/ +#else + 0, +#endif + (unaryfunc)cdata_float, /*nb_float*/ + 0, /*nb_oct*/ + 0, /*nb_hex*/ +}; + static PyMappingMethods CData_as_mapping = { (lenfunc)cdata_length, /*mp_length*/ (binaryfunc)cdata_subscript, /*mp_subscript*/ @@ -1407,7 +1611,7 @@ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)cdata_repr, /* tp_repr */ - 0,//&CData_as_number, /* tp_as_number */ + &CData_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ &CData_as_mapping, /* tp_as_mapping */ (hashfunc)cdata_hash, /* tp_hash */ diff --git a/zeffir/test/test_cdata.py b/zeffir/test/test_cdata.py --- a/zeffir/test/test_cdata.py +++ b/zeffir/test/test_cdata.py @@ -25,3 +25,16 @@ ffi = support.new_ffi() p = ffi.new("int[]", [10, 20, 30]) assert p[2] == 30 + +def test_cdata_as_number(): + ffi = support.new_ffi() + p = ffi.new("int[]", [10, 20, 30]) + assert (p + 2)[0] == 30 + assert (p + 2) - p == 2 + assert (p + 2) - (p + 1) == 1 + assert p + assert not ffi.NULL + assert int(ffi.cast("short", 40000)) == 40000 - 65536 + assert long(ffi.cast("short", 40000)) == 40000 - 65536 + x = float(ffi.cast("float", 1.222)) + assert 1E-15 < abs(x - 1.222) < 1E-8 # must get rounding errors From noreply at buildbot.pypy.org Fri Dec 5 21:44:47 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 21:44:47 +0100 (CET) Subject: [pypy-commit] creflect default: cdata iteration (copied from _cffi_backend) Message-ID: <20141205204447.0834F1D2A0C@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r183:0290e34a02b3 Date: 2014-12-05 21:45 +0100 http://bitbucket.org/cffi/creflect/changeset/0290e34a02b3/ Log: cdata iteration (copied from _cffi_backend) diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -1559,6 +1559,7 @@ return PyObject_GenericSetAttr((PyObject *)cd, attr, value); } +static PyObject *cdata_iter(CDataObject *); static PyNumberMethods CData_as_number = { (binaryfunc)cdata_add, /*nb_add*/ @@ -1626,7 +1627,7 @@ 0, /* tp_clear */ cdata_richcompare, /* tp_richcompare */ offsetof(CDataObject, c_weakreflist), /* tp_weaklistoffset */ - 0,//(getiterfunc)cdata_iter, /* tp_iter */ + (getiterfunc)cdata_iter, /* tp_iter */ 0, /* tp_iternext */ }; diff --git a/zeffir/citer.c b/zeffir/citer.c new file mode 100644 --- /dev/null +++ b/zeffir/citer.c @@ -0,0 +1,79 @@ + +typedef struct { + PyObject_HEAD + char *di_next, *di_stop; + CDataObject *di_object; + CTypeDescrObject *di_itemtype; +} CDataIterObject; + +static PyObject * +cdataiter_next(CDataIterObject *it) +{ + char *result = it->di_next; + if (result != it->di_stop) { + it->di_next = result + it->di_itemtype->ct_size; + return convert_to_object(result, it->di_itemtype); + } + return NULL; +} + +static void +cdataiter_dealloc(CDataIterObject *it) +{ + Py_DECREF(it->di_object); + PyObject_Del(it); +} + +static PyTypeObject CDataIter_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "_cffi_backend.CDataIter", /* tp_name */ + sizeof(CDataIterObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)cdataiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)cdataiter_next, /* tp_iternext */ +}; + +static PyObject * +cdata_iter(CDataObject *cd) +{ + CDataIterObject *it; + + if (!(cd->c_type->ct_flags & CT_ARRAY)) { + PyErr_Format(PyExc_TypeError, "cdata '%s' does not support iteration", + cd->c_type->ct_name); + return NULL; + } + + it = PyObject_New(CDataIterObject, &CDataIter_Type); + if (it == NULL) + return NULL; + + Py_INCREF(cd); + it->di_object = cd; + it->di_itemtype = cd->c_type->ct_itemdescr; + it->di_next = cd->c_data; + it->di_stop = cd->c_data + get_array_length(cd) * it->di_itemtype->ct_size; + return (PyObject *)it; +} diff --git a/zeffir/test/test_cdata.py b/zeffir/test/test_cdata.py --- a/zeffir/test/test_cdata.py +++ b/zeffir/test/test_cdata.py @@ -38,3 +38,9 @@ assert long(ffi.cast("short", 40000)) == 40000 - 65536 x = float(ffi.cast("float", 1.222)) assert 1E-15 < abs(x - 1.222) < 1E-8 # must get rounding errors + +def test_cdata_iter(): + ffi = support.new_ffi() + p = ffi.new("int[]", [10, 20, 30]) + it = iter(p) + assert list(it) == [10, 20, 30] diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c --- a/zeffir/zeffir.c +++ b/zeffir/zeffir.c @@ -13,6 +13,7 @@ #include "zeffir.h" #include "ctype.c" #include "cdata.c" +#include "citer.c" #include "cglob.c" #include "lib_obj.c" #include "cfunc.c" From noreply at buildbot.pypy.org Fri Dec 5 21:56:10 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 21:56:10 +0100 (CET) Subject: [pypy-commit] creflect default: ffi.new_handle(), ffi.from_handle() Message-ID: <20141205205610.C21C21D2CF0@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r184:f6141dc25e53 Date: 2014-12-05 21:56 +0100 http://bitbucket.org/cffi/creflect/changeset/f6141dc25e53/ Log: ffi.new_handle(), ffi.from_handle() diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -1,10 +1,10 @@ -typedef struct { +struct cdataobject_s { PyObject_HEAD CTypeDescrObject *c_type; char *c_data; PyObject *c_weakreflist; -} CDataObject; +}; typedef union { unsigned char m_char; @@ -884,64 +884,59 @@ //1491 static void cdataowninggc_dealloc(CDataObject *cd) { - abort(); -#if 0 - assert(!(cd->c_type->ct_flags & (CT_IS_PTR_TO_OWNED | - CT_PRIMITIVE_ANY | - CT_STRUCT | CT_UNION))); + assert(!(cd->c_type->ct_flags & (CT_PRIMITIVE_ANY | CT_STRUCT | CT_UNION))); PyObject_GC_UnTrack(cd); if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ PyObject *x = (PyObject *)(cd->c_data + 42); Py_DECREF(x); } +#if 0 else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ ffi_closure *closure = (ffi_closure *)cd->c_data; PyObject *args = (PyObject *)(closure->user_data); Py_XDECREF(args); cffi_closure_free(closure); } +#endif cdata_dealloc(cd); -#endif } //1534 static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg) { - abort(); -#if 0 if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ PyObject *x = (PyObject *)(cd->c_data + 42); Py_VISIT(x); } +#if 0 else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ ffi_closure *closure = (ffi_closure *)cd->c_data; PyObject *args = (PyObject *)(closure->user_data); Py_VISIT(args); } +#endif return 0; -#endif } //1548 static int cdataowninggc_clear(CDataObject *cd) { - abort(); -#if 0 if (cd->c_type->ct_flags & CT_IS_VOID_PTR) { /* a handle */ PyObject *x = (PyObject *)(cd->c_data + 42); Py_INCREF(Py_None); cd->c_data = ((char *)Py_None) - 42; Py_DECREF(x); } +#if 0 else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) { /* a callback */ ffi_closure *closure = (ffi_closure *)cd->c_data; PyObject *args = (PyObject *)(closure->user_data); closure->user_data = NULL; Py_XDECREF(args); } +#endif return 0; -#endif } //1599 @@ -1644,7 +1639,7 @@ (reprfunc)cdataowning_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ - 0,//&CDataOwn_as_mapping, /* tp_as_mapping */ + 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -684,19 +684,64 @@ return res; } +static PyObject *ffi_new_handle(ZefFFIObject *self, PyObject *arg) +{ + CTypeDescrObject *ct = ZefNULL->c_type; // + CDataObject *cd; + + cd = (CDataObject *)PyObject_GC_New(CDataObject, &CDataOwningGC_Type); + if (cd == NULL) + return NULL; + Py_INCREF(ct); + cd->c_type = ct; + Py_INCREF(arg); + cd->c_data = ((char *)arg) - 42; + cd->c_weakreflist = NULL; + PyObject_GC_Track(cd); + return (PyObject *)cd; +} + +static PyObject *ffi_from_handle(PyObject *self, PyObject *arg) +{ + CTypeDescrObject *ct; + char *raw; + PyObject *x; + if (!CData_Check(arg)) { + PyErr_SetString(PyExc_TypeError, "expected a 'cdata' object"); + return NULL; + } + ct = ((CDataObject *)arg)->c_type; + raw = ((CDataObject *)arg)->c_data; + if (!(ct->ct_flags & CT_CAST_ANYTHING)) { + PyErr_Format(PyExc_TypeError, + "expected a 'cdata' object with a 'void *' out of " + "new_handle(), got '%s'", ct->ct_name); + return NULL; + } + if (!raw) { + PyErr_SetString(PyExc_RuntimeError, + "cannot use from_handle() on NULL pointer"); + return NULL; + } + x = (PyObject *)(raw + 42); + Py_INCREF(x); + return x; +} + 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}, - {"getctype", (PyCFunction)ffi_getctype, METH_VARARGS}, - {"load_library", (PyCFunction)ffi_load_library, - METH_VARARGS | METH_KEYWORDS}, - {"offsetof", (PyCFunction)ffi_offsetof, METH_VARARGS}, - {"new", (PyCFunction)ffi_new, METH_VARARGS}, - {"sizeof", (PyCFunction)ffi_sizeof, METH_O}, - {"string", (PyCFunction)ffi_string, METH_VARARGS}, - {"typeof", (PyCFunction)ffi_typeof, METH_O}, + {"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}, + {"getctype", (PyCFunction)ffi_getctype, METH_VARARGS}, + {"load_library", (PyCFunction)ffi_load_library,METH_VARARGS|METH_KEYWORDS}, + {"offsetof", (PyCFunction)ffi_offsetof, METH_VARARGS}, + {"new", (PyCFunction)ffi_new, METH_VARARGS}, + {"new_handle", (PyCFunction)ffi_new_handle,METH_O}, + {"sizeof", (PyCFunction)ffi_sizeof, METH_O}, + {"string", (PyCFunction)ffi_string, METH_VARARGS}, + {"typeof", (PyCFunction)ffi_typeof, METH_O}, {NULL} }; diff --git a/zeffir/test/test_basic.py b/zeffir/test/test_basic.py --- a/zeffir/test/test_basic.py +++ b/zeffir/test/test_basic.py @@ -72,3 +72,12 @@ assert ffi.getctype("int[5]", '*') == "int(*)[5]" assert ffi.getctype("int[5]", '*foo') == "int(*foo)[5]" assert ffi.getctype("int[5]", ' ** foo ') == "int(** foo)[5]" + +def test_from_handle(): + ffi = support.new_ffi() + x = [5, 6] + x.append(7) + p = ffi.new_handle(x) + assert ffi.from_handle(p) is x + del x + assert ffi.from_handle(p) == [5, 6, 7] diff --git a/zeffir/zeffir.c b/zeffir/zeffir.c --- a/zeffir/zeffir.c +++ b/zeffir/zeffir.c @@ -73,16 +73,17 @@ { CTypeDescrObject *ctvoidp; - PyObject *cdnull; PyObject *d1 = PyDict_New(); if (d1 == NULL) return; ctvoidp = parse_c_decl(d1, "void*"); if (ctvoidp) { - cdnull = new_simple_cdata(NULL, ctvoidp); - if (cdnull) - PyDict_SetItemString(ZefFFI_Type.tp_dict, "NULL", cdnull); + ZefNULL = (CDataObject *)new_simple_cdata(NULL, ctvoidp); + if (ZefNULL) { + PyDict_SetItemString(ZefFFI_Type.tp_dict, "NULL", + (PyObject *)ZefNULL); + } } Py_DECREF(d1); if (PyErr_Occurred()) diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h --- a/zeffir/zeffir.h +++ b/zeffir/zeffir.h @@ -1,5 +1,6 @@ typedef struct _crx_type_s CTypeDescrObject; +typedef struct cdataobject_s CDataObject; typedef struct cfieldobject_s CFieldObject; typedef struct ZefLibObject_s ZefLibObject; typedef struct ZefFFIObject_s ZefFFIObject; @@ -12,6 +13,7 @@ static PyTypeObject CDataOwningGC_Type; static PyObject *ZefError; +static CDataObject *ZefNULL; static int lib_close(ZefLibObject *); static int load_creflect_main(ZefFFIObject *, ZefLibObject *); From noreply at buildbot.pypy.org Fri Dec 5 22:15:43 2014 From: noreply at buildbot.pypy.org (amauryfa) Date: Fri, 5 Dec 2014 22:15:43 +0100 (CET) Subject: [pypy-commit] pypy more-rposix: Fix various tests Message-ID: <20141205211543.4B11F1D29F4@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: more-rposix Changeset: r74841:76feb483c6b4 Date: 2014-11-11 21:00 +0100 http://bitbucket.org/pypy/pypy/changeset/76feb483c6b4/ Log: Fix various tests diff --git a/rpython/flowspace/test/test_objspace.py b/rpython/flowspace/test/test_objspace.py --- a/rpython/flowspace/test/test_objspace.py +++ b/rpython/flowspace/test/test_objspace.py @@ -10,6 +10,7 @@ from rpython.flowspace.flowcontext import FlowingError, FlowContext from rpython.conftest import option from rpython.tool.stdlib_opcode import host_bytecode_spec +from rpython.rlib import rposix import os import operator @@ -1261,9 +1262,9 @@ self.show(x) ops = x.startblock.operations assert ops[0].opname == 'simple_call' - assert ops[0].args[0].value is os.unlink + assert ops[0].args[0].value is rposix.unlink assert ops[1].opname == 'simple_call' - assert ops[1].args[0].value is os.unlink + assert ops[1].args[0].value is rposix.unlink def test_rabspath(self): import os.path diff --git a/rpython/rtyper/module/test/test_posix.py b/rpython/rtyper/module/test/test_posix.py --- a/rpython/rtyper/module/test/test_posix.py +++ b/rpython/rtyper/module/test/test_posix.py @@ -211,7 +211,9 @@ def test_os_wstar(self): from rpython.rtyper.module.ll_os import RegisterOs - for name in RegisterOs.w_star: + for name in ['WCOREDUMP', 'WIFCONTINUED', 'WIFSTOPPED', + 'WIFSIGNALED', 'WIFEXITED', + 'WEXITSTATUS', 'WSTOPSIG', 'WTERMSIG']: if not hasattr(os, name): continue def fun(s): diff --git a/rpython/rtyper/test/test_rbuiltin.py b/rpython/rtyper/test/test_rbuiltin.py --- a/rpython/rtyper/test/test_rbuiltin.py +++ b/rpython/rtyper/test/test_rbuiltin.py @@ -284,7 +284,7 @@ count = 0 for dir_call in enum_direct_calls(test_llinterp.typer.annotator.translator, wr_open): cfptr = dir_call.args[0] - assert self.get_callable(cfptr.value).__name__.startswith('os_open') + assert self.get_callable(cfptr.value).__name__ == 'open' count += 1 assert count == 1 From noreply at buildbot.pypy.org Fri Dec 5 22:15:44 2014 From: noreply at buildbot.pypy.org (amauryfa) Date: Fri, 5 Dec 2014 22:15:44 +0100 (CET) Subject: [pypy-commit] pypy more-rposix: Give a better name to the list of os.WEXITSTATUS macros Message-ID: <20141205211544.AA9091D29F4@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: more-rposix Changeset: r74842:0edb78d84f6a Date: 2014-11-11 21:16 +0100 http://bitbucket.org/pypy/pypy/changeset/0edb78d84f6a/ Log: Give a better name to the list of os.WEXITSTATUS macros diff --git a/pypy/module/posix/__init__.py b/pypy/module/posix/__init__.py --- a/pypy/module/posix/__init__.py +++ b/pypy/module/posix/__init__.py @@ -1,4 +1,5 @@ from pypy.interpreter.mixedmodule import MixedModule +from rpython.rlib import rposix import os exec 'import %s as posix' % os.name @@ -171,9 +172,7 @@ if hasattr(os, 'chroot'): interpleveldefs['chroot'] = 'interp_posix.chroot' - for name in ['WCOREDUMP', 'WIFCONTINUED', 'WIFSTOPPED', - 'WIFSIGNALED', 'WIFEXITED', - 'WEXITSTATUS', 'WSTOPSIG', 'WTERMSIG']: + for name in rposix.WAIT_MACROS: if hasattr(os, name): interpleveldefs[name] = 'interp_posix.' + name diff --git a/pypy/module/posix/interp_posix.py b/pypy/module/posix/interp_posix.py --- a/pypy/module/posix/interp_posix.py +++ b/pypy/module/posix/interp_posix.py @@ -1214,9 +1214,7 @@ WSTAR.func_name = name return WSTAR -for name in ['WCOREDUMP', 'WIFCONTINUED', 'WIFSTOPPED', - 'WIFSIGNALED', 'WIFEXITED', - 'WEXITSTATUS', 'WSTOPSIG', 'WTERMSIG']: +for name in rposix.WAIT_MACROS: if hasattr(os, name): func = declare_new_w_star(name) globals()[name] = func diff --git a/pypy/module/posix/test/test_posix2.py b/pypy/module/posix/test/test_posix2.py --- a/pypy/module/posix/test/test_posix2.py +++ b/pypy/module/posix/test/test_posix2.py @@ -7,6 +7,7 @@ from pypy.tool.pytest.objspace import gettestobjspace from pypy.conftest import pypydir from rpython.translator.c.test.test_extfunc import need_sparse_files +from rpython.rlib import rposix import os import py import sys @@ -575,9 +576,7 @@ raises(TypeError, "os.utime('xxx', 3)") raises(OSError, "os.utime('somefilewhichihopewouldneverappearhere', None)") - for name in ['WCOREDUMP', 'WIFCONTINUED', 'WIFSTOPPED', - 'WIFSIGNALED', 'WIFEXITED', - 'WEXITSTATUS', 'WSTOPSIG', 'WTERMSIG']: + for name in rposix.WAIT_MACROS: if hasattr(os, name): values = [0, 1, 127, 128, 255] code = py.code.Source(""" diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py --- a/rpython/rlib/rposix.py +++ b/rpython/rlib/rposix.py @@ -765,9 +765,10 @@ else: return bool(c_func(status)) -for name in ['WCOREDUMP', 'WIFCONTINUED', 'WIFSTOPPED', - 'WIFSIGNALED', 'WIFEXITED', - 'WEXITSTATUS', 'WSTOPSIG', 'WTERMSIG']: +WAIT_MACROS = ['WCOREDUMP', 'WIFCONTINUED', 'WIFSTOPPED', + 'WIFSIGNALED', 'WIFEXITED', + 'WEXITSTATUS', 'WSTOPSIG', 'WTERMSIG'] +for name in WAIT_MACROS: _make_waitmacro(name) #___________________________________________________________________ diff --git a/rpython/rtyper/module/test/test_posix.py b/rpython/rtyper/module/test/test_posix.py --- a/rpython/rtyper/module/test/test_posix.py +++ b/rpython/rtyper/module/test/test_posix.py @@ -210,10 +210,8 @@ assert self.interpret(f, []) == 1 def test_os_wstar(self): - from rpython.rtyper.module.ll_os import RegisterOs - for name in ['WCOREDUMP', 'WIFCONTINUED', 'WIFSTOPPED', - 'WIFSIGNALED', 'WIFEXITED', - 'WEXITSTATUS', 'WSTOPSIG', 'WTERMSIG']: + from rpython.rlib import rposix + for name in rposix.WAIT_MACROS: if not hasattr(os, name): continue def fun(s): From noreply at buildbot.pypy.org Fri Dec 5 22:15:45 2014 From: noreply at buildbot.pypy.org (amauryfa) Date: Fri, 5 Dec 2014 22:15:45 +0100 (CET) Subject: [pypy-commit] pypy more-rposix: Found a much better way to register a replacement function. Message-ID: <20141205211545.D64CD1D29F4@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: more-rposix Changeset: r74843:9af5b8184a71 Date: 2014-12-05 19:52 +0100 http://bitbucket.org/pypy/pypy/changeset/9af5b8184a71/ Log: Found a much better way to register a replacement function. diff --git a/rpython/flowspace/operation.py b/rpython/flowspace/operation.py --- a/rpython/flowspace/operation.py +++ b/rpython/flowspace/operation.py @@ -12,10 +12,11 @@ from rpython.tool.sourcetools import compile2 from rpython.flowspace.model import (Constant, WrapException, const, Variable, SpaceOperation) -from rpython.flowspace.specialcase import register_flow_sc, get_specialcase +from rpython.flowspace.specialcase import register_flow_sc from rpython.annotator.model import ( SomeTuple, AnnotatorError, read_can_only_throw) from rpython.annotator.argument import ArgumentsForTranslation +from rpython.flowspace.specialcase import SPECIAL_CASES NOT_REALLY_CONST = { @@ -569,8 +570,11 @@ w_callable, args_w = self.args[0], self.args[1:] if isinstance(w_callable, Constant): fn = w_callable.value - sc = get_specialcase(fn) - if sc: + try: + sc = SPECIAL_CASES[fn] # TypeError if 'fn' not hashable + except (KeyError, TypeError): + pass + else: return sc(ctx, *args_w) return ctx.do_op(self) @@ -585,8 +589,11 @@ w_callable = self.args[0] if isinstance(w_callable, Constant): fn = w_callable.value - sc = get_specialcase(fn) - if sc: + try: + sc = SPECIAL_CASES[fn] # TypeError if 'fn' not hashable + except (KeyError, TypeError): + pass + else: from rpython.flowspace.flowcontext import FlowingError raise FlowingError( "should not call %r with keyword arguments" % (fn,)) diff --git a/rpython/flowspace/specialcase.py b/rpython/flowspace/specialcase.py --- a/rpython/flowspace/specialcase.py +++ b/rpython/flowspace/specialcase.py @@ -54,26 +54,6 @@ from rpython.flowspace.operation import op return op.getattr(w_obj, w_index).eval(ctx) -def get_specialcase(fn): - try: - return SPECIAL_CASES[fn] # TypeError if 'fn' not hashable - except (KeyError, TypeError): - # Try to import modules containing special cases - for modname in SPECIAL_MODULES.get(getattr(fn, '__module__', None), []): - __import__(modname) - try: - return SPECIAL_CASES[fn] - except (KeyError, TypeError): - pass - return None - -SPECIAL_MODULES = { - # Modules with functions registered with @register_flow_sc, and - # which cannot be imported when before the flow object space - # (because of import loops). - 'posix': ['rpython.rlib.rposix'], -} - # _________________________________________________________________________ redirect_function(open, 'rpython.rlib.rfile.create_file') diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py --- a/rpython/rlib/objectmodel.py +++ b/rpython/rlib/objectmodel.py @@ -290,15 +290,14 @@ def sc_we_are_translated(ctx): return Constant(True) +def register_replacement_for(replaced_function, sandboxed_name=None): + def wrap(func): + from rpython.rtyper.extregistry import ExtRegistryEntry + class ExtRegistry(ExtRegistryEntry): + _about_ = replaced_function + def compute_annotation(self): + return self.bookkeeper.immutablevalue(func) -def register_replacement_for(replaced_function, sandboxed_name=None): - """Decorator that causes RPython to replace the function passed as parameter - with the function being defined.""" - def wrap(func): - if replaced_function is not None: - @register_flow_sc(replaced_function) - def sc_redirected_function(ctx, *args_w): - return ctx.appcall(func, *args_w) if sandboxed_name: func._sandbox_external_name = sandboxed_name # XXX THIS IS NOT CORRECT. Only do this when config.sandbox. @@ -306,7 +305,6 @@ return func return wrap - def keepalive_until_here(*values): pass From noreply at buildbot.pypy.org Fri Dec 5 22:15:52 2014 From: noreply at buildbot.pypy.org (amauryfa) Date: Fri, 5 Dec 2014 22:15:52 +0100 (CET) Subject: [pypy-commit] pypy more-rposix: hg merge default Message-ID: <20141205211552.4C1E01D29F4@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: more-rposix Changeset: r74844:511d0dd384da Date: 2014-12-05 22:06 +0100 http://bitbucket.org/pypy/pypy/changeset/511d0dd384da/ Log: hg merge default diff too long, truncating to 2000 out of 20185 lines diff --git a/lib-python/2.7/subprocess.py b/lib-python/2.7/subprocess.py --- a/lib-python/2.7/subprocess.py +++ b/lib-python/2.7/subprocess.py @@ -655,6 +655,21 @@ """Create new Popen instance.""" _cleanup() + # --- PyPy hack, see _pypy_install_libs_after_virtualenv() --- + # match arguments passed by different versions of virtualenv + if args[1:] in ( + ['-c', 'import sys; print(sys.prefix)'], # 1.6 10ba3f3c + ['-c', "\nimport sys\nprefix = sys.prefix\n" # 1.7 0e9342ce + "if sys.version_info[0] == 3:\n" + " prefix = prefix.encode('utf8')\n" + "if hasattr(sys.stdout, 'detach'):\n" + " sys.stdout = sys.stdout.detach()\n" + "elif hasattr(sys.stdout, 'buffer'):\n" + " sys.stdout = sys.stdout.buffer\nsys.stdout.write(prefix)\n"], + ['-c', 'import sys;out=sys.stdout;getattr(out, "buffer"' + ', out).write(sys.prefix.encode("utf-8"))']): # 1.7.2 a9454bce + _pypy_install_libs_after_virtualenv(args[0]) + if not isinstance(bufsize, (int, long)): raise TypeError("bufsize must be an integer") @@ -1560,6 +1575,27 @@ self.send_signal(signal.SIGKILL) +def _pypy_install_libs_after_virtualenv(target_executable): + # https://bitbucket.org/pypy/pypy/issue/1922/future-proofing-virtualenv + # + # PyPy 2.4.1 turned --shared on by default. This means the pypy binary + # depends on the 'libpypy-c.so' shared library to be able to run. + # The virtualenv code existing at the time did not account for this + # and would break. Try to detect that we're running under such a + # virtualenv in the "Testing executable with" phase and copy the + # library ourselves. + caller = sys._getframe(2) + if ('virtualenv_version' in caller.f_globals and + 'copyfile' in caller.f_globals): + dest_dir = sys.pypy_resolvedirof(target_executable) + src_dir = sys.pypy_resolvedirof(sys.executable) + for libname in ['libpypy-c.so']: + dest_library = os.path.join(dest_dir, libname) + src_library = os.path.join(src_dir, libname) + if os.path.exists(src_library): + caller.f_globals['copyfile'](src_library, dest_library) + + def _demo_posix(): # # Example 1: Simple redirection: Get process list diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -59,7 +59,7 @@ def __init__(self, basename, core=False, compiler=None, usemodules='', skip=None): self.basename = basename - self._usemodules = usemodules.split() + ['signal', 'rctime', 'itertools', '_socket'] + self._usemodules = usemodules.split() + ['signal', 'time', 'itertools', '_socket'] self._compiler = compiler self.core = core self.skip = skip diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -29,7 +29,7 @@ # --allworkingmodules working_modules = default_modules.copy() working_modules.update([ - "_socket", "unicodedata", "mmap", "fcntl", "_locale", "pwd", "rctime" , + "_socket", "unicodedata", "mmap", "fcntl", "_locale", "pwd", "time" , "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", @@ -40,7 +40,7 @@ translation_modules = default_modules.copy() translation_modules.update([ - "fcntl", "rctime", "select", "signal", "_rawffi", "zlib", "struct", "_md5", + "fcntl", "time", "select", "signal", "_rawffi", "zlib", "struct", "_md5", "cStringIO", "array", "binascii", # the following are needed for pyrepl (and hence for the # interactive prompt/pdb) @@ -64,19 +64,15 @@ default_modules.add("_locale") if sys.platform == "sunos5": - working_modules.remove('mmap') # depend on ctypes, can't get at c-level 'errono' - working_modules.remove('rctime') # depend on ctypes, missing tm_zone/tm_gmtoff - working_modules.remove('signal') # depend on ctypes, can't get at c-level 'errono' working_modules.remove('fcntl') # LOCK_NB not defined working_modules.remove("_minimal_curses") working_modules.remove("termios") - working_modules.remove("_multiprocessing") # depends on rctime if "cppyy" in working_modules: working_modules.remove("cppyy") # depends on ctypes module_dependencies = { - '_multiprocessing': [('objspace.usemodules.rctime', True), + '_multiprocessing': [('objspace.usemodules.time', True), ('objspace.usemodules.thread', True)], 'cpyext': [('objspace.usemodules.array', True)], 'cppyy': [('objspace.usemodules.cpyext', True)], @@ -86,9 +82,10 @@ # itself needs the interp-level struct module # because 'P' is missing from the app-level one "_rawffi": [("objspace.usemodules.struct", True)], - "cpyext": [("translation.secondaryentrypoints", "cpyext,main"), - ("translation.shared", sys.platform == "win32")], + "cpyext": [("translation.secondaryentrypoints", "cpyext,main")], } +if sys.platform == "win32": + module_suggests["cpyext"].append(("translation.shared", True)) module_import_dependencies = { # no _rawffi if importing rpython.rlib.clibffi raises ImportError diff --git a/pypy/doc/config/objspace.usemodules.rctime.txt b/pypy/doc/config/objspace.usemodules.rctime.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.usemodules.rctime.txt +++ /dev/null @@ -1,7 +0,0 @@ -Use the 'rctime' module. - -'rctime' is our `rffi`_ based implementation of the builtin 'time' module. -It supersedes the less complete :config:`objspace.usemodules.time`, -at least for C-like targets (the C and LLVM backends). - -.. _`rffi`: ../rffi.html diff --git a/pypy/doc/config/objspace.usemodules.time.txt b/pypy/doc/config/objspace.usemodules.time.txt --- a/pypy/doc/config/objspace.usemodules.time.txt +++ b/pypy/doc/config/objspace.usemodules.time.txt @@ -1,5 +1,1 @@ Use the 'time' module. - -Obsolete; use :config:`objspace.usemodules.rctime` for our up-to-date version -of the application-level 'time' module, at least for C-like targets (the C -and LLVM backends). diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -205,23 +205,28 @@ The above is true both in CPython and in PyPy. Differences can occur about whether a built-in function or method will call an overridden method of *another* object than ``self``. -In PyPy, they are generally always called, whereas not in -CPython. For example, in PyPy, ``dict1.update(dict2)`` -considers that ``dict2`` is just a general mapping object, and -will thus call overridden ``keys()`` and ``__getitem__()`` -methods on it. So the following code prints ``42`` on PyPy -but ``foo`` on CPython:: +In PyPy, they are often called in cases where CPython would not. +Two examples:: - >>>> class D(dict): - .... def __getitem__(self, key): - .... return 42 - .... - >>>> - >>>> d1 = {} - >>>> d2 = D(a='foo') - >>>> d1.update(d2) - >>>> print d1['a'] - 42 + class D(dict): + def __getitem__(self, key): + return "%r from D" % (key,) + + class A(object): + pass + + a = A() + a.__dict__ = D() + a.foo = "a's own foo" + print a.foo + # CPython => a's own foo + # PyPy => 'foo' from D + + glob = D(foo="base item") + loc = {} + exec "print foo" in glob, loc + # CPython => base item + # PyPy => 'foo' from D Mutating classes of objects which are already used as dictionary keys @@ -292,6 +297,9 @@ above types will return a value that is computed from the argument, and can thus be larger than ``sys.maxint`` (i.e. it can be an arbitrary long). +Notably missing from the list above are ``str`` and ``unicode``. If your +code relies on comparing strings with ``is``, then it might break in PyPy. + Miscellaneous ------------- diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -43,3 +43,11 @@ .. branch nditer-external_loop Implement `external_loop` arguement to numpy's nditer + +.. branch kill-rctime + +Rename pypy/module/rctime to pypy/module/time, since it contains the implementation of the 'time' module. + +.. branch: ssa-flow + +Use SSA form for flow graphs inside build_flow() and part of simplify_graph() diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -1,15 +1,13 @@ -""" -Python control flow graph generation and bytecode assembly. -""" +"""Python control flow graph generation and bytecode assembly.""" -from pypy.interpreter.astcompiler import ast, symtable -from pypy.interpreter import pycode +from rpython.rlib import rfloat +from rpython.rlib.objectmodel import we_are_translated + +from pypy.interpreter.astcompiler import ast, misc, symtable +from pypy.interpreter.error import OperationError +from pypy.interpreter.pycode import PyCode from pypy.tool import stdlib_opcode as ops -from pypy.interpreter.error import OperationError -from rpython.rlib.objectmodel import we_are_translated -from rpython.rlib import rfloat - class Instruction(object): """Represents a single opcode.""" @@ -21,14 +19,12 @@ self.has_jump = False def size(self): - """Return the size of bytes of this instruction when it is encoded.""" + """Return the size of bytes of this instruction when it is + encoded. + """ if self.opcode >= ops.HAVE_ARGUMENT: - if self.arg > 0xFFFF: - return 6 - else: - return 3 - else: - return 1 + return (6 if self.arg > 0xFFFF else 3) + return 1 def jump_to(self, target, absolute=False): """Indicate the target this jump instruction. @@ -54,9 +50,9 @@ class Block(object): """A basic control flow block. - It has one entry point and several possible exit points. Its instructions - may be jumps to other blocks, or if control flow reaches the end of the - block, it continues to next_block. + It has one entry point and several possible exit points. Its + instructions may be jumps to other blocks, or if control flow + reaches the end of the block, it continues to next_block. """ def __init__(self): @@ -71,10 +67,10 @@ stack.append(nextblock) def post_order(self): - """Return this block and its children in post order. - This means that the graph of blocks is first cleaned up to - ignore back-edges, thus turning it into a DAG. Then the DAG - is linearized. For example: + """Return this block and its children in post order. This means + that the graph of blocks is first cleaned up to ignore + back-edges, thus turning it into a DAG. Then the DAG is + linearized. For example: A --> B -\ => [A, D, B, C] \-> D ---> C @@ -105,7 +101,9 @@ return resultblocks def code_size(self): - """Return the encoded size of all the instructions in this block.""" + """Return the encoded size of all the instructions in this + block. + """ i = 0 for instr in self.instructions: i += instr.size() @@ -141,6 +139,7 @@ i += 1 return result + def _list_to_dict(l, offset=0): result = {} index = offset @@ -300,11 +299,11 @@ def _resolve_block_targets(self, blocks): """Compute the arguments of jump instructions.""" last_extended_arg_count = 0 - # The reason for this loop is extended jumps. EXTENDED_ARG extends the - # bytecode size, so it might invalidate the offsets we've already given. - # Thus we have to loop until the number of extended args is stable. Any - # extended jump at all is extremely rare, so performance is not too - # concerning. + # The reason for this loop is extended jumps. EXTENDED_ARG + # extends the bytecode size, so it might invalidate the offsets + # we've already given. Thus we have to loop until the number of + # extended args is stable. Any extended jump at all is + # extremely rare, so performance is not too concerning. while True: extended_arg_count = 0 offset = 0 @@ -330,7 +329,8 @@ instr.opcode = ops.JUMP_ABSOLUTE absolute = True elif target_op == ops.RETURN_VALUE: - # Replace JUMP_* to a RETURN into just a RETURN + # Replace JUMP_* to a RETURN into + # just a RETURN instr.opcode = ops.RETURN_VALUE instr.arg = 0 instr.has_jump = False @@ -345,7 +345,8 @@ instr.arg = jump_arg if jump_arg > 0xFFFF: extended_arg_count += 1 - if extended_arg_count == last_extended_arg_count and not force_redo: + if (extended_arg_count == last_extended_arg_count and + not force_redo): break else: last_extended_arg_count = extended_arg_count @@ -360,12 +361,14 @@ while True: try: w_key = space.next(w_iter) - except OperationError, e: + except OperationError as e: if not e.match(space, space.w_StopIteration): raise break w_index = space.getitem(w_consts, w_key) - consts_w[space.int_w(w_index)] = space.getitem(w_key, first) + w_constant = space.getitem(w_key, first) + w_constant = misc.intern_if_common_string(space, w_constant) + consts_w[space.int_w(w_index)] = w_constant return consts_w def _get_code_flags(self): @@ -433,15 +436,16 @@ continue addr = offset - current_off # Python assumes that lineno always increases with - # increasing bytecode address (lnotab is unsigned char). - # Depending on when SET_LINENO instructions are emitted this - # is not always true. Consider the code: + # increasing bytecode address (lnotab is unsigned + # char). Depending on when SET_LINENO instructions + # are emitted this is not always true. Consider the + # code: # a = (1, # b) - # In the bytecode stream, the assignment to "a" occurs after - # the loading of "b". This works with the C Python compiler - # because it only generates a SET_LINENO instruction for the - # assignment. + # In the bytecode stream, the assignment to "a" + # occurs after the loading of "b". This works with + # the C Python compiler because it only generates a + # SET_LINENO instruction for the assignment. if line or addr: while addr > 255: push(chr(255)) @@ -484,22 +488,22 @@ free_names = _list_from_dict(self.free_vars, len(cell_names)) flags = self._get_code_flags() | self.compile_info.flags bytecode = ''.join([block.get_code() for block in blocks]) - return pycode.PyCode(self.space, - self.argcount, - len(self.var_names), - stack_depth, - flags, - bytecode, - list(consts_w), - names, - var_names, - self.compile_info.filename, - self.name, - self.first_lineno, - lnotab, - free_names, - cell_names, - self.compile_info.hidden_applevel) + return PyCode(self.space, + self.argcount, + len(self.var_names), + stack_depth, + flags, + bytecode, + list(consts_w), + names, + var_names, + self.compile_info.filename, + self.name, + self.first_lineno, + lnotab, + free_names, + cell_names, + self.compile_info.hidden_applevel) def _list_from_dict(d, offset=0): @@ -510,134 +514,134 @@ _static_opcode_stack_effects = { - ops.NOP : 0, - ops.STOP_CODE : 0, + ops.NOP: 0, + ops.STOP_CODE: 0, - ops.POP_TOP : -1, - ops.ROT_TWO : 0, - ops.ROT_THREE : 0, - ops.ROT_FOUR : 0, - ops.DUP_TOP : 1, + ops.POP_TOP: -1, + ops.ROT_TWO: 0, + ops.ROT_THREE: 0, + ops.ROT_FOUR: 0, + ops.DUP_TOP: 1, - ops.UNARY_POSITIVE : 0, - ops.UNARY_NEGATIVE : 0, - ops.UNARY_NOT : 0, - ops.UNARY_CONVERT : 0, - ops.UNARY_INVERT : 0, + ops.UNARY_POSITIVE: 0, + ops.UNARY_NEGATIVE: 0, + ops.UNARY_NOT: 0, + ops.UNARY_CONVERT: 0, + ops.UNARY_INVERT: 0, - ops.LIST_APPEND : -1, - ops.SET_ADD : -1, - ops.MAP_ADD : -2, - ops.STORE_MAP : -2, + ops.LIST_APPEND: -1, + ops.SET_ADD: -1, + ops.MAP_ADD: -2, + ops.STORE_MAP: -2, - ops.BINARY_POWER : -1, - ops.BINARY_MULTIPLY : -1, - ops.BINARY_DIVIDE : -1, - ops.BINARY_MODULO : -1, - ops.BINARY_ADD : -1, - ops.BINARY_SUBTRACT : -1, - ops.BINARY_SUBSCR : -1, - ops.BINARY_FLOOR_DIVIDE : -1, - ops.BINARY_TRUE_DIVIDE : -1, - ops.BINARY_LSHIFT : -1, - ops.BINARY_RSHIFT : -1, - ops.BINARY_AND : -1, - ops.BINARY_OR : -1, - ops.BINARY_XOR : -1, + ops.BINARY_POWER: -1, + ops.BINARY_MULTIPLY: -1, + ops.BINARY_DIVIDE: -1, + ops.BINARY_MODULO: -1, + ops.BINARY_ADD: -1, + ops.BINARY_SUBTRACT: -1, + ops.BINARY_SUBSCR: -1, + ops.BINARY_FLOOR_DIVIDE: -1, + ops.BINARY_TRUE_DIVIDE: -1, + ops.BINARY_LSHIFT: -1, + ops.BINARY_RSHIFT: -1, + ops.BINARY_AND: -1, + ops.BINARY_OR: -1, + ops.BINARY_XOR: -1, - ops.INPLACE_FLOOR_DIVIDE : -1, - ops.INPLACE_TRUE_DIVIDE : -1, - ops.INPLACE_ADD : -1, - ops.INPLACE_SUBTRACT : -1, - ops.INPLACE_MULTIPLY : -1, - ops.INPLACE_DIVIDE : -1, - ops.INPLACE_MODULO : -1, - ops.INPLACE_POWER : -1, - ops.INPLACE_LSHIFT : -1, - ops.INPLACE_RSHIFT : -1, - ops.INPLACE_AND : -1, - ops.INPLACE_OR : -1, - ops.INPLACE_XOR : -1, + ops.INPLACE_FLOOR_DIVIDE: -1, + ops.INPLACE_TRUE_DIVIDE: -1, + ops.INPLACE_ADD: -1, + ops.INPLACE_SUBTRACT: -1, + ops.INPLACE_MULTIPLY: -1, + ops.INPLACE_DIVIDE: -1, + ops.INPLACE_MODULO: -1, + ops.INPLACE_POWER: -1, + ops.INPLACE_LSHIFT: -1, + ops.INPLACE_RSHIFT: -1, + ops.INPLACE_AND: -1, + ops.INPLACE_OR: -1, + ops.INPLACE_XOR: -1, - ops.SLICE+0 : 1, - ops.SLICE+1 : 0, - ops.SLICE+2 : 0, - ops.SLICE+3 : -1, - ops.STORE_SLICE+0 : -2, - ops.STORE_SLICE+1 : -3, - ops.STORE_SLICE+2 : -3, - ops.STORE_SLICE+3 : -4, - ops.DELETE_SLICE+0 : -1, - ops.DELETE_SLICE+1 : -2, - ops.DELETE_SLICE+2 : -2, - ops.DELETE_SLICE+3 : -3, + ops.SLICE+0: 1, + ops.SLICE+1: 0, + ops.SLICE+2: 0, + ops.SLICE+3: -1, + ops.STORE_SLICE+0: -2, + ops.STORE_SLICE+1: -3, + ops.STORE_SLICE+2: -3, + ops.STORE_SLICE+3: -4, + ops.DELETE_SLICE+0: -1, + ops.DELETE_SLICE+1: -2, + ops.DELETE_SLICE+2: -2, + ops.DELETE_SLICE+3: -3, - ops.STORE_SUBSCR : -2, - ops.DELETE_SUBSCR : -2, + ops.STORE_SUBSCR: -2, + ops.DELETE_SUBSCR: -2, - ops.GET_ITER : 0, - ops.FOR_ITER : 1, - ops.BREAK_LOOP : 0, - ops.CONTINUE_LOOP : 0, - ops.SETUP_LOOP : 0, + ops.GET_ITER: 0, + ops.FOR_ITER: 1, + ops.BREAK_LOOP: 0, + ops.CONTINUE_LOOP: 0, + ops.SETUP_LOOP: 0, - ops.PRINT_EXPR : -1, - ops.PRINT_ITEM : -1, - ops.PRINT_NEWLINE : 0, - ops.PRINT_ITEM_TO : -2, - ops.PRINT_NEWLINE_TO : -1, + ops.PRINT_EXPR: -1, + ops.PRINT_ITEM: -1, + ops.PRINT_NEWLINE: 0, + ops.PRINT_ITEM_TO: -2, + ops.PRINT_NEWLINE_TO: -1, - ops.WITH_CLEANUP : -1, - ops.POP_BLOCK : 0, - ops.END_FINALLY : -1, - ops.SETUP_WITH : 1, - ops.SETUP_FINALLY : 0, - ops.SETUP_EXCEPT : 0, + ops.WITH_CLEANUP: -1, + ops.POP_BLOCK: 0, + ops.END_FINALLY: -1, + ops.SETUP_WITH: 1, + ops.SETUP_FINALLY: 0, + ops.SETUP_EXCEPT: 0, - ops.LOAD_LOCALS : 1, - ops.RETURN_VALUE : -1, - ops.EXEC_STMT : -3, - ops.YIELD_VALUE : 0, - ops.BUILD_CLASS : -2, - ops.BUILD_MAP : 1, - ops.BUILD_SET : 1, - ops.COMPARE_OP : -1, + ops.LOAD_LOCALS: 1, + ops.RETURN_VALUE: -1, + ops.EXEC_STMT: -3, + ops.YIELD_VALUE: 0, + ops.BUILD_CLASS: -2, + ops.BUILD_MAP: 1, + ops.BUILD_SET: 1, + ops.COMPARE_OP: -1, - ops.LOOKUP_METHOD : 1, + ops.LOOKUP_METHOD: 1, - ops.LOAD_NAME : 1, - ops.STORE_NAME : -1, - ops.DELETE_NAME : 0, + ops.LOAD_NAME: 1, + ops.STORE_NAME: -1, + ops.DELETE_NAME: 0, - ops.LOAD_FAST : 1, - ops.STORE_FAST : -1, - ops.DELETE_FAST : 0, + ops.LOAD_FAST: 1, + ops.STORE_FAST: -1, + ops.DELETE_FAST: 0, - ops.LOAD_ATTR : 0, - ops.STORE_ATTR : -2, - ops.DELETE_ATTR : -1, + ops.LOAD_ATTR: 0, + ops.STORE_ATTR: -2, + ops.DELETE_ATTR: -1, - ops.LOAD_GLOBAL : 1, - ops.STORE_GLOBAL : -1, - ops.DELETE_GLOBAL : 0, + ops.LOAD_GLOBAL: 1, + ops.STORE_GLOBAL: -1, + ops.DELETE_GLOBAL: 0, - ops.LOAD_CLOSURE : 1, - ops.LOAD_DEREF : 1, - ops.STORE_DEREF : -1, + ops.LOAD_CLOSURE: 1, + ops.LOAD_DEREF: 1, + ops.STORE_DEREF: -1, - ops.LOAD_CONST : 1, + ops.LOAD_CONST: 1, - ops.IMPORT_STAR : -1, - ops.IMPORT_NAME : -1, - ops.IMPORT_FROM : 1, + ops.IMPORT_STAR: -1, + ops.IMPORT_NAME: -1, + ops.IMPORT_FROM: 1, - ops.JUMP_FORWARD : 0, - ops.JUMP_ABSOLUTE : 0, - ops.JUMP_IF_TRUE_OR_POP : 0, - ops.JUMP_IF_FALSE_OR_POP : 0, - ops.POP_JUMP_IF_TRUE : -1, - ops.POP_JUMP_IF_FALSE : -1, - ops.JUMP_IF_NOT_DEBUG : 0, + ops.JUMP_FORWARD: 0, + ops.JUMP_ABSOLUTE: 0, + ops.JUMP_IF_TRUE_OR_POP: 0, + ops.JUMP_IF_FALSE_OR_POP: 0, + ops.POP_JUMP_IF_TRUE: -1, + ops.POP_JUMP_IF_FALSE: -1, + ops.JUMP_IF_NOT_DEBUG: 0, ops.BUILD_LIST_FROM_ARG: 1, } diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -106,3 +106,13 @@ except IndexError: return name return "_%s%s" % (klass[i:], name) + + +def intern_if_common_string(space, w_const): + # only intern identifier-like strings + if not space.is_w(space.type(w_const), space.w_str): + return w_const + for c in space.str_w(w_const): + if not (c.isalnum() or c == '_'): + return w_const + return space.new_interned_w_str(w_const) diff --git a/pypy/interpreter/astcompiler/optimize.py b/pypy/interpreter/astcompiler/optimize.py --- a/pypy/interpreter/astcompiler/optimize.py +++ b/pypy/interpreter/astcompiler/optimize.py @@ -272,6 +272,11 @@ if w_const is None: return tup consts_w[i] = w_const + # intern the string constants packed into the tuple here, + # because assemble.py will see the result as just a tuple constant + for i in range(len(consts_w)): + consts_w[i] = misc.intern_if_common_string( + self.space, consts_w[i]) else: consts_w = [] w_consts = self.space.newtuple(consts_w) diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -14,7 +14,7 @@ UserDelAction) from pypy.interpreter.error import OperationError, new_exception_class, oefmt from pypy.interpreter.argument import Arguments -from pypy.interpreter.miscutils import ThreadLocals +from pypy.interpreter.miscutils import ThreadLocals, make_weak_value_dictionary __all__ = ['ObjSpace', 'OperationError', 'W_Root'] @@ -384,7 +384,7 @@ self.builtin_modules = {} self.reloading_modules = {} - self.interned_strings = {} + self.interned_strings = make_weak_value_dictionary(self, str, W_Root) self.actionflag = ActionFlag() # changed by the signal module self.check_signal_action = None # changed by the signal module self.user_del_action = UserDelAction(self) @@ -522,11 +522,6 @@ if name not in modules: modules.append(name) - # a bit of custom logic: rctime take precedence over time - # XXX this could probably be done as a "requires" in the config - if 'rctime' in modules and 'time' in modules: - modules.remove('time') - self._builtinmodule_list = modules return self._builtinmodule_list @@ -782,25 +777,30 @@ return self.w_False def new_interned_w_str(self, w_s): + assert isinstance(w_s, W_Root) # and is not None s = self.str_w(w_s) if not we_are_translated(): assert type(s) is str - try: - return self.interned_strings[s] - except KeyError: - pass - self.interned_strings[s] = w_s - return w_s + w_s1 = self.interned_strings.get(s) + if w_s1 is None: + w_s1 = w_s + self.interned_strings.set(s, w_s1) + return w_s1 def new_interned_str(self, s): if not we_are_translated(): assert type(s) is str - try: - return self.interned_strings[s] - except KeyError: - pass - w_s = self.interned_strings[s] = self.wrap(s) - return w_s + w_s1 = self.interned_strings.get(s) + if w_s1 is None: + w_s1 = self.wrap(s) + self.interned_strings.set(s, w_s1) + return w_s1 + + def is_interned_str(self, s): + # interface for marshal_impl + if not we_are_translated(): + assert type(s) is str + return self.interned_strings.get(s) is not None def descr_self_interp_w(self, RequiredClass, w_obj): if not isinstance(w_obj, RequiredClass): diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py --- a/pypy/interpreter/miscutils.py +++ b/pypy/interpreter/miscutils.py @@ -31,3 +31,19 @@ def getallvalues(self): return {0: self._value} + + +def make_weak_value_dictionary(space, keytype, valuetype): + "NOT_RPYTHON" + if space.config.translation.rweakref: + from rpython.rlib.rweakref import RWeakValueDictionary + return RWeakValueDictionary(keytype, valuetype) + else: + class FakeWeakValueDict(object): + def __init__(self): + self._dict = {} + def get(self, key): + return self._dict.get(key, None) + def set(self, key, value): + self._dict[key] = value + return FakeWeakValueDict() diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -131,7 +131,6 @@ # class bodies only have CO_NEWLOCALS. # CO_NEWLOCALS: make a locals dict unless optimized is also set # CO_OPTIMIZED: no locals dict needed at all - # NB: this method is overridden in nestedscope.py flags = code.co_flags if not (flags & pycode.CO_OPTIMIZED): if flags & pycode.CO_NEWLOCALS: diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -970,7 +970,12 @@ sys.stdout = out output = s.getvalue() assert "CALL_METHOD" in output - + + def test_interned_strings(self): + source = """x = ('foo_bar42', 5); y = 'foo_bar42'; z = x[0]""" + exec source + assert y is z + class AppTestExceptions: def test_indentation_error(self): diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py --- a/pypy/interpreter/test/test_objspace.py +++ b/pypy/interpreter/test/test_objspace.py @@ -378,3 +378,41 @@ assert space.str_w(space.getattr(space.sys, w_executable)) == 'foobar' space.startup() assert space.str_w(space.getattr(space.sys, w_executable)) == 'foobar' + + def test_interned_strings_are_weak(self): + import weakref, gc, random + space = self.space + assert space.config.translation.rweakref + w1 = space.new_interned_str("abcdef") + w2 = space.new_interned_str("abcdef") + assert w2 is w1 + # + # check that 'w1' goes away if we don't hold a reference to it + rw1 = weakref.ref(w1) + del w1, w2 + i = 10 + while rw1() is not None: + i -= 1 + assert i >= 0 + gc.collect() + # + s = "foobar%r" % random.random() + w0 = space.wrap(s) + w1 = space.new_interned_w_str(w0) + assert w1 is w0 + w2 = space.new_interned_w_str(w0) + assert w2 is w0 + w3 = space.wrap(s) + assert w3 is not w0 + w4 = space.new_interned_w_str(w3) + assert w4 is w0 + # + # check that 'w0' goes away if we don't hold a reference to it + # (even if we hold a reference to 'w3') + rw0 = weakref.ref(w0) + del w0, w1, w2, w4 + i = 10 + while rw0() is not None: + i -= 1 + assert i >= 0 + gc.collect() diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -158,21 +158,14 @@ class W_CTypePrimitiveSigned(W_CTypePrimitive): - _attrs_ = ['value_fits_long', 'vmin', 'vrangemax'] - _immutable_fields_ = ['value_fits_long', 'vmin', 'vrangemax'] + _attrs_ = ['value_fits_long', 'value_smaller_than_long'] + _immutable_fields_ = ['value_fits_long', 'value_smaller_than_long'] is_primitive_integer = True def __init__(self, *args): W_CTypePrimitive.__init__(self, *args) self.value_fits_long = self.size <= rffi.sizeof(lltype.Signed) - if self.size < rffi.sizeof(lltype.Signed): - assert self.value_fits_long - sh = self.size * 8 - self.vmin = r_uint(-1) << (sh - 1) - self.vrangemax = (r_uint(1) << sh) - 1 - else: - self.vmin = r_uint(0) - self.vrangemax = r_uint(-1) + self.value_smaller_than_long = self.size < rffi.sizeof(lltype.Signed) def cast_to_int(self, cdata): return self.convert_to_object(cdata) @@ -192,8 +185,17 @@ def convert_from_object(self, cdata, w_ob): if self.value_fits_long: value = misc.as_long(self.space, w_ob) - if self.size < rffi.sizeof(lltype.Signed): - if r_uint(value) - self.vmin > self.vrangemax: + if self.value_smaller_than_long: + size = self.size + if size == 1: + signextended = misc.signext(value, 1) + elif size == 2: + signextended = misc.signext(value, 2) + elif size == 4: + signextended = misc.signext(value, 4) + else: + raise AssertionError("unsupported size") + if value != signextended: self._overflow(w_ob) misc.write_raw_signed_data(cdata, value, self.size) else: @@ -221,7 +223,7 @@ length = w_cdata.get_array_length() populate_list_from_raw_array(res, buf, length) return res - elif self.value_fits_long: + elif self.value_smaller_than_long: res = [0] * w_cdata.get_array_length() misc.unpack_list_from_raw_array(res, w_cdata._cdata, self.size) return res @@ -235,8 +237,8 @@ cdata = rffi.cast(rffi.LONGP, cdata) copy_list_to_raw_array(int_list, cdata) else: - overflowed = misc.pack_list_to_raw_array_bounds( - int_list, cdata, self.size, self.vmin, self.vrangemax) + overflowed = misc.pack_list_to_raw_array_bounds_signed( + int_list, cdata, self.size) if overflowed != 0: self._overflow(self.space.wrap(overflowed)) return True @@ -314,8 +316,8 @@ def pack_list_of_items(self, cdata, w_ob): int_list = self.space.listview_int(w_ob) if int_list is not None: - overflowed = misc.pack_list_to_raw_array_bounds( - int_list, cdata, self.size, r_uint(0), self.vrangemax) + overflowed = misc.pack_list_to_raw_array_bounds_unsigned( + int_list, cdata, self.size, self.vrangemax) if overflowed != 0: self._overflow(self.space.wrap(overflowed)) return True diff --git a/pypy/module/_cffi_backend/misc.py b/pypy/module/_cffi_backend/misc.py --- a/pypy/module/_cffi_backend/misc.py +++ b/pypy/module/_cffi_backend/misc.py @@ -216,6 +216,19 @@ neg_msg = "can't convert negative number to unsigned" ovf_msg = "long too big to convert" + at specialize.arg(1) +def signext(value, size): + # 'value' is sign-extended from 'size' bytes to a full integer. + # 'size' should be a constant smaller than a full integer size. + if size == rffi.sizeof(rffi.SIGNEDCHAR): + return rffi.cast(lltype.Signed, rffi.cast(rffi.SIGNEDCHAR, value)) + elif size == rffi.sizeof(rffi.SHORT): + return rffi.cast(lltype.Signed, rffi.cast(rffi.SHORT, value)) + elif size == rffi.sizeof(rffi.INT): + return rffi.cast(lltype.Signed, rffi.cast(rffi.INT, value)) + else: + raise AssertionError("unsupported size") + # ____________________________________________________________ class _NotStandardObject(Exception): @@ -334,13 +347,26 @@ # ____________________________________________________________ -def pack_list_to_raw_array_bounds(int_list, target, size, vmin, vrangemax): +def pack_list_to_raw_array_bounds_signed(int_list, target, size): for TP, TPP in _prim_signed_types: if size == rffi.sizeof(TP): ptr = rffi.cast(TPP, target) for i in range(len(int_list)): x = int_list[i] - if r_uint(x) - vmin > vrangemax: + y = rffi.cast(TP, x) + if x != rffi.cast(lltype.Signed, y): + return x # overflow + ptr[i] = y + return 0 + raise NotImplementedError("bad integer size") + +def pack_list_to_raw_array_bounds_unsigned(int_list, target, size, vrangemax): + for TP, TPP in _prim_signed_types: + if size == rffi.sizeof(TP): + ptr = rffi.cast(TPP, target) + for i in range(len(int_list)): + x = int_list[i] + if r_uint(x) > vrangemax: return x # overflow ptr[i] = rffi.cast(TP, x) return 0 diff --git a/pypy/module/_file/test/test_file.py b/pypy/module/_file/test/test_file.py --- a/pypy/module/_file/test/test_file.py +++ b/pypy/module/_file/test/test_file.py @@ -304,7 +304,7 @@ py.test.skip("works with internals of _file impl on py.py") state = [0] def read(fd, n=None): - if fd != 42: + if fd != 424242: return cls.old_read(fd, n) if state[0] == 0: state[0] += 1 @@ -315,7 +315,7 @@ return '' os.read = read stdin = W_File(cls.space) - stdin.file_fdopen(42, 'rb', 1) + stdin.file_fdopen(424242, 'rb', 1) stdin.name = '' cls.w_stream = stdin diff --git a/pypy/module/_file/test/test_file_extra.py b/pypy/module/_file/test/test_file_extra.py --- a/pypy/module/_file/test/test_file_extra.py +++ b/pypy/module/_file/test/test_file_extra.py @@ -221,7 +221,7 @@ expected_filename = str(udir.join('sample')) expected_mode = 'rb' extra_args = () - spaceconfig = {'usemodules': ['binascii', 'rctime', 'struct']} + spaceconfig = {'usemodules': ['binascii', 'time', 'struct']} def setup_method(self, method): space = self.space @@ -281,7 +281,7 @@ expected_filename = '' expected_mode = 'rb' extra_args = () - spaceconfig = {'usemodules': ['binascii', 'rctime', 'struct']} + spaceconfig = {'usemodules': ['binascii', 'time', 'struct']} def setup_method(self, method): space = self.space @@ -359,7 +359,7 @@ # A few extra tests class AppTestAFewExtra: - spaceconfig = {'usemodules': ['_socket', 'array', 'binascii', 'rctime', + spaceconfig = {'usemodules': ['_socket', 'array', 'binascii', 'time', 'struct']} def setup_method(self, method): diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -1,6 +1,6 @@ class AppTestCProfile(object): spaceconfig = { - "usemodules": ['_lsprof', 'rctime'], + "usemodules": ['_lsprof', 'time'], } def setup_class(cls): diff --git a/pypy/module/_md5/test/test_md5.py b/pypy/module/_md5/test/test_md5.py --- a/pypy/module/_md5/test/test_md5.py +++ b/pypy/module/_md5/test/test_md5.py @@ -5,7 +5,7 @@ class AppTestMD5(object): spaceconfig = { - 'usemodules': ['_md5', 'binascii', 'rctime', 'struct'], + 'usemodules': ['_md5', 'binascii', 'time', 'struct'], } def setup_class(cls): diff --git a/pypy/module/_multibytecodec/src/cjkcodecs/multibytecodec.h b/pypy/module/_multibytecodec/src/cjkcodecs/multibytecodec.h --- a/pypy/module/_multibytecodec/src/cjkcodecs/multibytecodec.h +++ b/pypy/module/_multibytecodec/src/cjkcodecs/multibytecodec.h @@ -97,24 +97,24 @@ Py_UNICODE *outbuf_start, *outbuf, *outbuf_end; }; -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN struct pypy_cjk_dec_s *pypy_cjk_dec_new(const MultibyteCodec *codec); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_dec_init(struct pypy_cjk_dec_s *d, char *inbuf, Py_ssize_t inlen); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN void pypy_cjk_dec_free(struct pypy_cjk_dec_s *); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_dec_chunk(struct pypy_cjk_dec_s *); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_UNICODE *pypy_cjk_dec_outbuf(struct pypy_cjk_dec_s *); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_dec_outlen(struct pypy_cjk_dec_s *); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_dec_inbuf_remaining(struct pypy_cjk_dec_s *d); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_dec_inbuf_consumed(struct pypy_cjk_dec_s* d); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_dec_replace_on_error(struct pypy_cjk_dec_s* d, Py_UNICODE *, Py_ssize_t, Py_ssize_t); @@ -125,35 +125,35 @@ unsigned char *outbuf_start, *outbuf, *outbuf_end; }; -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN struct pypy_cjk_enc_s *pypy_cjk_enc_new(const MultibyteCodec *codec); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_enc_init(struct pypy_cjk_enc_s *d, Py_UNICODE *inbuf, Py_ssize_t inlen); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN void pypy_cjk_enc_free(struct pypy_cjk_enc_s *); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_enc_chunk(struct pypy_cjk_enc_s *, Py_ssize_t); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_enc_reset(struct pypy_cjk_enc_s *); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN char *pypy_cjk_enc_outbuf(struct pypy_cjk_enc_s *); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_enc_outlen(struct pypy_cjk_enc_s *); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_enc_inbuf_remaining(struct pypy_cjk_enc_s *d); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_enc_inbuf_consumed(struct pypy_cjk_enc_s* d); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN Py_ssize_t pypy_cjk_enc_replace_on_error(struct pypy_cjk_enc_s* d, char *, Py_ssize_t, Py_ssize_t); -RPY_EXPORTED_FOR_TESTS +RPY_EXTERN const MultibyteCodec *pypy_cjk_enc_getcodec(struct pypy_cjk_enc_s *); /* list of codecs defined in the .c files */ #define DEFINE_CODEC(name) \ - RPY_EXPORTED_FOR_TESTS MultibyteCodec *pypy_cjkcodec_##name(void); + RPY_EXTERN MultibyteCodec *pypy_cjkcodec_##name(void); // _codecs_cn DEFINE_CODEC(gb2312) diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -254,7 +254,7 @@ start = _GetTickCount() while True: - from pypy.module.rctime.interp_time import State + from pypy.module.time.interp_time import State interrupt_event = space.fromcache(State).get_interrupt_event() handles = [self.handle, interrupt_event] diff --git a/pypy/module/_random/test/test_random.py b/pypy/module/_random/test/test_random.py --- a/pypy/module/_random/test/test_random.py +++ b/pypy/module/_random/test/test_random.py @@ -1,6 +1,6 @@ class AppTestRandom: spaceconfig = { - "usemodules": ['_random', 'rctime'], + "usemodules": ['_random', 'time'], } def test_dict(self): diff --git a/pypy/module/_sha/test/test_sha.py b/pypy/module/_sha/test/test_sha.py --- a/pypy/module/_sha/test/test_sha.py +++ b/pypy/module/_sha/test/test_sha.py @@ -5,7 +5,7 @@ class AppTestSHA(object): spaceconfig = { - 'usemodules': ['_sha', 'binascii', 'rctime', 'struct'], + 'usemodules': ['_sha', 'binascii', 'time', 'struct'], } def setup_class(cls): diff --git a/pypy/module/_ssl/thread_lock.py b/pypy/module/_ssl/thread_lock.py --- a/pypy/module/_ssl/thread_lock.py +++ b/pypy/module/_ssl/thread_lock.py @@ -24,12 +24,19 @@ separate_module_source = """ #include +#ifndef _WIN32 +# include +#endif static unsigned int _ssl_locks_count = 0; static struct RPyOpaque_ThreadLock *_ssl_locks; static unsigned long _ssl_thread_id_function(void) { - return RPyThreadGetIdent(); +#ifdef _WIN32 + return (unsigned long)GetCurrentThreadId(); +#else + return (unsigned long)pthread_self(); +#endif } static void _ssl_thread_locking_function(int mode, int n, const char *file, @@ -65,7 +72,7 @@ eci = rthread.eci.merge(ExternalCompilationInfo( separate_module_sources=[separate_module_source], post_include_bits=[ - "RPY_EXPORTED_FOR_TESTS int _PyPy_SSL_SetupThreads(void);"], + "RPY_EXTERN int _PyPy_SSL_SetupThreads(void);"], libraries = libraries, )) diff --git a/pypy/module/bz2/test/test_bz2_file.py b/pypy/module/bz2/test/test_bz2_file.py --- a/pypy/module/bz2/test/test_bz2_file.py +++ b/pypy/module/bz2/test/test_bz2_file.py @@ -53,7 +53,7 @@ class AppTestBZ2File(CheckAllocation): spaceconfig = { - 'usemodules': ['bz2', 'binascii', 'rctime', 'struct'] + 'usemodules': ['bz2', 'binascii', 'time', 'struct'] } def setup_class(cls): diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h --- a/pypy/module/cppyy/include/capi.h +++ b/pypy/module/cppyy/include/capi.h @@ -2,6 +2,7 @@ #define CPPYY_CAPI #include +#include "src/precommondefs.h" #ifdef __cplusplus extern "C" { @@ -15,102 +16,167 @@ typedef void* (*cppyy_methptrgetter_t)(cppyy_object_t); /* name to opaque C++ scope representation -------------------------------- */ + RPY_EXTERN int cppyy_num_scopes(cppyy_scope_t parent); + RPY_EXTERN char* cppyy_scope_name(cppyy_scope_t parent, int iscope); + RPY_EXTERN char* cppyy_resolve_name(const char* cppitem_name); + RPY_EXTERN cppyy_scope_t cppyy_get_scope(const char* scope_name); + RPY_EXTERN cppyy_type_t cppyy_get_template(const char* template_name); + RPY_EXTERN cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj); /* memory management ------------------------------------------------------ */ + RPY_EXTERN cppyy_object_t cppyy_allocate(cppyy_type_t type); + RPY_EXTERN void cppyy_deallocate(cppyy_type_t type, cppyy_object_t self); + RPY_EXTERN void cppyy_destruct(cppyy_type_t type, cppyy_object_t self); /* method/function dispatching -------------------------------------------- */ + RPY_EXTERN void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t klass, int nargs, void* args); + RPY_EXTERN cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, cppyy_type_t result_type); + RPY_EXTERN cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_scope_t scope, cppyy_index_t idx); /* handling of function argument buffer ----------------------------------- */ + RPY_EXTERN void* cppyy_allocate_function_args(int nargs); + RPY_EXTERN void cppyy_deallocate_function_args(void* args); + RPY_EXTERN size_t cppyy_function_arg_sizeof(); + RPY_EXTERN size_t cppyy_function_arg_typeoffset(); /* scope reflection information ------------------------------------------- */ + RPY_EXTERN int cppyy_is_namespace(cppyy_scope_t scope); + RPY_EXTERN int cppyy_is_enum(const char* type_name); /* class reflection information ------------------------------------------- */ + RPY_EXTERN char* cppyy_final_name(cppyy_type_t type); + RPY_EXTERN char* cppyy_scoped_final_name(cppyy_type_t type); + RPY_EXTERN int cppyy_has_complex_hierarchy(cppyy_type_t type); + RPY_EXTERN int cppyy_num_bases(cppyy_type_t type); + RPY_EXTERN char* cppyy_base_name(cppyy_type_t type, int base_index); + RPY_EXTERN int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base); /* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */ + RPY_EXTERN ptrdiff_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction); /* method/function reflection information --------------------------------- */ + RPY_EXTERN int cppyy_num_methods(cppyy_scope_t scope); + RPY_EXTERN cppyy_index_t cppyy_method_index_at(cppyy_scope_t scope, int imeth); + RPY_EXTERN cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const char* name); + RPY_EXTERN char* cppyy_method_name(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN char* cppyy_method_result_type(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN int cppyy_method_num_args(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN int cppyy_method_req_args(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN char* cppyy_method_arg_type(cppyy_scope_t scope, cppyy_index_t idx, int arg_index); + RPY_EXTERN char* cppyy_method_arg_default(cppyy_scope_t scope, cppyy_index_t idx, int arg_index); + RPY_EXTERN char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN int cppyy_method_num_template_args(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN char* cppyy_method_template_arg_name(cppyy_scope_t scope, cppyy_index_t idx, cppyy_index_t iarg); + RPY_EXTERN cppyy_method_t cppyy_get_method(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN cppyy_index_t cppyy_get_global_operator( cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op); /* method properties ------------------------------------------------------ */ + RPY_EXTERN int cppyy_is_constructor(cppyy_type_t type, cppyy_index_t idx); + RPY_EXTERN int cppyy_is_staticmethod(cppyy_type_t type, cppyy_index_t idx); /* data member reflection information ------------------------------------- */ + RPY_EXTERN int cppyy_num_datamembers(cppyy_scope_t scope); + RPY_EXTERN char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index); + RPY_EXTERN char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index); + RPY_EXTERN ptrdiff_t cppyy_datamember_offset(cppyy_scope_t scope, int datamember_index); + RPY_EXTERN int cppyy_datamember_index(cppyy_scope_t scope, const char* name); /* data member properties ------------------------------------------------- */ + RPY_EXTERN int cppyy_is_publicdata(cppyy_type_t type, int datamember_index); + RPY_EXTERN int cppyy_is_staticdata(cppyy_type_t type, int datamember_index); /* misc helpers ----------------------------------------------------------- */ + RPY_EXTERN long long cppyy_strtoll(const char* str); + RPY_EXTERN unsigned long long cppyy_strtoull(const char* str); + RPY_EXTERN void cppyy_free(void* ptr); + RPY_EXTERN cppyy_object_t cppyy_charp2stdstring(const char* str); + RPY_EXTERN cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr); #ifdef __cplusplus diff --git a/pypy/module/cppyy/src/dummy_backend.cxx b/pypy/module/cppyy/src/dummy_backend.cxx --- a/pypy/module/cppyy/src/dummy_backend.cxx +++ b/pypy/module/cppyy/src/dummy_backend.cxx @@ -1,4 +1,3 @@ -#include "src/precommondefs.h" #include "cppyy.h" #include "capi.h" @@ -349,29 +348,24 @@ /* name to opaque C++ scope representation -------------------------------- */ -RPY_EXPORTED_FOR_TESTS int cppyy_num_scopes(cppyy_scope_t handle) { return 0; } -RPY_EXPORTED_FOR_TESTS char* cppyy_resolve_name(const char* cppitem_name) { return cppstring_to_cstring(cppitem_name); } -RPY_EXPORTED_FOR_TESTS cppyy_scope_t cppyy_get_scope(const char* scope_name) { return s_handles[scope_name]; // lookup failure will return 0 (== error) } -RPY_EXPORTED_FOR_TESTS cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t /* obj */) { return klass; } /* memory management ------------------------------------------------------ */ -RPY_EXPORTED_FOR_TESTS void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) { if (handle == s_handles["example01"]) delete (dummy::example01*)self; @@ -379,7 +373,6 @@ /* method/function dispatching -------------------------------------------- */ -RPY_EXPORTED_FOR_TESTS void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { long idx = (long)method; if (idx == s_methods["static_example01::staticSetPayload_payload*_double"]) { @@ -469,7 +462,6 @@ } } -RPY_EXPORTED_FOR_TESTS unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { unsigned char result = 0; const long idx = (long)method; @@ -482,7 +474,6 @@ return result; } -RPY_EXPORTED_FOR_TESTS char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { char result = 0; const long idx = (long)method; @@ -498,7 +489,6 @@ return result; } -RPY_EXPORTED_FOR_TESTS short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { short result = 0; const long idx = (long)method; @@ -514,7 +504,6 @@ return result; } -RPY_EXPORTED_FOR_TESTS int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { int result = 0; const long idx = (long)method; @@ -547,7 +536,6 @@ return result; } -RPY_EXPORTED_FOR_TESTS long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { long result = 0; const long idx = (long)method; @@ -689,7 +677,6 @@ return result; } -RPY_EXPORTED_FOR_TESTS long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { long long result = 0; const long idx = (long)method; @@ -705,7 +692,6 @@ return result; } -RPY_EXPORTED_FOR_TESTS float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { float result = 0; const long idx = (long)method; @@ -718,7 +704,6 @@ return result; } -RPY_EXPORTED_FOR_TESTS double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { double result = 0.; const long idx = (long)method; @@ -740,7 +725,6 @@ return result; } -RPY_EXPORTED_FOR_TESTS char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { char* result = 0; const long idx = (long)method; @@ -753,7 +737,6 @@ return result; } -RPY_EXPORTED_FOR_TESTS cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t handle, int nargs, void* args) { void* result = 0; const long idx = (long)method; @@ -776,14 +759,12 @@ return (cppyy_object_t)result; } -RPY_EXPORTED_FOR_TESTS cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) { return (cppyy_methptrgetter_t)0; } /* handling of function argument buffer ----------------------------------- */ -RPY_EXPORTED_FOR_TESTS void* cppyy_allocate_function_args(int nargs) { CPPYY_G__value* args = (CPPYY_G__value*)malloc(nargs*sizeof(CPPYY_G__value)); for (int i = 0; i < nargs; ++i) @@ -793,36 +774,30 @@ /* handling of function argument buffer ----------------------------------- */ -RPY_EXPORTED_FOR_TESTS void cppyy_deallocate_function_args(void* args) { free(args); } -RPY_EXPORTED_FOR_TESTS size_t cppyy_function_arg_sizeof() { return sizeof(CPPYY_G__value); } -RPY_EXPORTED_FOR_TESTS size_t cppyy_function_arg_typeoffset() { return offsetof(CPPYY_G__value, type); } /* scope reflection information ------------------------------------------- */ -RPY_EXPORTED_FOR_TESTS int cppyy_is_namespace(cppyy_scope_t /* handle */) { return 0; } -RPY_EXPORTED_FOR_TESTS int cppyy_is_enum(const char* /* type_name */) { return 0; } /* class reflection information ------------------------------------------- */ -RPY_EXPORTED_FOR_TESTS char* cppyy_final_name(cppyy_type_t handle) { for (Handles_t::iterator isp = s_handles.begin(); isp != s_handles.end(); ++isp) { if (isp->second == handle) @@ -831,75 +806,61 @@ return cppstring_to_cstring(""); } -RPY_EXPORTED_FOR_TESTS char* cppyy_scoped_final_name(cppyy_type_t handle) { return cppyy_final_name(handle); } -RPY_EXPORTED_FOR_TESTS int cppyy_has_complex_hierarchy(cppyy_type_t /* handle */) { return 0; } -RPY_EXPORTED_FOR_TESTS int cppyy_num_bases(cppyy_type_t /*handle*/) { return 0; } /* method/function reflection information --------------------------------- */ -RPY_EXPORTED_FOR_TESTS int cppyy_num_methods(cppyy_scope_t handle) { return s_scopes[handle].m_methods.size(); } -RPY_EXPORTED_FOR_TESTS cppyy_index_t cppyy_method_index_at(cppyy_scope_t /* scope */, int imeth) { return (cppyy_index_t)imeth; } -RPY_EXPORTED_FOR_TESTS char* cppyy_method_name(cppyy_scope_t handle, cppyy_index_t method_index) { return cppstring_to_cstring(s_scopes[handle].m_methods[(int)method_index].m_name); } -RPY_EXPORTED_FOR_TESTS char* cppyy_method_result_type(cppyy_scope_t handle, cppyy_index_t method_index) { return cppstring_to_cstring(s_scopes[handle].m_methods[method_index].m_returntype); } -RPY_EXPORTED_FOR_TESTS int cppyy_method_num_args(cppyy_scope_t handle, cppyy_index_t method_index) { return s_scopes[handle].m_methods[method_index].m_argtypes.size(); } -RPY_EXPORTED_FOR_TESTS int cppyy_method_req_args(cppyy_scope_t handle, cppyy_index_t method_index) { return cppyy_method_num_args(handle, method_index); } -RPY_EXPORTED_FOR_TESTS char* cppyy_method_arg_type(cppyy_scope_t handle, cppyy_index_t method_index, int arg_index) { return cppstring_to_cstring(s_scopes[handle].m_methods[method_index].m_argtypes[arg_index]); } -RPY_EXPORTED_FOR_TESTS char* cppyy_method_arg_default( cppyy_scope_t /* handle */, cppyy_index_t /* method_index */, int /* arg_index */) { return cppstring_to_cstring(""); } -RPY_EXPORTED_FOR_TESTS char* cppyy_method_signature(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */) { return cppstring_to_cstring(""); } -RPY_EXPORTED_FOR_TESTS int cppyy_method_is_template(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */) { return 0; } -RPY_EXPORTED_FOR_TESTS cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t method_index) { if (s_scopes.find(handle) != s_scopes.end()) { long id = s_scopes[handle].m_method_offset + (long)method_index; @@ -911,7 +872,6 @@ /* method properties ----------------------------------------------------- */ -RPY_EXPORTED_FOR_TESTS int cppyy_is_constructor(cppyy_type_t handle, cppyy_index_t method_index) { if (s_scopes.find(handle) != s_scopes.end()) return s_scopes[handle].m_methods[method_index].m_type == kConstructor; @@ -919,7 +879,6 @@ return 0; } -RPY_EXPORTED_FOR_TESTS int cppyy_is_staticmethod(cppyy_type_t handle, cppyy_index_t method_index) { if (s_scopes.find(handle) != s_scopes.end()) return s_scopes[handle].m_methods[method_index].m_type == kStatic; @@ -929,34 +888,28 @@ /* data member reflection information ------------------------------------- */ -RPY_EXPORTED_FOR_TESTS int cppyy_num_datamembers(cppyy_scope_t handle) { return s_scopes[handle].m_datambrs.size(); } -RPY_EXPORTED_FOR_TESTS char* cppyy_datamember_name(cppyy_scope_t handle, int idatambr) { return cppstring_to_cstring(s_scopes[handle].m_datambrs[idatambr].m_name); } -RPY_EXPORTED_FOR_TESTS char* cppyy_datamember_type(cppyy_scope_t handle, int idatambr) { return cppstring_to_cstring(s_scopes[handle].m_datambrs[idatambr].m_type); } -RPY_EXPORTED_FOR_TESTS ptrdiff_t cppyy_datamember_offset(cppyy_scope_t handle, int idatambr) { return s_scopes[handle].m_datambrs[idatambr].m_offset; } /* data member properties ------------------------------------------------ */ -RPY_EXPORTED_FOR_TESTS int cppyy_is_publicdata(cppyy_scope_t handle, int idatambr) { return 1; } -RPY_EXPORTED_FOR_TESTS int cppyy_is_staticdata(cppyy_scope_t handle, int idatambr) { return s_scopes[handle].m_datambrs[idatambr].m_isstatic; } @@ -964,44 +917,37 @@ /* misc helpers ----------------------------------------------------------- */ #if defined(_MSC_VER) -RPY_EXPORTED_FOR_TESTS long long cppyy_strtoll(const char* str) { return _strtoi64(str, NULL, 0); } extern "C" { -RPY_EXPORTED_FOR_TESTS unsigned long long cppyy_strtoull(const char* str) { return _strtoui64(str, NULL, 0); } } #else -RPY_EXPORTED_FOR_TESTS long long cppyy_strtoll(const char* str) { return strtoll(str, NULL, 0); } extern "C" { -RPY_EXPORTED_FOR_TESTS unsigned long long cppyy_strtoull(const char* str) { return strtoull(str, NULL, 0); } } #endif -RPY_EXPORTED_FOR_TESTS void cppyy_free(void* ptr) { free(ptr); } -RPY_EXPORTED_FOR_TESTS cppyy_object_t cppyy_charp2stdstring(const char* str) { void* arena = new char[sizeof(std::string)]; new (arena) std::string(str); return (cppyy_object_t)arena; } -RPY_EXPORTED_FOR_TESTS cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr) { void* arena = new char[sizeof(std::string)]; new (arena) std::string(*(std::string*)ptr); diff --git a/pypy/module/cppyy/test/conftest.py b/pypy/module/cppyy/test/conftest.py --- a/pypy/module/cppyy/test/conftest.py +++ b/pypy/module/cppyy/test/conftest.py @@ -50,7 +50,7 @@ eci = ExternalCompilationInfo( separate_module_files=[srcpath.join('dummy_backend.cxx')], include_dirs=[incpath, tstpath, cdir], - compile_extra=['-DRPY_EXPORTED_FOR_TESTS=RPY_EXPORTED'], + compile_extra=['-DRPY_EXTERN=RPY_EXPORTED'], use_cpp_linker=True, ) diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -775,8 +775,7 @@ struct PyPyAPI { %(members)s } _pypyAPI; - RPY_EXPORTED_FOR_TESTS - struct PyPyAPI* pypyAPI = &_pypyAPI; + RPY_EXTERN struct PyPyAPI* pypyAPI = &_pypyAPI; """ % dict(members=structmembers) functions = generate_decls_and_callbacks(db, export_symbols) @@ -947,7 +946,7 @@ name_no_star = process_va_name(name) header = ('%s pypy_va_get_%s(va_list* vp)' % (name, name_no_star)) - pypy_decls.append('RPY_EXPORTED_FOR_TESTS ' + header + ';') + pypy_decls.append('RPY_EXTERN ' + header + ';') functions.append(header + '\n{return va_arg(*vp, %s);}\n' % name) for name, (typ, expr) in GLOBALS.iteritems(): @@ -1007,7 +1006,7 @@ if sys.platform == 'win32': get_pythonapi_source = ''' #include - RPY_EXPORTED_FOR_TESTS + RPY_EXTERN HANDLE pypy_get_pythonapi_handle() { MEMORY_BASIC_INFORMATION mi; memset(&mi, 0, sizeof(mi)); diff --git a/pypy/module/cpyext/include/modsupport.h b/pypy/module/cpyext/include/modsupport.h --- a/pypy/module/cpyext/include/modsupport.h +++ b/pypy/module/cpyext/include/modsupport.h @@ -78,11 +78,20 @@ /* * This is from pyport.h. Perhaps it belongs elsewhere. */ +#ifdef _WIN32 +/* explicitly export since PyAPI_FUNC is usually dllimport */ +#ifdef __cplusplus +#define PyMODINIT_FUNC extern "C" __declspec(dllexport) void +#else +#define PyMODINIT_FUNC __declspec(dllexport) void +#endif +#else #ifdef __cplusplus #define PyMODINIT_FUNC extern "C" PyAPI_FUNC(void) #else #define PyMODINIT_FUNC PyAPI_FUNC(void) #endif +#endif /* WIN32 */ PyAPI_DATA(char *) _Py_PackageContext; diff --git a/pypy/module/cpyext/src/pythread.c b/pypy/module/cpyext/src/pythread.c --- a/pypy/module/cpyext/src/pythread.c +++ b/pypy/module/cpyext/src/pythread.c @@ -1,11 +1,18 @@ #include +#ifndef _WIN32 +# include +#endif #include "pythread.h" #include "src/thread.h" long PyThread_get_thread_ident(void) { - return RPyThreadGetIdent(); +#ifdef _WIN32 + return (long)GetCurrentThreadId(); +#else + return (long)pthread_self(); +#endif } PyThread_type_lock diff --git a/pypy/module/cpyext/test/conftest.py b/pypy/module/cpyext/test/conftest.py --- a/pypy/module/cpyext/test/conftest.py +++ b/pypy/module/cpyext/test/conftest.py @@ -7,7 +7,7 @@ # it's necessary to run "import time" at least once before any # other cpyext test, otherwise the same statement will fail in # test_datetime.py. - space = gettestobjspace(usemodules=['rctime']) + space = gettestobjspace(usemodules=['time']) space.getbuiltinmodule("time") def pytest_ignore_collect(path, config): diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -102,7 +102,7 @@ class LeakCheckingTest(object): """Base class for all cpyext tests.""" spaceconfig = dict(usemodules=['cpyext', 'thread', '_rawffi', 'array', - 'itertools', 'rctime', 'binascii', 'micronumpy']) + 'itertools', 'time', 'binascii', 'micronumpy']) spaceconfig['std.withmethodcache'] = True enable_leak_checking = True diff --git a/pypy/module/fcntl/test/test_fcntl.py b/pypy/module/fcntl/test/test_fcntl.py --- a/pypy/module/fcntl/test/test_fcntl.py +++ b/pypy/module/fcntl/test/test_fcntl.py @@ -12,7 +12,7 @@ class AppTestFcntl: spaceconfig = dict(usemodules=('fcntl', 'array', 'struct', 'termios', - 'select', 'rctime')) + 'select', 'time')) def setup_class(cls): tmpprefix = str(udir.ensure('test_fcntl', dir=1).join('tmp_')) diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py --- a/pypy/module/imp/test/test_app.py +++ b/pypy/module/imp/test/test_app.py @@ -4,7 +4,7 @@ class AppTestImpModule: spaceconfig = { - 'usemodules': ['binascii', 'imp', 'itertools', 'rctime', 'struct'], + 'usemodules': ['binascii', 'imp', 'itertools', 'time', 'struct'], } def setup_class(cls): diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py --- a/pypy/module/imp/test/test_import.py +++ b/pypy/module/imp/test/test_import.py @@ -149,7 +149,7 @@ class AppTestImport: spaceconfig = { - "usemodules": ['_md5', 'rctime'], + "usemodules": ['_md5', 'time'], } def setup_class(cls): @@ -1044,7 +1044,7 @@ class AppTestImportHooks(object): spaceconfig = { - "usemodules": ['struct', 'itertools', 'rctime'], + "usemodules": ['struct', 'itertools', 'time'], } def setup_class(cls): @@ -1304,7 +1304,7 @@ class AppTestMultithreadedImp(object): - spaceconfig = dict(usemodules=['thread', 'rctime']) + spaceconfig = dict(usemodules=['thread', 'time']) def setup_class(cls): #if not conftest.option.runappdirect: diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -144,7 +144,6 @@ atom_int(tc, int) puts code and int atom_int64(tc, int64) puts code and int64 atom_str(tc, str) puts code, len and string - atom_strlist(tc, strlist) puts code, len and list of strings building blocks for compound types: @@ -198,15 +197,6 @@ self.atom_int(typecode, len(x)) self.put(x) - def atom_strlist(self, typecode, tc2, x): - self.atom_int(typecode, len(x)) - atom_str = self.atom_str - for item in x: - # type(str) seems to be forbidden - #if type(item) is not str: - # self.raise_exc('object with wrong type in strlist') - atom_str(tc2, item) - def start(self, typecode): # type(char) not supported self.put(typecode) @@ -379,16 +369,6 @@ self.start(typecode) return self.get_lng() - def atom_strlist(self, typecode, tc2): - self.start(typecode) - lng = self.get_lng() - res = [None] * lng - idx = 0 - while idx < lng: - res[idx] = self.atom_str(tc2) - idx += 1 - return res - def start(self, typecode): tc = self.get1() if tc != typecode: @@ -436,7 +416,6 @@ def get_w_obj(self, allow_null=False): space = self.space - w_ret = space.w_None # something not None tc = self.get1() w_ret = self._dispatch[ord(tc)](space, self, tc) if w_ret is None and not allow_null: diff --git a/pypy/module/math/test/test_math.py b/pypy/module/math/test/test_math.py --- a/pypy/module/math/test/test_math.py +++ b/pypy/module/math/test/test_math.py @@ -7,7 +7,7 @@ class AppTestMath: spaceconfig = { - "usemodules": ['math', 'struct', 'itertools', 'rctime', 'binascii'], + "usemodules": ['math', 'struct', 'itertools', 'time', 'binascii'], } From noreply at buildbot.pypy.org Fri Dec 5 22:15:53 2014 From: noreply at buildbot.pypy.org (amauryfa) Date: Fri, 5 Dec 2014 22:15:53 +0100 (CET) Subject: [pypy-commit] pypy more-rposix: Restore the previous version to fix the test Message-ID: <20141205211553.7A4231D29F4@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: more-rposix Changeset: r74845:34acd72615a6 Date: 2014-12-05 22:15 +0100 http://bitbucket.org/pypy/pypy/changeset/34acd72615a6/ Log: Restore the previous version to fix the test diff --git a/rpython/flowspace/test/test_objspace.py b/rpython/flowspace/test/test_objspace.py --- a/rpython/flowspace/test/test_objspace.py +++ b/rpython/flowspace/test/test_objspace.py @@ -10,7 +10,6 @@ from rpython.flowspace.flowcontext import FlowingError, FlowContext from rpython.conftest import option from rpython.tool.stdlib_opcode import host_bytecode_spec -from rpython.rlib import rposix import os import operator @@ -1263,9 +1262,9 @@ self.show(x) ops = x.startblock.operations assert ops[0].opname == 'simple_call' - assert ops[0].args[0].value is rposix.unlink + assert ops[0].args[0].value is os.unlink assert ops[1].opname == 'simple_call' - assert ops[1].args[0].value is rposix.unlink + assert ops[1].args[0].value is os.unlink def test_rabspath(self): import os.path From noreply at buildbot.pypy.org Fri Dec 5 22:37:25 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 22:37:25 +0100 (CET) Subject: [pypy-commit] creflect default: move some code around and translate gc_weakrefs.py into C. Message-ID: <20141205213725.A528D1D2E26@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo 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 + 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 - 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); From noreply at buildbot.pypy.org Fri Dec 5 22:42:52 2014 From: noreply at buildbot.pypy.org (arigo) Date: Fri, 5 Dec 2014 22:42:52 +0100 (CET) Subject: [pypy-commit] creflect default: simplify Message-ID: <20141205214252.04CE41D257D@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r186:8bcc78765083 Date: 2014-12-05 22:43 +0100 http://bitbucket.org/cffi/creflect/changeset/8bcc78765083/ Log: simplify diff --git a/zeffir/cgc.c b/zeffir/cgc.c --- a/zeffir/cgc.c +++ b/zeffir/cgc.c @@ -2,16 +2,12 @@ /* 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) +static PyObject *gc_wref_remove(PyObject *ffi_wref_data, PyObject *arg) { PyObject *destructor, *cdata, *x; - PyObject *res = PyObject_CallMethodObjArgs(GCWREF_DATA(ffi), + PyObject *res = PyObject_CallMethodObjArgs(ffi_wref_data, zef_name_pop, arg, NULL); if (res == NULL) return NULL; @@ -30,7 +26,7 @@ } static PyMethodDef remove_callback = { - "remove", (PyCFunction)gc_wref_remove, METH_O + "zef_remove", (PyCFunction)gc_wref_remove, METH_O }; static PyObject *gc_weakrefs_build(ZefFFIObject *ffi, CDataObject *cd, @@ -38,32 +34,29 @@ { PyObject *new_cdata, *ref = NULL, *tup = NULL; - if (GCWREF_DATA(ffi) == NULL) { + if (ffi->gc_wrefs == NULL) { /* initialize */ - PyObject *remove, *data; + PyObject *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) + data = PyDict_New(); + if (data == NULL) return NULL; - data = PyDict_New(); - if (data == NULL) { - Py_DECREF(remove); + ffi->gc_wrefs = PyCFunction_New(&remove_callback, data); + Py_DECREF(data); + if (ffi->gc_wrefs == NULL) 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)); + ref = PyWeakref_NewRef(new_cdata, ffi->gc_wrefs); if (ref == NULL) goto error; @@ -71,7 +64,8 @@ if (tup == NULL) goto error; - if (PyDict_SetItem(GCWREF_DATA(ffi), ref, tup) < 0) + /* the 'self' of the function 'gc_wrefs' is actually the data dict */ + if (PyDict_SetItem(PyCFunction_GET_SELF(ffi->gc_wrefs), ref, tup) < 0) goto error; Py_DECREF(tup); diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -17,23 +17,21 @@ struct ZefFFIObject_s { PyObject_HEAD PyObject *types_dict; - PyObject *gc_wrefs[2]; + PyObject *gc_wrefs; }; 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]); + Py_XDECREF(ffi->gc_wrefs); 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]); + Py_VISIT(ffi->gc_wrefs); return 0; } @@ -53,8 +51,7 @@ return NULL; } ffi->types_dict = dict; - ffi->gc_wrefs[0] = NULL; - ffi->gc_wrefs[1] = NULL; + ffi->gc_wrefs = NULL; PyObject_GC_Track(ffi); return (PyObject *)ffi; From noreply at buildbot.pypy.org Fri Dec 5 23:01:38 2014 From: noreply at buildbot.pypy.org (rguillebert) Date: Fri, 5 Dec 2014 23:01:38 +0100 (CET) Subject: [pypy-commit] extradoc extradoc: Progress Message-ID: <20141205220138.6CAEB1D2CF0@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: extradoc Changeset: r5478:dd38c1bea82c Date: 2014-12-06 03:31 +0530 http://bitbucket.org/pypy/extradoc/changeset/dd38c1bea82c/ Log: Progress diff --git a/talk/scipyindia2014/talk.rst b/talk/scipyindia2014/talk.rst --- a/talk/scipyindia2014/talk.rst +++ b/talk/scipyindia2014/talk.rst @@ -1,3 +1,5 @@ +.. include:: beamerdefs.txt + ============================= PyPy and the scientific stack ============================= @@ -40,7 +42,16 @@ Speed ----- -* XXX : Insert speed.pypy.org screenshot +.. image:: speed.png + :scale: 50% + :align: center + +How ? +----- + +* Tracing Just-In-Time compiler + +* Removes overhead Demo ---- @@ -103,8 +114,23 @@ NumPyPy performance ------------------- +* Vectorized operations should be as fast as Numpy + +* Using ndarrays as you would use arrays in C or Java should be as fast + +* Lazy evaluation ? + PyMetabiosis ------------ +* Work in progress + JitPy ----- + +* Work in progress + +Thank You +--------- + +Questions ? From noreply at buildbot.pypy.org Fri Dec 5 23:17:35 2014 From: noreply at buildbot.pypy.org (rguillebert) Date: Fri, 5 Dec 2014 23:17:35 +0100 (CET) Subject: [pypy-commit] extradoc extradoc: Add image Message-ID: <20141205221735.BA3FA1D2CF0@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: extradoc Changeset: r5479:9883ef8b82cc Date: 2014-12-06 03:47 +0530 http://bitbucket.org/pypy/extradoc/changeset/9883ef8b82cc/ Log: Add image diff --git a/talk/scipyindia2014/speed.png b/talk/scipyindia2014/speed.png new file mode 100644 index 0000000000000000000000000000000000000000..63b771ce59358bbcb28efbba84a43f03328b4554 GIT binary patch [cut] From noreply at buildbot.pypy.org Fri Dec 5 23:27:52 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Fri, 5 Dec 2014 23:27:52 +0100 (CET) Subject: [pypy-commit] pypy default: add test_zjit for reduce_cumulative Message-ID: <20141205222752.733741D2E26@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74846:f907c020762a Date: 2014-12-05 16:48 -0500 http://bitbucket.org/pypy/pypy/changeset/f907c020762a/ Log: add test_zjit for reduce_cumulative diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -34,8 +34,8 @@ SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any", - "unegative", "flat", "tostring","count_nonzero", - "argsort"] + "unegative", "flat", "tostring", "count_nonzero", + "argsort", "cumsum"] TWO_ARG_FUNCTIONS = ["dot", 'take', 'searchsorted'] TWO_ARG_FUNCTIONS_OR_NONE = ['view', 'astype'] THREE_ARG_FUNCTIONS = ['where'] @@ -559,6 +559,8 @@ w_res = arr.descr_any(interp.space) elif self.name == "all": w_res = arr.descr_all(interp.space) + elif self.name == "cumsum": + w_res = arr.descr_cumsum(interp.space) elif self.name == "unegative": neg = ufuncs.get(interp.space).negative w_res = neg.call(interp.space, [arr]) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -183,6 +183,28 @@ 'raw_load': 1, }) + def define_cumsum(): + return """ + a = |30| + b = cumsum(a) + b -> 5 + """ + + def test_cumsum(self): + result = self.run("cumsum") + assert result == 15 + self.check_trace_count(1) + self.check_simple_loop({ + 'float_add': 1, + 'guard_false': 1, + 'guard_not_invalidated': 1, + 'int_add': 4, + 'int_ge': 1, + 'jump': 1, + 'raw_load': 1, + 'raw_store': 1, + }) + def define_axissum(): return """ a = [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]] @@ -218,7 +240,7 @@ 'getfield_gc': 5, 'getfield_gc_pure': 51, 'guard_class': 3, - 'guard_false': 12, + 'guard_false': 13, 'guard_nonnull': 11, 'guard_nonnull_class': 3, 'guard_not_invalidated': 2, From noreply at buildbot.pypy.org Fri Dec 5 23:27:53 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Fri, 5 Dec 2014 23:27:53 +0100 (CET) Subject: [pypy-commit] pypy default: avoid tracking an index in reduce_cumulative Message-ID: <20141205222753.B83E91D2E26@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74847:f28d82b7078c Date: 2014-12-05 17:03 -0500 http://bitbucket.org/pypy/pypy/changeset/f28d82b7078c/ Log: avoid tracking an index in reduce_cumulative diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -166,6 +166,7 @@ def compute_reduce_cumulative(space, obj, out, calc_dtype, func, identity): obj_iter, obj_state = obj.create_iter() out_iter, out_state = out.create_iter() + out_iter.track_index = False if identity is None: cur_value = obj_iter.getitem(obj_state).convert_to(space, calc_dtype) out_iter.setitem(out_state, cur_value) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -198,7 +198,7 @@ 'float_add': 1, 'guard_false': 1, 'guard_not_invalidated': 1, - 'int_add': 4, + 'int_add': 3, 'int_ge': 1, 'jump': 1, 'raw_load': 1, From noreply at buildbot.pypy.org Fri Dec 5 23:27:54 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Fri, 5 Dec 2014 23:27:54 +0100 (CET) Subject: [pypy-commit] pypy default: add test_zjit for logical_xor reduce Message-ID: <20141205222754.D64691D2E26@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74848:dba4524de78e Date: 2014-12-05 16:17 -0500 http://bitbucket.org/pypy/pypy/changeset/dba4524de78e/ Log: add test_zjit for logical_xor reduce diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -33,7 +33,7 @@ pass -SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any", +SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any", "xor", "unegative", "flat", "tostring", "count_nonzero", "argsort", "cumsum"] TWO_ARG_FUNCTIONS = ["dot", 'take', 'searchsorted'] @@ -561,6 +561,9 @@ w_res = arr.descr_all(interp.space) elif self.name == "cumsum": w_res = arr.descr_cumsum(interp.space) + elif self.name == "xor": + xor = ufuncs.get(interp.space).logical_xor + w_res = xor.reduce(interp.space, arr, None) elif self.name == "unegative": neg = ufuncs.get(interp.space).negative w_res = neg.call(interp.space, [arr]) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -400,6 +400,7 @@ def test_all(self): result = self.run("all") assert result == 1 + self.check_trace_count(1) self.check_simple_loop({ 'cast_float_to_int': 1, 'guard_false': 1, @@ -412,6 +413,36 @@ 'raw_load': 1, }) + def define_logical_xor_reduce(): + return """ + a = [1,1,1,1,1,1,1,1] + xor(a) + """ + + def test_logical_xor_reduce(self): + result = self.run("logical_xor_reduce") + assert result == 0 + self.check_trace_count(2) + # XXX fix this + self.check_simple_loop({ + 'cast_float_to_int': 1, + 'getfield_gc': 2, + 'getfield_gc_pure': 11, + 'guard_class': 1, + 'guard_false': 2, + 'guard_not_invalidated': 1, + 'guard_true': 4, + 'int_add': 2, + 'int_and': 1, + 'int_ge': 1, + 'int_is_true': 3, + 'int_xor': 1, + 'jump': 1, + 'new_with_vtable': 1, + 'raw_load': 1, + 'setfield_gc': 4, + }) + def define_already_forced(): return """ a = |30| From noreply at buildbot.pypy.org Fri Dec 5 23:27:56 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Fri, 5 Dec 2014 23:27:56 +0100 (CET) Subject: [pypy-commit] pypy default: eliminate some ops in logical_xor Message-ID: <20141205222756.038B71D2E26@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74849:794a98c020bf Date: 2014-12-05 16:39 -0500 http://bitbucket.org/pypy/pypy/changeset/794a98c020bf/ Log: eliminate some ops in logical_xor diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -429,14 +429,13 @@ 'getfield_gc': 2, 'getfield_gc_pure': 11, 'guard_class': 1, - 'guard_false': 2, + 'guard_false': 1, 'guard_not_invalidated': 1, - 'guard_true': 4, + 'guard_true': 5, 'int_add': 2, 'int_and': 1, 'int_ge': 1, - 'int_is_true': 3, - 'int_xor': 1, + 'int_is_true': 2, 'jump': 1, 'new_with_vtable': 1, 'raw_load': 1, diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py --- a/pypy/module/micronumpy/types.py +++ b/pypy/module/micronumpy/types.py @@ -285,7 +285,9 @@ @raw_binary_op def logical_xor(self, v1, v2): - return bool(v1) ^ bool(v2) + a = bool(v1) + b = bool(v2) + return (not b and a) or (not a and b) @raw_unary_op def bool(self, v): @@ -1258,7 +1260,9 @@ @raw_binary_op def logical_xor(self, v1, v2): - return self._bool(v1) ^ self._bool(v2) + a = self._bool(v1) + b = self._bool(v2) + return (not b and a) or (not a and b) def min(self, v1, v2): if self.le(v1, v2) or self.isnan(v1): @@ -1733,7 +1737,9 @@ @str_binary_op def logical_xor(self, v1, v2): - return bool(v1) ^ bool(v2) + a = bool(v1) + b = bool(v2) + return (not b and a) or (not a and b) def bool(self, v): return bool(self.to_str(v)) diff --git a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py --- a/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py +++ b/pypy/module/pypyjit/test_pypy_c/test_micronumpy.py @@ -30,9 +30,7 @@ guard_true(i14, descr=...) i15 = getfield_gc_pure(p1, descr=) i16 = int_is_true(i15) - i18 = int_xor(i16, 1) - i19 = int_is_true(i18) - guard_true(i19, descr=...) + guard_false(i16, descr=...) i20 = getfield_gc(p2, descr=) i21 = getfield_gc_pure(p0, descr=) guard_true(i21, descr=...) From noreply at buildbot.pypy.org Sat Dec 6 06:56:55 2014 From: noreply at buildbot.pypy.org (rguillebert) Date: Sat, 6 Dec 2014 06:56:55 +0100 (CET) Subject: [pypy-commit] extradoc extradoc: Progress Message-ID: <20141206055655.AD09E1C07E8@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: extradoc Changeset: r5480:61ba4f722878 Date: 2014-12-06 11:25 +0530 http://bitbucket.org/pypy/extradoc/changeset/61ba4f722878/ Log: Progress diff --git a/talk/scipyindia2014/talk.rst b/talk/scipyindia2014/talk.rst --- a/talk/scipyindia2014/talk.rst +++ b/talk/scipyindia2014/talk.rst @@ -17,8 +17,6 @@ * Software consultant -* Feel free to interrupt me - PyPy ---- @@ -125,11 +123,71 @@ * Work in progress +* Allows you to use any CPython module on PyPy + +* Embeds CPython into PyPy with CFFI + +* Numpy arrays can be shared between PyPy and CPython + +PyMetabiosis +------------ + +|scriptsize| + +.. sourcecode:: python + + from pymetabiosis import import_module + + cpython_virtualenv_path = + "/home/rguillebert/.virtualenvs/venv/bin/activate_this.py" + + builtin = import_module("__builtin__") + + # Activate a virtualenv for the cpython interpreter + builtin.execfile(cpython_virtualenv_path, + {"__file__" : cpython_virtualenv_path} + ) + + pylab = import_module("matplotlib.pylab") + + pylab.plot([1, 2, 3, 4]) + pylab.show() + +|end_scriptsize| + JitPy ----- * Work in progress +* Embeds PyPy into CPython + +* Provides a decorator that allows you to run specific functions on PyPy + +* Is used the same way as numba, but different performance caracteristics + +JitPy +----- + +|scriptsize| + +.. sourcecode:: python + + from jitpy import setup + setup('') + from jitpy.wrapper import jittify + + @jittify([int, float], float) + def func(count, no): + s = 0 + for i in range(count): + s += no + return s + + func(100000, 1.2) + +|end_scriptsize| + Thank You --------- From noreply at buildbot.pypy.org Sat Dec 6 09:32:51 2014 From: noreply at buildbot.pypy.org (rguillebert) Date: Sat, 6 Dec 2014 09:32:51 +0100 (CET) Subject: [pypy-commit] extradoc extradoc: Nearly done ? Message-ID: <20141206083251.DE7B21D3616@cobra.cs.uni-duesseldorf.de> Author: Romain Guillebert Branch: extradoc Changeset: r5481:89e8eadeff5e Date: 2014-12-06 14:02 +0530 http://bitbucket.org/pypy/extradoc/changeset/89e8eadeff5e/ Log: Nearly done ? diff --git a/talk/scipyindia2014/talk.pdf b/talk/scipyindia2014/talk.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4be849fc047dc21919a478732a2521894f5b01fc GIT binary patch [cut] diff --git a/talk/scipyindia2014/talk.rst b/talk/scipyindia2014/talk.rst --- a/talk/scipyindia2014/talk.rst +++ b/talk/scipyindia2014/talk.rst @@ -107,14 +107,14 @@ * Most of numpy is there -* XXX is missing +* linalg and the object dtype are the two biggest features that we haven't implemented yet NumPyPy performance ------------------- * Vectorized operations should be as fast as Numpy -* Using ndarrays as you would use arrays in C or Java should be as fast +* Using ndarrays as you would use arrays in C or Java should be as fast as the vectorized way * Lazy evaluation ? @@ -123,7 +123,7 @@ * Work in progress -* Allows you to use any CPython module on PyPy +* Allows you to use any CPython module on PyPy (scipy for example) * Embeds CPython into PyPy with CFFI @@ -164,7 +164,7 @@ * Provides a decorator that allows you to run specific functions on PyPy -* Is used the same way as numba, but different performance caracteristics +* Is used the same way as numba, but different performance characteristics JitPy ----- @@ -188,6 +188,17 @@ |end_scriptsize| +Future +------ + +* Full numpy support + +* Improved C extension compatibility + +* I would like to see Cython work with PyPy + +* No more Global Interpreter Lock + Thank You --------- From noreply at buildbot.pypy.org Sat Dec 6 11:41:59 2014 From: noreply at buildbot.pypy.org (amauryfa) Date: Sat, 6 Dec 2014 11:41:59 +0100 (CET) Subject: [pypy-commit] pypy more-rposix: Better placement for sandbox properties Message-ID: <20141206104159.4CE871C07E8@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: more-rposix Changeset: r74850:3b5d1aeee6d5 Date: 2014-12-06 11:37 +0100 http://bitbucket.org/pypy/pypy/changeset/3b5d1aeee6d5/ Log: Better placement for sandbox properties diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py --- a/rpython/rlib/objectmodel.py +++ b/rpython/rlib/objectmodel.py @@ -296,12 +296,12 @@ class ExtRegistry(ExtRegistryEntry): _about_ = replaced_function def compute_annotation(self): + if sandboxed_name: + config = self.bookkeeper.annotator.translator.config + if config.translation.sandbox: + func._sandbox_external_name = sandboxed_name + func._dont_inline_ = True return self.bookkeeper.immutablevalue(func) - - if sandboxed_name: - func._sandbox_external_name = sandboxed_name - # XXX THIS IS NOT CORRECT. Only do this when config.sandbox. - func._dont_inline_ = True return func return wrap From noreply at buildbot.pypy.org Sat Dec 6 11:42:00 2014 From: noreply at buildbot.pypy.org (amauryfa) Date: Sat, 6 Dec 2014 11:42:00 +0100 (CET) Subject: [pypy-commit] pypy more-rposix: Don't use os.write in gc helper functions. Message-ID: <20141206104200.D6F8B1C07E8@cobra.cs.uni-duesseldorf.de> Author: Amaury Forgeot d'Arc Branch: more-rposix Changeset: r74851:c722fad1b5bf Date: 2014-12-06 11:41 +0100 http://bitbucket.org/pypy/pypy/changeset/c722fad1b5bf/ Log: Don't use os.write in gc helper functions. This fixes a test where os.write is not used in translated function, and is annotated too late. extfunc.py uses a "mixed-level delayed object" but I don't know how to do this here. diff --git a/rpython/memory/gctransform/support.py b/rpython/memory/gctransform/support.py --- a/rpython/memory/gctransform/support.py +++ b/rpython/memory/gctransform/support.py @@ -73,15 +73,19 @@ hop.exception_cannot_occur() return hop.inputconst(hop.r_result.lowleveltype, hop.s_result.const) +def write(fd, string): + from rpython.rlib.rposix import c_write + return c_write(fd, string, len(string)) + def ll_call_destructor(destrptr, destr_v, typename): try: destrptr(destr_v) except Exception, e: try: - os.write(2, "a destructor of type ") - os.write(2, typename) - os.write(2, " raised an exception ") - os.write(2, str(e)) - os.write(2, " ignoring it\n") + write(2, "a destructor of type ") + write(2, typename) + write(2, " raised an exception ") + write(2, str(e)) + write(2, " ignoring it\n") except: pass From noreply at buildbot.pypy.org Sat Dec 6 18:02:42 2014 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 6 Dec 2014 18:02:42 +0100 (CET) Subject: [pypy-commit] creflect default: tweak the regexp to recognize also "#define FOO" with no value specified. Message-ID: <20141206170242.D3C811D2324@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r187:31b44d824886 Date: 2014-12-06 18:03 +0100 http://bitbucket.org/cffi/creflect/changeset/31b44d824886/ Log: tweak the regexp to recognize also "#define FOO" with no value specified. diff --git a/creflect/cparser.py b/creflect/cparser.py --- a/creflect/cparser.py +++ b/creflect/cparser.py @@ -31,7 +31,7 @@ r_empty_braces = re.compile(r"{(\s*)}") # after comments have been removed r_typedef_dotdodot = re.compile(r"\btypedef(\s*)[.][.][.]") r_define_var = re.compile( - r"^[ \t]*#[ \t]*define[ \t]+([A-Za-z_][A-Za-z0-9_]+)[ \t][^\n]+", + r"^[ \t]*#[ \t]*define[ \t]+([A-Za-z_][A-Za-z0-9_]+)([ \t].*)?$", re.MULTILINE) def remove_comments(csource): diff --git a/creflect/test/codegen/macro-001.c b/creflect/test/codegen/macro-001.c --- a/creflect/test/codegen/macro-001.c +++ b/creflect/test/codegen/macro-001.c @@ -1,5 +1,10 @@ +#define FOO +#define BAR (40U + 2) + +# ____________________________________________________________ + +#undef FOO #define FOO 42 -#define BAR (40U + 2) # ____________________________________________________________ From noreply at buildbot.pypy.org Sat Dec 6 19:34:38 2014 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 6 Dec 2014 19:34:38 +0100 (CET) Subject: [pypy-commit] creflect default: Calling function pointer cdata objects. Works only for types that have Message-ID: <20141206183438.72CEF1C13BD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r188:13d44f67603a Date: 2014-12-06 19:34 +0100 http://bitbucket.org/cffi/creflect/changeset/13d44f67603a/ Log: Calling function pointer cdata objects. Works only for types that have been declared in the .crx, but without any libffi dependency. diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -160,6 +160,7 @@ static _crx_type_t *_zef_function(_crx_builder_t *cb, _crx_type_t *ret, _crx_qual_type args[], int nargs, + _crx_trampoline1_fn trampl, int dotdotdot) { if (PyErr_Occurred()) @@ -223,12 +224,16 @@ ct->ct_size = -1; ct->ct_flags = CT_FUNCTION; - /* XXX more... */ put_cached_type(get_types_dict(cb), name_obj, ct); done: Py_DECREF(name_obj); + + if (ct->ct_stuff == NULL && trampl != NULL && !PyErr_Occurred()) { + assert(!dotdotdot); /* should have 'trampl == NULL' in this case */ + ct->ct_stuff = make_func_support(ret, args, nargs, trampl, 0); + } return ct; } @@ -236,7 +241,7 @@ _crx_qual_type args[], int nargs, _crx_trampoline1_fn trampl) { - return _zef_function(cb, ret, args, nargs, 0); + return _zef_function(cb, ret, args, nargs, trampl, 0); } static _crx_type_t *zef_get_ellipsis_function_type(_crx_builder_t *cb, @@ -244,7 +249,7 @@ _crx_qual_type args[], int nargs) { - return _zef_function(cb, ret, args, nargs, 1); + return _zef_function(cb, ret, args, nargs, NULL, 1); } static CTypeDescrObject *fetch_pointer_type(PyObject *types_dict, @@ -517,7 +522,8 @@ if (interned_fields == NULL) return; - previous = (CFieldObject **)&ct->ct_extra; + assert(ct->ct_fields == NULL); + previous = &ct->ct_fields; for (i = 0; i < nfields; i++) { _crx_field_t *f = &fields[i]; diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -638,7 +638,7 @@ if (PyList_Check(init) || PyTuple_Check(init)) { PyObject **items = PySequence_Fast_ITEMS(init); Py_ssize_t i, n = PySequence_Fast_GET_SIZE(init); - CFieldObject *cf = (CFieldObject *)ct->ct_extra; + CFieldObject *cf = ct->ct_fields; for (i=0; izfs_nargs; Py_ssize_t actualnargs; void *llargs[nargs]; @@ -123,8 +123,8 @@ if (actualnargs != nargs) { if (!PyErr_Occurred()) PyErr_Format(PyExc_TypeError, - "'%s()' expected %d arguments, but got %zd", - zfs->zfs_md.ml_name, nargs, actualnargs); + "'%s' expected %d arguments, but got %zd", + funcname, nargs, actualnargs); return NULL; } @@ -165,7 +165,14 @@ lloffset += ct->ct_size; } - zfs->zfs_trampl(llargs, llbuffer); + if (func == NULL) { + assert(zfs->zfs_md.ml_name != NULL); + ((_crx_trampoline0_fn)zfs->zfs_trampl)(llargs, llbuffer); + } + else { + assert(zfs->zfs_md.ml_name == NULL); + ((_crx_trampoline1_fn)zfs->zfs_trampl)(func, llargs, llbuffer); + } if (returns_void) { Py_INCREF(Py_None); @@ -174,21 +181,61 @@ return convert_to_object(llbuffer, zfs->zfs_ret); } -static PyObject *make_builtin_func(PyObject *libname_obj, - const char *funcname, _crx_type_t *ret, +static PyObject *zfs_call(PyObject *self, PyObject *args) +{ + ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)self; + return common_call(zfs, args, NULL, zfs->zfs_md.ml_name); +} + +static PyObject*cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds) +{ + CTypeDescrObject *ct = cd->c_type->ct_itemdescr; + ZefFuncSupportObject *zfs; + + if (!(cd->c_type->ct_flags & CT_POINTER) || !(ct->ct_flags & CT_FUNCTION)) { + PyErr_Format(PyExc_TypeError, "cdata '%s' is not callable", + cd->c_type->ct_name); + return NULL; + } + + zfs = (ZefFuncSupportObject *)ct->ct_stuff; + if (zfs == NULL) { + PyErr_SetString(ZefError, "cdata '%s' cannot be called, because no " + "wrapper was generated for functions of this type "); + return NULL; + } + + if (kwds != NULL && PyDict_Size(kwds) != 0) { + PyErr_SetString(PyExc_TypeError, + "cdata function pointers cannot be called with keyword arguments"); + return NULL; + } + if (cd->c_data == NULL) { + PyErr_SetString(PyExc_RuntimeError, "cannot call NULL cdata"); + return NULL; + } + + return common_call(zfs, args, cd->c_data, cd->c_type->ct_name); +} + +static PyObject *make_func_support(_crx_type_t *ret, _crx_qual_type args[], int nargs, - _crx_trampoline0_fn trampl) + void *trampl, size_t extra_alloc) { + /* note that 'trampl' is either a '_crx_trampoline0_fn' or a + '_crx_trampoline1_fn', depending on how the ZefFuncSupportObject + is going to be used. + */ int i; - char *p; size_t size = (sizeof(ZefFuncSupportObject) + (nargs - 1) * sizeof(CTypeDescrObject *) - + strlen(funcname) + 1); + + extra_alloc); ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)PyObject_Malloc(size); if (zfs == NULL) return PyErr_NoMemory(); PyObject_Init((PyObject *)zfs, &ZefFuncSupport_Type); + memset(&zfs->zfs_md, 0, sizeof(PyMethodDef)); zfs->zfs_nargs = nargs; zfs->zfs_trampl = trampl; zfs->zfs_ret = ret; @@ -207,9 +254,23 @@ size = ROUND_UP(size) + ct->ct_size; } zfs->zfs_size_args = size; + + return (PyObject *)zfs; +} + +static PyObject *make_builtin_func(PyObject *libname_obj, + const char *funcname, _crx_type_t *ret, + _crx_qual_type args[], int nargs, + _crx_trampoline0_fn trampl) +{ + char *p; + ZefFuncSupportObject *zfs; + zfs = (ZefFuncSupportObject *)make_func_support(ret, args, nargs, trampl, + strlen(funcname) + 1); + if (zfs == NULL) + return NULL; + p = (char *)(zfs->zfs_args + nargs); - - memset(&zfs->zfs_md, 0, sizeof(PyMethodDef)); zfs->zfs_md.ml_name = strcpy(p, funcname); zfs->zfs_md.ml_meth = &zfs_call; zfs->zfs_md.ml_flags = METH_VARARGS; diff --git a/zeffir/ctype.c b/zeffir/ctype.c --- a/zeffir/ctype.c +++ b/zeffir/ctype.c @@ -31,11 +31,10 @@ CTypeDescrObject *ct_itemdescr; /* ptrs and arrays: the item type */ PyObject *ct_stuff; /* structs: dict of the fields arrays: ctypedescr of the ptr type - function: tuple(abi, ctres, ctargs..) + functions: ZefFuncSupportObject enum: pair {"name":x},{x:"name"} ptrs: lazily, ctypedescr of array */ - void *ct_extra; /* structs: first field (not a ref!) - function types: cif_description */ + CFieldObject *ct_fields; /* structs: first field (not a ref!) */ PyObject *ct_weakreflist; /* weakref support */ diff --git a/zeffir/ffi_obj.c b/zeffir/ffi_obj.c --- a/zeffir/ffi_obj.c +++ b/zeffir/ffi_obj.c @@ -177,7 +177,14 @@ static PyObject *ffi_typeof(ZefFFIObject *self, PyObject *arg) { PyObject *x = (PyObject *)_ffi_type(self, arg, ACCEPT_STRING|ACCEPT_CDATA); - Py_XINCREF(x); + if (x != NULL) { + Py_INCREF(x); + } + else if (PyCFunction_Check(arg)) { + PyErr_SetString(PyExc_TypeError, "typeof(lib.func) not supported: the " + "exact type of functions is unknown (declare that " + "function as a function pointer instead)"); + } return x; } @@ -446,7 +453,7 @@ else reason = "numeric constants don't have addresses"; - PyErr_Format(PyExc_NotImplementedError, + PyErr_Format(PyExc_TypeError, "cannot take the address of '%s' (%s)", fieldname, reason); return NULL; diff --git a/zeffir/test/funcptr.crx b/zeffir/test/funcptr.crx new file mode 100644 --- /dev/null +++ b/zeffir/test/funcptr.crx @@ -0,0 +1,24 @@ +int add_1(int x) +{ + return x + 1; +} + +int add_42(int x) +{ + return x + 42; +} + +int (*get_fnptr(int target))(int) +{ + if (target == 42) + return add_42; + else + return add_1; +} + + +// CREFLECT: start + +int (*get_fnptr(int target))(int); + +// CREFLECT: end diff --git a/zeffir/test/test_funcptr.py b/zeffir/test/test_funcptr.py new file mode 100644 --- /dev/null +++ b/zeffir/test/test_funcptr.py @@ -0,0 +1,31 @@ +import py +import support + + +def test_cannot_call_nonfunc(): + ffi = support.new_ffi() + x = ffi.new("int *", 42) + py.test.raises(TypeError, x) + +def test_cannot_call_unprepared_func_type(): + ffi = support.new_ffi() + x = ffi.cast("int(*)(int)", 42) + py.test.raises(ffi.error, x) + +def test_get_fnptr(): + ffi, lib = support.compile_and_open('funcptr') + fn = lib.get_fnptr(42) + assert fn(100) == 142 + assert ffi.typeof(fn) == ffi.typeof("int(*)(int)") + # + e = py.test.raises(TypeError, fn, 100, 200) + assert str(e.value) == "'int(*)(int)' expected 1 arguments, but got 2" + e = py.test.raises(TypeError, fn, foobar=42) + assert str(e.value) == ("cdata function pointers cannot be called " + "with keyword arguments") + +def test_cannot_call_null(): + ffi, lib = support.compile_and_open('funcptr') + fn = lib.get_fnptr(42) + fn = ffi.cast(ffi.typeof(fn), 0) + py.test.raises(RuntimeError, fn, 100) diff --git a/zeffir/test/test_function.py b/zeffir/test/test_function.py --- a/zeffir/test/test_function.py +++ b/zeffir/test/test_function.py @@ -7,6 +7,9 @@ res = lib.simple_function(42) assert type(res) is int assert res == 43 + # + e = py.test.raises(TypeError, lib.simple_function, foobar=42) + assert str(e.value) == "simple_function() takes no keyword arguments" def test_function_with_pointer_arg(): ffi, lib = support.compile_and_open('function') @@ -29,4 +32,11 @@ def test_addressof_function(): ffi, lib = support.compile_and_open('function') - py.test.raises(NotImplementedError, ffi.addressof, lib, 'simple_function') + py.test.raises(TypeError, ffi.addressof, lib, 'simple_function') + +def test_typeof_function(): + ffi, lib = support.compile_and_open('function') + e = py.test.raises(TypeError, ffi.typeof, lib.simple_function) + assert str(e.value) == ("typeof(lib.func) not supported: the " + "exact type of functions is unknown (declare that " + "function as a function pointer instead)") diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h --- a/zeffir/zeffir.h +++ b/zeffir/zeffir.h @@ -29,3 +29,4 @@ size_t extra_text_len); static PyObject *gc_weakrefs_build(ZefFFIObject *ffi, CDataObject *cd, PyObject *destructor); +static PyObject*cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds); From noreply at buildbot.pypy.org Sat Dec 6 19:42:31 2014 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 6 Dec 2014 19:42:31 +0100 (CET) Subject: [pypy-commit] creflect default: fix asserts Message-ID: <20141206184231.448A11C13BD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r189:08d9551d66e1 Date: 2014-12-06 19:42 +0100 http://bitbucket.org/cffi/creflect/changeset/08d9551d66e1/ Log: fix asserts diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -522,7 +522,6 @@ if (interned_fields == NULL) return; - assert(ct->ct_fields == NULL); previous = &ct->ct_fields; for (i = 0; i < nfields; i++) { diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -781,6 +781,7 @@ return 0; } if (ct->ct_flags & (CT_STRUCT|CT_UNION)) { + assert(ct->ct_size >= 0); if (CData_Check(init)) { if (((CDataObject *)init)->c_type == ct && ct->ct_size >= 0) { From noreply at buildbot.pypy.org Sat Dec 6 20:11:06 2014 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 6 Dec 2014 20:11:06 +0100 (CET) Subject: [pypy-commit] creflect default: port more from _cffi_backend Message-ID: <20141206191106.9B6B21C07E8@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r190:4f6dbe2e4bdc Date: 2014-12-06 20:11 +0100 http://bitbucket.org/cffi/creflect/changeset/4f6dbe2e4bdc/ Log: port more from _cffi_backend diff --git a/zeffir/builder.c b/zeffir/builder.c --- a/zeffir/builder.c +++ b/zeffir/builder.c @@ -224,15 +224,21 @@ ct->ct_size = -1; ct->ct_flags = CT_FUNCTION; + ct->ct_stuff = make_func_support(ret, args, nargs, dotdotdot, 0); + if (ct->ct_stuff == NULL) { + Py_DECREF(ct); + ct = NULL; + goto done; + } put_cached_type(get_types_dict(cb), name_obj, ct); done: Py_DECREF(name_obj); - if (ct->ct_stuff == NULL && trampl != NULL && !PyErr_Occurred()) { + if (!PyErr_Occurred() && trampl != NULL) { assert(!dotdotdot); /* should have 'trampl == NULL' in this case */ - ct->ct_stuff = make_func_support(ret, args, nargs, trampl, 0); + provide_trampoline(ct->ct_stuff, trampl); } return ct; } diff --git a/zeffir/cdata.c b/zeffir/cdata.c --- a/zeffir/cdata.c +++ b/zeffir/cdata.c @@ -1903,3 +1903,40 @@ Py_TYPE(ob)->tp_name, ct->ct_name); return NULL; } + +static PyObject *get_field_name(CTypeDescrObject *ct, CFieldObject *cf) +{ + Py_ssize_t i = 0; + PyObject *d_key, *d_value; + while (PyDict_Next(ct->ct_stuff, &i, &d_key, &d_value)) { + if (d_value == (PyObject *)cf) + return d_key; + } + Py_FatalError("_cffi_backend: get_field_name()"); + return NULL; +} + +static PyObject *cstructtype_getfields(CTypeDescrObject *ct) +{ + if (ct->ct_size >= 0) { + CFieldObject *cf; + PyObject *res = PyList_New(0); + if (res == NULL) + return NULL; + for (cf = ct->ct_fields; cf != NULL; cf = cf->cf_next) { + PyObject *o = PyTuple_Pack(2, get_field_name(ct, cf), + (PyObject *)cf); + int err = (o != NULL) ? PyList_Append(res, o) : -1; + Py_XDECREF(o); + if (err < 0) { + Py_DECREF(res); + return NULL; + } + } + return res; + } + else { + Py_INCREF(Py_None); + return Py_None; + } +} diff --git a/zeffir/cfunc.c b/zeffir/cfunc.c --- a/zeffir/cfunc.c +++ b/zeffir/cfunc.c @@ -2,7 +2,12 @@ typedef struct { PyObject_HEAD + /* note that 'zfs_trampl' is either a '_crx_trampoline0_fn' or a + '_crx_trampoline1_fn', depending on how the ZefFuncSupportObject + is going to be used. + */ int zfs_nargs; + int zfs_dotdotdot; void *zfs_trampl; PyMethodDef zfs_md; size_t zfs_size_args; @@ -199,7 +204,7 @@ } zfs = (ZefFuncSupportObject *)ct->ct_stuff; - if (zfs == NULL) { + if (zfs->zfs_trampl == NULL) { PyErr_SetString(ZefError, "cdata '%s' cannot be called, because no " "wrapper was generated for functions of this type "); return NULL; @@ -220,12 +225,8 @@ static PyObject *make_func_support(_crx_type_t *ret, _crx_qual_type args[], int nargs, - void *trampl, size_t extra_alloc) + int dotdotdot, size_t extra_alloc) { - /* note that 'trampl' is either a '_crx_trampoline0_fn' or a - '_crx_trampoline1_fn', depending on how the ZefFuncSupportObject - is going to be used. - */ int i; size_t size = (sizeof(ZefFuncSupportObject) + (nargs - 1) * sizeof(CTypeDescrObject *) @@ -236,8 +237,9 @@ PyObject_Init((PyObject *)zfs, &ZefFuncSupport_Type); memset(&zfs->zfs_md, 0, sizeof(PyMethodDef)); + zfs->zfs_trampl = NULL; zfs->zfs_nargs = nargs; - zfs->zfs_trampl = trampl; + zfs->zfs_dotdotdot = dotdotdot; zfs->zfs_ret = ret; Py_INCREF(ret); @@ -258,6 +260,13 @@ return (PyObject *)zfs; } +static void provide_trampoline(PyObject *zfs, void *trampl) +{ + if (((ZefFuncSupportObject *)zfs)->zfs_trampl == NULL) { + ((ZefFuncSupportObject *)zfs)->zfs_trampl = trampl; + } +} + static PyObject *make_builtin_func(PyObject *libname_obj, const char *funcname, _crx_type_t *ret, _crx_qual_type args[], int nargs, @@ -265,11 +274,13 @@ { char *p; ZefFuncSupportObject *zfs; - zfs = (ZefFuncSupportObject *)make_func_support(ret, args, nargs, trampl, + zfs = (ZefFuncSupportObject *)make_func_support(ret, args, nargs, 0, strlen(funcname) + 1); if (zfs == NULL) return NULL; + zfs->zfs_trampl = trampl; + p = (char *)(zfs->zfs_args + nargs); zfs->zfs_md.ml_name = strcpy(p, funcname); zfs->zfs_md.ml_meth = &zfs_call; @@ -281,3 +292,33 @@ Py_DECREF(zfs); return res; } + +static PyObject *cfunctype_getargs(CTypeDescrObject *ct) +{ + ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)ct->ct_stuff; + int i; + PyObject *tup = PyTuple_New(zfs->zfs_nargs); + if (tup == NULL) + return NULL; + + for (i = 0; i < zfs->zfs_nargs; i++) { + PyObject *obj = (PyObject *)zfs->zfs_args[i]; + Py_INCREF(obj); + PyTuple_SET_ITEM(tup, i, obj); + } + return tup; +} + +static PyObject *cfunctype_getresult(CTypeDescrObject *ct) +{ + ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)ct->ct_stuff; + PyObject *res = (PyObject *)zfs->zfs_ret; + Py_INCREF(res); + return res; +} + +static PyObject *cfunctype_getellipsis(CTypeDescrObject *ct) +{ + ZefFuncSupportObject *zfs = (ZefFuncSupportObject *)ct->ct_stuff; + return PyBool_FromLong(zfs->zfs_dotdotdot); +} diff --git a/zeffir/ctype.c b/zeffir/ctype.c --- a/zeffir/ctype.c +++ b/zeffir/ctype.c @@ -102,6 +102,176 @@ return 0; } + +static PyObject *nosuchattr(const char *attr) +{ + PyErr_SetString(PyExc_AttributeError, attr); + return NULL; +} + +static PyObject *ctypeget_kind(CTypeDescrObject *ct, void *context) +{ + char *result; + if (ct->ct_flags & CT_PRIMITIVE_ANY) { + if (ct->ct_flags & CT_IS_ENUM) + result = "enum"; + else + result = "primitive"; + } + else if (ct->ct_flags & CT_POINTER) { + result = "pointer"; + } + else if (ct->ct_flags & CT_ARRAY) { + result = "array"; + } + else if (ct->ct_flags & CT_VOID) { + result = "void"; + } + else if (ct->ct_flags & CT_STRUCT) { + result = "struct"; + } + else if (ct->ct_flags & CT_UNION) { + result = "union"; + } + else if (ct->ct_flags & CT_FUNCTION) { + result = "function"; + } + else if (ct->ct_flags & CT_UNKNOWN) { + result = "opaque"; + } + else + result = "?"; + + return PyText_FromString(result); +} + +static PyObject *ctypeget_cname(CTypeDescrObject *ct, void *context) +{ + return PyText_FromString(ct->ct_name); +} + +static PyObject *ctypeget_item(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & (CT_POINTER | CT_ARRAY)) { + Py_INCREF(ct->ct_itemdescr); + return (PyObject *)ct->ct_itemdescr; + } + return nosuchattr("item"); +} + +static PyObject *ctypeget_length(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_ARRAY) { + if (ct->ct_length >= 0) { + return PyInt_FromSsize_t(ct->ct_length); + } + else { + Py_INCREF(Py_None); + return Py_None; + } + } + return nosuchattr("length"); +} + +static PyObject *ctypeget_fields(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & (CT_STRUCT | CT_UNION)) { + return cstructtype_getfields(ct); + } + return nosuchattr("fields"); +} + +static PyObject *ctypeget_args(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_FUNCTION) { + return cfunctype_getargs(ct); + } + return nosuchattr("args"); +} + +static PyObject *ctypeget_result(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_FUNCTION) { + return cfunctype_getresult(ct); + } + return nosuchattr("result"); +} + +static PyObject *ctypeget_ellipsis(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_FUNCTION) { + return cfunctype_getellipsis(ct); + } + return nosuchattr("ellipsis"); +} + +static PyObject *ctypeget_elements(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_IS_ENUM) { + PyObject *res = PyTuple_GetItem(ct->ct_stuff, 1); + if (res) res = PyDict_Copy(res); + return res; + } + return nosuchattr("elements"); +} + +static PyObject *ctypeget_relements(CTypeDescrObject *ct, void *context) +{ + if (ct->ct_flags & CT_IS_ENUM) { + PyObject *res = PyTuple_GetItem(ct->ct_stuff, 0); + if (res) res = PyDict_Copy(res); + return res; + } + return nosuchattr("relements"); +} + +static PyGetSetDef ctypedescr_getsets[] = { + {"kind", (getter)ctypeget_kind, NULL, "kind"}, + {"cname", (getter)ctypeget_cname, NULL, "C name"}, + {"item", (getter)ctypeget_item, NULL, "pointer to, or array of"}, + {"length", (getter)ctypeget_length, NULL, "array length or None"}, + {"fields", (getter)ctypeget_fields, NULL, "struct or union fields"}, + {"args", (getter)ctypeget_args, NULL, "function argument types"}, + {"result", (getter)ctypeget_result, NULL, "function result type"}, + {"ellipsis", (getter)ctypeget_ellipsis, NULL, "function has '...'"}, + {"elements", (getter)ctypeget_elements, NULL, "enum elements"}, + {"relements", (getter)ctypeget_relements, NULL, "enum elements, reverse"}, + {NULL} /* sentinel */ +}; + +static PyObject * +ctypedescr_dir(PyObject *ct, PyObject *noarg) +{ + int err; + struct PyGetSetDef *gsdef; + PyObject *res = PyList_New(0); + if (res == NULL) + return NULL; + + for (gsdef = ctypedescr_getsets; gsdef->name; gsdef++) { + PyObject *x = PyObject_GetAttrString(ct, gsdef->name); + if (x == NULL) { + PyErr_Clear(); + } + else { + Py_DECREF(x); + x = PyText_FromString(gsdef->name); + err = (x != NULL) ? PyList_Append(res, x) : -1; + Py_XDECREF(x); + if (err < 0) { + Py_DECREF(res); + return NULL; + } + } + } + return res; +} + +static PyMethodDef ctypedescr_methods[] = { + {"__dir__", ctypedescr_dir, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + static PyTypeObject CTypeDescr_Type = { PyVarObject_HEAD_INIT(NULL, 0) "zeffir.CType", @@ -130,7 +300,7 @@ offsetof(CTypeDescrObject, ct_weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - 0,//ctypedescr_methods, /* tp_methods */ + ctypedescr_methods, /* tp_methods */ 0, /* tp_members */ - 0,//ctypedescr_getsets, /* tp_getset */ + ctypedescr_getsets, /* tp_getset */ }; diff --git a/zeffir/test/test_c.py b/zeffir/test/test_c.py new file mode 100644 --- /dev/null +++ b/zeffir/test/test_c.py @@ -0,0 +1,57 @@ +import py +import support + +import sys +if sys.version_info < (3,): + type_or_class = "type" + mandatory_b_prefix = '' + mandatory_u_prefix = 'u' + bytechr = chr + bitem2bchr = lambda x: x + class U(object): + def __add__(self, other): + return eval('u'+repr(other).replace(r'\\u', r'\u') + .replace(r'\\U', r'\U')) + u = U() + str2bytes = str +else: + type_or_class = "class" + long = int + unicode = str + unichr = chr + mandatory_b_prefix = 'b' + mandatory_u_prefix = '' + bytechr = lambda n: bytes([n]) + bitem2bchr = bytechr + u = "" + str2bytes = lambda s: bytes(s, "ascii") + +def size_of_int(): + ffi = support.new_ffi() + return ffi.sizeof("int") + +def size_of_long(): + ffi = support.new_ffi() + return ffi.sizeof("long") + +def size_of_ptr(): + ffi = support.new_ffi() + return ffi.sizeof("void*") + + +def test_new_primitive_type(): + ffi = support.new_ffi() + py.test.raises(ffi.error, ffi.typeof, "foo") + p = ffi.typeof("signed char") + assert repr(p) == "" + +def check_dir(p, expected): + got = set(name for name in dir(p) if not name.startswith('_')) + assert got == set(expected) + +def test_inspect_primitive_type(): + ffi = support.new_ffi() + p = ffi.typeof("signed char") + assert p.kind == "primitive" + assert p.cname == "signed char" + check_dir(p, ['cname', 'kind']) diff --git a/zeffir/zeffir.h b/zeffir/zeffir.h --- a/zeffir/zeffir.h +++ b/zeffir/zeffir.h @@ -29,4 +29,8 @@ size_t extra_text_len); static PyObject *gc_weakrefs_build(ZefFFIObject *ffi, CDataObject *cd, PyObject *destructor); -static PyObject*cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds); +static PyObject *cdata_call(CDataObject *cd, PyObject *args, PyObject *kwds); +static PyObject *cfunctype_getargs(CTypeDescrObject *ct); +static PyObject *cfunctype_getresult(CTypeDescrObject *ct); +static PyObject *cfunctype_getellipsis(CTypeDescrObject *ct); +static PyObject *cstructtype_getfields(CTypeDescrObject *ct); From noreply at buildbot.pypy.org Sat Dec 6 21:03:24 2014 From: noreply at buildbot.pypy.org (bdkearns) Date: Sat, 6 Dec 2014 21:03:24 +0100 (CET) Subject: [pypy-commit] pypy default: adjust test_zjit func name for clarity Message-ID: <20141206200324.7644E1D2324@cobra.cs.uni-duesseldorf.de> Author: Brian Kearns Branch: Changeset: r74852:b797c990f775 Date: 2014-12-06 15:03 -0500 http://bitbucket.org/pypy/pypy/changeset/b797c990f775/ Log: adjust test_zjit func name for clarity diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -33,9 +33,9 @@ pass -SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any", "xor", +SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any", "unegative", "flat", "tostring", "count_nonzero", - "argsort", "cumsum"] + "argsort", "cumsum", "logical_xor_reduce"] TWO_ARG_FUNCTIONS = ["dot", 'take', 'searchsorted'] TWO_ARG_FUNCTIONS_OR_NONE = ['view', 'astype'] THREE_ARG_FUNCTIONS = ['where'] @@ -561,9 +561,9 @@ w_res = arr.descr_all(interp.space) elif self.name == "cumsum": w_res = arr.descr_cumsum(interp.space) - elif self.name == "xor": - xor = ufuncs.get(interp.space).logical_xor - w_res = xor.reduce(interp.space, arr, None) + elif self.name == "logical_xor_reduce": + logical_xor = ufuncs.get(interp.space).logical_xor + w_res = logical_xor.reduce(interp.space, arr, None) elif self.name == "unegative": neg = ufuncs.get(interp.space).negative w_res = neg.call(interp.space, [arr]) diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py --- a/pypy/module/micronumpy/test/test_zjit.py +++ b/pypy/module/micronumpy/test/test_zjit.py @@ -416,7 +416,7 @@ def define_logical_xor_reduce(): return """ a = [1,1,1,1,1,1,1,1] - xor(a) + logical_xor_reduce(a) """ def test_logical_xor_reduce(self): From noreply at buildbot.pypy.org Sat Dec 6 21:40:21 2014 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 6 Dec 2014 21:40:21 +0100 (CET) Subject: [pypy-commit] creflect default: enums Message-ID: <20141206204021.938991C13BD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r192:d43293d10be7 Date: 2014-12-06 21:40 +0100 http://bitbucket.org/cffi/creflect/changeset/d43293d10be7/ Log: enums diff --git a/creflect/cparser.py b/creflect/cparser.py --- a/creflect/cparser.py +++ b/creflect/cparser.py @@ -256,7 +256,7 @@ def get_struct_union_enum_type(self, kind, type, approx_name=None): name = type.name or approx_name - if not name or name.startswith('$$$'): + if kind != 'enum' and (not name or name.startswith('$$$')): self.parse_error("not implemented: anonymous 'struct' elsewhere " "than in 'typedef struct { ... } typename;' or " "'typedef struct { ... } *typename;'", type) @@ -270,7 +270,7 @@ if kind == 'struct' or kind == 'union': typedecl = model.StructOrUnionDecl(result) elif kind == 'enum': - typedecl = XXX + typedecl = model.EnumDecl(result) else: raise AssertionError("kind = %r" % (kind,)) self.struct_union_enum_decl[key] = typedecl @@ -280,8 +280,12 @@ # # is there a 'type.decls'? If yes, then this is the place in the # C sources that declare the fields. - if type.decls is not None: - self.add_fields_declaration(typedecl, type.decls) + if kind == 'struct' or kind == 'union': + if type.decls is not None: + self.add_fields_declaration(typedecl, type.decls) + if kind == 'enum': + if type.values is not None: + self.add_enum_values_declaration(typedecl, type.values) if must_add: self.declarations.append(typedecl) return result @@ -312,6 +316,13 @@ raise NotImplementedError("%s: using both bitfields and '...;'" % (tp,)) + def add_enum_values_declaration(self, typedecl, values): + for enumerator in values.enumerators: + self.declarations.append( + model.ConstDecl(enumerator.name, + model.QualType(model.int_type))) + typedecl.complete = True + def parse_constant(self, constant): return int(constant.value) # xxx diff --git a/creflect/creflect_debug_print.c b/creflect/creflect_debug_print.c --- a/creflect/creflect_debug_print.c +++ b/creflect/creflect_debug_print.c @@ -202,7 +202,8 @@ static void tst_complete_enum(_crx_builder_t *cb, _crx_type_t *t, _crx_type_t *inttype) { - abort(); + assert(memcmp(t->text, "ENUM ", 5) == 0); + printf("%s = %s\n", t->text, inttype->text); } static void tst_define_type(_crx_builder_t *cb, const char *name, diff --git a/creflect/model.py b/creflect/model.py --- a/creflect/model.py +++ b/creflect/model.py @@ -249,6 +249,8 @@ block.writeline('cb->define_num_const(cb, "%s", %s, &v);' % ( varname, t1)) +int_type = PrimitiveType('int') + class FunctionType(BaseType): _attrs_ = ('args', 'result', 'ellipsis') @@ -730,6 +732,40 @@ funcblock.writeline(' %s, %d);' % (d1, len(self.fldnames))) +class EnumDecl(object): + + def __init__(self, type): + self.type = type + self.complete = False + + def write_declaration(self, funcblock): + if not self.complete or self.type.name is None: + return # opaque + tp = "%s %s" % (self.type.kind, self.type.name) + block = CodeBlock(funcblock) + if not self.type.name.startswith('$'): + realtp = tp + else: + realtp = self.type.name[1:] + if not realtp.startswith('$'): + expr = '(%s)-1' % realtp + else: + # xxx obscure case: "typedef enum e *t;" + ptrtp = realtp[1:] + assert not ptrtp.startswith('$') + block.writedecl("%s p1;" % (ptrtp,)) + block.writedecl("char b[sizeof(*p1)];") + block.writeline("memset(b, -1, sizeof(b));") + block.writeline("p1 = (%s)b;" % (ptrtp,)) + expr = '*p1' + # + t1 = self.type.get_type_var(block) + t2 = block.write_crx_type_var('_CRX_INT_TYPE(cb, %s, _crx_sc_int)' % + (expr,)) + block.writeline('cb->complete_enum(cb, %s, %s);' % (t1, t2)) + funcblock.write_subblock(block) + + class TypeDefDecl(object): def __init__(self, name, qualtype): self.name = name diff --git a/creflect/test/codegen/enum-001.c b/creflect/test/codegen/enum-001.c new file mode 100644 --- /dev/null +++ b/creflect/test/codegen/enum-001.c @@ -0,0 +1,13 @@ +typedef enum myname_e foo_t; // unusual, but valid C + +# ____________________________________________________________ + +void testenum_001(_crx_builder_t *cb) +{ + _crx_type_t *t1; + { + t1 = cb->get_enum_type(cb, "myname_e"); + cb->define_type(cb, "foo_t", t1, 0); +#expect TYPEDEF foo_t = ENUM myname_e + } +} diff --git a/creflect/test/codegen/enum-002.c b/creflect/test/codegen/enum-002.c new file mode 100644 --- /dev/null +++ b/creflect/test/codegen/enum-002.c @@ -0,0 +1,22 @@ +enum { AA, BB }; /* anonymous */ + +# ____________________________________________________________ + +void testenum_002(_crx_builder_t *cb) +{ + _crx_type_t *t1, *t2; + { + _crx_num_const_t v; + (void)((AA) << 1); /* check that 'AA' is an integer */ + t1 = _CRX_INT_CONST(cb, AA, &v, 1); + cb->define_num_const(cb, "AA", t1, &v); +#expect NUMCONST AA = int 0 + } + { + _crx_num_const_t v; + (void)((BB) << 1); /* check that 'BB' is an integer */ + t2 = _CRX_INT_CONST(cb, BB, &v, 1); + cb->define_num_const(cb, "BB", t2, &v); +#expect NUMCONST BB = int 1 + } +} diff --git a/creflect/test/codegen/enum-002b.c b/creflect/test/codegen/enum-002b.c new file mode 100644 --- /dev/null +++ b/creflect/test/codegen/enum-002b.c @@ -0,0 +1,28 @@ + +enum { AA=(10+10), BB=-4 }; + +# ____________________________________________________________ + +#define AA 100 +#define BB 200 + +# ____________________________________________________________ + +void testenum_002b(_crx_builder_t *cb) +{ + _crx_type_t *t1, *t2; + { + _crx_num_const_t v; + (void)((AA) << 1); /* check that 'AA' is an integer */ + t1 = _CRX_INT_CONST(cb, AA, &v, 1); + cb->define_num_const(cb, "AA", t1, &v); +#expect NUMCONST AA = int 100 + } + { + _crx_num_const_t v; + (void)((BB) << 1); /* check that 'BB' is an integer */ + t2 = _CRX_INT_CONST(cb, BB, &v, 1); + cb->define_num_const(cb, "BB", t2, &v); +#expect NUMCONST BB = int 200 + } +} diff --git a/creflect/test/codegen/enum-003.c b/creflect/test/codegen/enum-003.c new file mode 100644 --- /dev/null +++ b/creflect/test/codegen/enum-003.c @@ -0,0 +1,23 @@ +enum myname_e { AA }; +/* note that with GCC, "enum myname_e" is equivalent to "unsigned int", + but AA itself is a constant of type "int", obscurely */ + +# ____________________________________________________________ + +void testenum_003(_crx_builder_t *cb) +{ + _crx_type_t *t1, *t2, *t3; + { + _crx_num_const_t v; + (void)((AA) << 1); /* check that 'AA' is an integer */ + t1 = _CRX_INT_CONST(cb, AA, &v, 1); + cb->define_num_const(cb, "AA", t1, &v); +#expect NUMCONST AA = int 0 + } + { + t2 = cb->get_enum_type(cb, "myname_e"); + t3 = _CRX_INT_TYPE(cb, (enum myname_e)-1, _crx_sc_int); + cb->complete_enum(cb, t2, t3); +#expect ENUM myname_e = unsigned int + } +} diff --git a/creflect/test/codegen/enum-003b.c b/creflect/test/codegen/enum-003b.c new file mode 100644 --- /dev/null +++ b/creflect/test/codegen/enum-003b.c @@ -0,0 +1,28 @@ +enum myname_e { AA=0x80000000U, BB=3U }; + +# ____________________________________________________________ + +void testenum_003b(_crx_builder_t *cb) +{ + _crx_type_t *t1, *t2, *t3, *t4; + { + _crx_num_const_t v; + (void)((AA) << 1); /* check that 'AA' is an integer */ + t1 = _CRX_INT_CONST(cb, AA, &v, 1); + cb->define_num_const(cb, "AA", t1, &v); +#expect NUMCONST AA = unsigned int 2147483648 + } + { + _crx_num_const_t v; + (void)((BB) << 1); /* check that 'BB' is an integer */ + t2 = _CRX_INT_CONST(cb, BB, &v, 1); + cb->define_num_const(cb, "BB", t2, &v); +#expect NUMCONST BB = int 3 + } + { + t3 = cb->get_enum_type(cb, "myname_e"); + t4 = _CRX_INT_TYPE(cb, (enum myname_e)-1, _crx_sc_int); + cb->complete_enum(cb, t3, t4); +#expect ENUM myname_e = unsigned int + } +} diff --git a/creflect/test/codegen/enum-003c.c b/creflect/test/codegen/enum-003c.c new file mode 100644 --- /dev/null +++ b/creflect/test/codegen/enum-003c.c @@ -0,0 +1,21 @@ +enum myname_e { AA=-3L }; + +# ____________________________________________________________ + +void testenum_003c(_crx_builder_t *cb) +{ + _crx_type_t *t1, *t2, *t3; + { + _crx_num_const_t v; + (void)((AA) << 1); /* check that 'AA' is an integer */ + t1 = _CRX_INT_CONST(cb, AA, &v, 1); + cb->define_num_const(cb, "AA", t1, &v); +#expect NUMCONST AA = int -3 + } + { + t2 = cb->get_enum_type(cb, "myname_e"); + t3 = _CRX_INT_TYPE(cb, (enum myname_e)-1, _crx_sc_int); + cb->complete_enum(cb, t2, t3); +#expect ENUM myname_e = int + } +} diff --git a/creflect/test/codegen/enum-004.c b/creflect/test/codegen/enum-004.c new file mode 100644 --- /dev/null +++ b/creflect/test/codegen/enum-004.c @@ -0,0 +1,34 @@ +typedef enum { AA } *foo_t; + +# ____________________________________________________________ + +void testenum_004(_crx_builder_t *cb) +{ + _crx_type_t *t1, *t2, *t3, *t4; + { + _crx_num_const_t v; + (void)((AA) << 1); /* check that 'AA' is an integer */ + t1 = _CRX_INT_CONST(cb, AA, &v, 1); + cb->define_num_const(cb, "AA", t1, &v); +#expect NUMCONST AA = int 0 + } + { + foo_t p1; + char b[sizeof(*p1)]; + memset(b, -1, sizeof(b)); + p1 = (foo_t)b; + t2 = cb->get_enum_type(cb, "$$foo_t"); + t3 = _CRX_INT_TYPE(cb, *p1, _crx_sc_int); + cb->complete_enum(cb, t2, t3); +#expect ENUM $$foo_t = unsigned int + } + { + foo_t *p1; + char *p2; + p1 = (void *)&p2; + *p1 = (void *)0; /* check that 'foo_t' is a pointer type */ + t4 = cb->get_pointer_type(cb, t2, 0); + cb->define_type(cb, "foo_t", t4, 0); +#expect TYPEDEF foo_t = PTR ENUM $$foo_t + } +} From noreply at buildbot.pypy.org Sat Dec 6 21:40:20 2014 From: noreply at buildbot.pypy.org (arigo) Date: Sat, 6 Dec 2014 21:40:20 +0100 (CET) Subject: [pypy-commit] creflect default: Declare opaque structs Message-ID: <20141206204020.82D441C13BD@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r191:1471bfadbc0f Date: 2014-12-06 20:25 +0100 http://bitbucket.org/cffi/creflect/changeset/1471bfadbc0f/ Log: Declare opaque structs diff --git a/creflect/model.py b/creflect/model.py --- a/creflect/model.py +++ b/creflect/model.py @@ -659,6 +659,8 @@ self.fldbitsize = None def write_declaration(self, funcblock): + if self.fldnames is None: + return # opaque tp = "%s %s" % (self.type.kind, self.type.name) if not self.type.name.startswith('$'): realtp = tp diff --git a/creflect/test/codegen/struct-007.c b/creflect/test/codegen/struct-007.c new file mode 100644 --- /dev/null +++ b/creflect/test/codegen/struct-007.c @@ -0,0 +1,13 @@ +typedef struct mystruct_s foo_t; + +# ____________________________________________________________ + +void teststruct_007(_crx_builder_t *cb) +{ + _crx_type_t *t1; + { + t1 = cb->get_struct_type(cb, "mystruct_s"); + cb->define_type(cb, "foo_t", t1, 0); +#expect TYPEDEF foo_t = STRUCT mystruct_s + } +} From noreply at buildbot.pypy.org Sun Dec 7 05:10:46 2014 From: noreply at buildbot.pypy.org (alex_gaynor) Date: Sun, 7 Dec 2014 05:10:46 +0100 (CET) Subject: [pypy-commit] pypy default: Support building on systems with no ssl3 Message-ID: <20141207041046.2ADE71C13F5@cobra.cs.uni-duesseldorf.de> Author: Alex Gaynor Branch: Changeset: r74853:de9938702e0c Date: 2014-12-06 20:10 -0800 http://bitbucket.org/pypy/pypy/changeset/de9938702e0c/ Log: Support building on systems with no ssl3 diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -52,7 +52,8 @@ if not OPENSSL_NO_SSL2: constants["PROTOCOL_SSLv2"] = PY_SSL_VERSION_SSL2 -constants["PROTOCOL_SSLv3"] = PY_SSL_VERSION_SSL3 +if not OPENSSL_NO_SSL3: + constants["PROTOCOL_SSLv3"] = PY_SSL_VERSION_SSL3 constants["PROTOCOL_SSLv23"] = PY_SSL_VERSION_SSL23 constants["PROTOCOL_TLSv1"] = PY_SSL_VERSION_TLS1 @@ -656,7 +657,7 @@ # set up context if protocol == PY_SSL_VERSION_TLS1: method = libssl_TLSv1_method() - elif protocol == PY_SSL_VERSION_SSL3: + elif protocol == PY_SSL_VERSION_SSL3 and not OPENSSL_NO_SSL3: method = libssl_SSLv3_method() elif protocol == PY_SSL_VERSION_SSL2 and not OPENSSL_NO_SSL2: method = libssl_SSLv2_method() diff --git a/rpython/rlib/ropenssl.py b/rpython/rlib/ropenssl.py --- a/rpython/rlib/ropenssl.py +++ b/rpython/rlib/ropenssl.py @@ -68,6 +68,7 @@ SSLEAY_VERSION = rffi_platform.DefinedConstantString( "SSLEAY_VERSION", "SSLeay_version(SSLEAY_VERSION)") OPENSSL_NO_SSL2 = rffi_platform.Defined("OPENSSL_NO_SSL2") + OPENSSL_NO_SSL3 = rffi_platform.Defined("OPENSSL_NO_SSL3") SSL_FILETYPE_PEM = rffi_platform.ConstantInteger("SSL_FILETYPE_PEM") SSL_OP_ALL = rffi_platform.ConstantInteger("SSL_OP_ALL") SSL_OP_NO_SSLv2 = rffi_platform.ConstantInteger("SSL_OP_NO_SSLv2") From noreply at buildbot.pypy.org Sun Dec 7 11:18:16 2014 From: noreply at buildbot.pypy.org (arigo) Date: Sun, 7 Dec 2014 11:18:16 +0100 (CET) Subject: [pypy-commit] creflect default: avoid generating tons of 'a%d[n]' local variables if we declare tons Message-ID: <20141207101816.E00121C33E2@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r193:94b9f2a44589 Date: 2014-12-07 11:18 +0100 http://bitbucket.org/cffi/creflect/changeset/94b9f2a44589/ Log: avoid generating tons of 'a%d[n]' local variables if we declare tons of functions with the same argument types diff --git a/creflect/codegen.py b/creflect/codegen.py --- a/creflect/codegen.py +++ b/creflect/codegen.py @@ -9,12 +9,14 @@ self.crx_type_cache = {} self.crx_qualtype_vars = [] self.crx_field_vars = [] + self.crx_args_cache = {} self.crx_top_level = self else: self.crx_type_vars = parent.crx_type_vars self.crx_type_cache = parent.crx_type_cache self.crx_qualtype_vars = parent.crx_qualtype_vars self.crx_field_vars = parent.crx_field_vars + self.crx_args_cache = parent.crx_args_cache self.crx_top_level = parent.crx_top_level def writedecl(self, line): diff --git a/creflect/model.py b/creflect/model.py --- a/creflect/model.py +++ b/creflect/model.py @@ -271,11 +271,16 @@ def _get_arg_ret_types(self, block): inspect = MissingInspector() t1, q1_ignored = self.result.inspect_type(block, inspect, 0) - a2 = block.write_crx_qualtype_var(len(self.args)) - for i, arg in enumerate(self.args): - t3, q3 = arg.inspect_qualtype(block, inspect) - block.writeline('%s[%d].type = %s;' % (a2, i, t3)) - block.writeline('%s[%d].qualifiers = %s;' % (a2, i, q3)) + all_args = [arg.inspect_qualtype(block, inspect) for arg in self.args] + key = tuple(all_args) + try: + a2 = block.crx_args_cache[key] + except KeyError: + a2 = block.write_crx_qualtype_var(len(self.args)) + block.crx_args_cache[key] = a2 + for i, (t3, q3) in enumerate(all_args): + block.writeline('%s[%d].type = %s;' % (a2, i, t3)) + block.writeline('%s[%d].qualifiers = %s;' % (a2, i, q3)) return t1, a2 def _get_c_call_sequence(self, varname): diff --git a/creflect/test/codegen/func-001b.c b/creflect/test/codegen/func-001b.c --- a/creflect/test/codegen/func-001b.c +++ b/creflect/test/codegen/func-001b.c @@ -39,7 +39,6 @@ _crx_type_t *t1, *t2, *t3; _crx_qual_type a1[1]; _crx_qual_type a2[2]; - _crx_qual_type a3[2]; { t1 = cb->get_unsigned_type(cb, sizeof(unsigned int), "int"); t2 = cb->get_signed_type(cb, sizeof(long), "long"); @@ -58,11 +57,7 @@ #expect FUNC g: int -> int -> long } { - a3[0].type = t3; - a3[0].qualifiers = 0; - a3[1].type = t3; - a3[1].qualifiers = 0; - cb->define_func(cb, "h", t2, a3, 2, &testfunc_001b__c_h, &testfunc_001b__d_h); + cb->define_func(cb, "h", t2, a2, 2, &testfunc_001b__c_h, &testfunc_001b__d_h); #expect FUNC h: int -> int -> long } } diff --git a/creflect/test/codegen/func-005.c b/creflect/test/codegen/func-005.c --- a/creflect/test/codegen/func-005.c +++ b/creflect/test/codegen/func-005.c @@ -28,19 +28,19 @@ t1 = cb->get_void_type(cb); t2 = cb->get_signed_type(cb, sizeof(int), "int"); t3 = cb->get_incomplete_array_type(cb, t2); - a1[0].type = t3; - a1[0].qualifiers = _CRX_CONST; t4 = cb->get_signed_type(cb, sizeof(long), "long"); t5 = cb->get_char_type(cb); - a2[0].type = t5; - a2[0].qualifiers = 0; t6 = cb->get_signed_type(cb, sizeof(short), "short"); - a2[1].type = t6; + a1[0].type = t5; + a1[0].qualifiers = 0; + a1[1].type = t6; + a1[1].qualifiers = 0; + t7 = cb->get_function_type(cb, t4, a1, 2, &testfunc_005__f4); + a2[0].type = t3; + a2[0].qualifiers = _CRX_CONST; + a2[1].type = t7; a2[1].qualifiers = 0; - t7 = cb->get_function_type(cb, t4, a2, 2, &testfunc_005__f4); - a1[1].type = t7; - a1[1].qualifiers = 0; - cb->define_func(cb, "f", t1, a1, 2, &testfunc_005__c_f, &testfunc_005__d_f); + cb->define_func(cb, "f", t1, a2, 2, &testfunc_005__c_f, &testfunc_005__d_f); #expect FUNC f: CONST ARRAY[] int -> FUNC( char -> short -> long ) -> void } } From noreply at buildbot.pypy.org Sun Dec 7 20:56:42 2014 From: noreply at buildbot.pypy.org (fijal) Date: Sun, 7 Dec 2014 20:56:42 +0100 (CET) Subject: [pypy-commit] pypy default: incliude a note Message-ID: <20141207195642.4EF261C0907@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r74854:f680308d914e Date: 2014-12-07 21:56 +0200 http://bitbucket.org/pypy/pypy/changeset/f680308d914e/ Log: incliude a note diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst --- a/pypy/doc/embedding.rst +++ b/pypy/doc/embedding.rst @@ -6,6 +6,10 @@ C. It was developed in collaboration with Roberto De Ioris from the `uwsgi`_ project. The `PyPy uwsgi plugin`_ is a good example of using the embedding API. +**NOTE**: As of 1st of December, PyPy comes with ``--shared`` by default +on linux, linux64 and windows. We will make it the default on all platforms +by the time of the next release. + The first thing that you need is to compile PyPy yourself with the option ``--shared``. We plan to make ``--shared`` the default in the future. Consult the `how to compile PyPy`_ doc for details. This will result in ``libpypy.so`` From noreply at buildbot.pypy.org Mon Dec 8 05:34:23 2014 From: noreply at buildbot.pypy.org (pjenvey) Date: Mon, 8 Dec 2014 05:34:23 +0100 (CET) Subject: [pypy-commit] pypy py3k: fix breakage from default: marshal co_names as str again instead of as Message-ID: <20141208043423.305261D2DFB@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r74855:9314eec351d7 Date: 2014-12-07 20:32 -0800 http://bitbucket.org/pypy/pypy/changeset/9314eec351d7/ Log: fix breakage from default: marshal co_names as str again instead of as unicode. though marshaling as unicode is more correct per cpython3 (applies to various other code object fields too), we'll come back to that later.. diff --git a/pypy/objspace/std/marshal_impl.py b/pypy/objspace/std/marshal_impl.py --- a/pypy/objspace/std/marshal_impl.py +++ b/pypy/objspace/std/marshal_impl.py @@ -329,7 +329,7 @@ m.put_int(x.co_flags) m.atom_str(TYPE_STRING, x.co_code) m.put_tuple_w(TYPE_TUPLE, x.co_consts_w) - m.put_tuple_w(TYPE_TUPLE, x.co_names_w) + _put_str_list(space, m, [space.str_w(w_name) for w_name in x.co_names_w]) _put_str_list(space, m, x.co_varnames) _put_str_list(space, m, x.co_freevars) _put_str_list(space, m, x.co_cellvars) From noreply at buildbot.pypy.org Mon Dec 8 05:34:24 2014 From: noreply at buildbot.pypy.org (pjenvey) Date: Mon, 8 Dec 2014 05:34:24 +0100 (CET) Subject: [pypy-commit] pypy py3k: adapt to py3 Message-ID: <20141208043424.89AAA1D2DFB@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r74856:f91fe709f1b0 Date: 2014-12-07 20:32 -0800 http://bitbucket.org/pypy/pypy/changeset/f91fe709f1b0/ Log: adapt to py3 diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -110,12 +110,11 @@ def intern_if_common_string(space, w_const): # only intern identifier-like strings - if not space.is_w(space.type(w_const), space.w_str): - return w_const - for c in space.str_w(w_const): - if not (c.isalnum() or c == '_'): - return w_const - return space.new_interned_w_str(w_const) + from pypy.objspace.std.unicodeobject import _isidentifier + if (space.is_w(space.type(w_const), space.w_unicode) and + _isidentifier(space.unicode_w(w_const))): + return space.new_interned_w_str(w_const) + return w_const def new_identifier(space, name): From noreply at buildbot.pypy.org Mon Dec 8 05:34:25 2014 From: noreply at buildbot.pypy.org (pjenvey) Date: Mon, 8 Dec 2014 05:34:25 +0100 (CET) Subject: [pypy-commit] pypy py3k: store unicode for intern'd strings, fixes a long standing bug where interning a Message-ID: <20141208043425.E62FB1D2DFB@cobra.cs.uni-duesseldorf.de> Author: Philip Jenvey Branch: py3k Changeset: r74857:001db61e74f0 Date: 2014-12-07 20:33 -0800 http://bitbucket.org/pypy/pypy/changeset/001db61e74f0/ Log: store unicode for intern'd strings, fixes a long standing bug where interning a string w/ surrogates would fail diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -362,7 +362,7 @@ self.builtin_modules = {} self.reloading_modules = {} - self.interned_strings = make_weak_value_dictionary(self, str, W_Root) + self.interned_strings = make_weak_value_dictionary(self, unicode, W_Root) self.actionflag = ActionFlag() # changed by the signal module self.check_signal_action = None # changed by the signal module self.user_del_action = UserDelAction(self) @@ -765,31 +765,35 @@ else: return self.w_False - def new_interned_w_str(self, w_s): - assert isinstance(w_s, W_Root) # and is not None - s = self.str_w(w_s) + def new_interned_w_str(self, w_u): + assert isinstance(w_u, W_Root) # and is not None + u = self.unicode_w(w_u) + if not we_are_translated(): + assert type(u) is unicode + w_u1 = self.interned_strings.get(u) + if w_u1 is None: + w_u1 = w_u + self.interned_strings.set(u, w_u1) + return w_u1 + + def new_interned_str(self, s): + """Assumes an identifier (utf-8 encoded str)""" if not we_are_translated(): assert type(s) is str - w_s1 = self.interned_strings.get(s) + u = s.decode('utf-8') + w_s1 = self.interned_strings.get(u) if w_s1 is None: - w_s1 = w_s - self.interned_strings.set(s, w_s1) - return w_s1 - - def new_interned_str(self, s): - if not we_are_translated(): - assert type(s) is str - w_s1 = self.interned_strings.get(s) - if w_s1 is None: - w_s1 = self.wrap(s) - self.interned_strings.set(s, w_s1) + w_s1 = self.wrap(u) + self.interned_strings.set(u, w_s1) return w_s1 def is_interned_str(self, s): + """Assumes an identifier (utf-8 encoded str)""" # interface for marshal_impl if not we_are_translated(): assert type(s) is str - return self.interned_strings.get(s) is not None + u = s.decode('utf-8') + return self.interned_strings.get(u) is not None def descr_self_interp_w(self, RequiredClass, w_obj): if not isinstance(w_obj, RequiredClass): diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py --- a/pypy/module/sys/test/test_sysmodule.py +++ b/pypy/module/sys/test/test_sysmodule.py @@ -648,6 +648,9 @@ assert s3 != s2 s4 = s3.swapcase() assert intern(s4) is s2 + s5 = "\ud800" + # previously failed + assert intern(s5) == s5 class AppTestSysExcInfoDirect: From noreply at buildbot.pypy.org Mon Dec 8 09:38:05 2014 From: noreply at buildbot.pypy.org (fijal) Date: Mon, 8 Dec 2014 09:38:05 +0100 (CET) Subject: [pypy-commit] pypy default: mention AF_XXX in project-ideas Message-ID: <20141208083805.ABBD41C07E8@cobra.cs.uni-duesseldorf.de> Author: Maciej Fijalkowski Branch: Changeset: r74858:1a94e37bcf6a Date: 2014-12-08 10:37 +0200 http://bitbucket.org/pypy/pypy/changeset/1a94e37bcf6a/ Log: mention AF_XXX in project-ideas diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst --- a/pypy/doc/project-ideas.rst +++ b/pypy/doc/project-ideas.rst @@ -35,6 +35,13 @@ PyPy's bytearray type is very inefficient. It would be an interesting task to look into possible optimizations on this. +Implement AF_XXX packet types for PyPy +-------------------------------------- + +PyPy is missing AF_XXX types of sockets. Implementing it is easy-to-medium +task. `bug report`_ + +.. _`bug report`: https://bitbucket.org/pypy/pypy/issue/1942/support-for-af_xxx-sockets#more Implement copy-on-write list slicing ------------------------------------ From noreply at buildbot.pypy.org Mon Dec 8 16:38:11 2014 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 8 Dec 2014 16:38:11 +0100 (CET) Subject: [pypy-commit] benchmarks default: (cfbolz, arigo) Message-ID: <20141208153811.9D3711D35D9@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r282:d9d9946e1cda Date: 2014-12-08 15:37 +0000 http://bitbucket.org/pypy/benchmarks/changeset/d9d9946e1cda/ Log: (cfbolz, arigo) Add the Krakatau benchmark (Robert Grosse on pypy-dev). It's actually not all about the warm-up time; after warm-up it is still much slower on PyPy than on CPython. diff too long, truncating to 2000 out of 14612 lines diff --git a/own/bm_krakatau.py b/own/bm_krakatau.py new file mode 100644 --- /dev/null +++ b/own/bm_krakatau.py @@ -0,0 +1,66 @@ +import sys, os +import time +import util, optparse + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'krakatau/Krakatau')) +print sys.path + +import Krakatau.ssa +from Krakatau.environment import Environment +from Krakatau.java import javaclass +from Krakatau.verifier.inference_verifier import verifyBytecode + + +def makeGraph(m): + v = verifyBytecode(m.code) + s = Krakatau.ssa.ssaFromVerified(m.code, v) + + # print _stats(s) + if s.procs: + # s.mergeSingleSuccessorBlocks() + # s.removeUnusedVariables() + s.inlineSubprocs() + + s.condenseBlocks() + s.mergeSingleSuccessorBlocks() + # print _stats(s) + s.removeUnusedVariables() + s.constraintPropagation() + s.disconnectConstantVariables() + s.simplifyJumps() + s.mergeSingleSuccessorBlocks() + s.removeUnusedVariables() + # print _stats(s) + return s + +def decompileClass(): + path = ['krakatau/rt.jar'] + targets = ['javax/swing/plaf/nimbus/ToolBarSouthState'] + e = Environment() + for part in path: + e.addToPath(part) + + with e: + for i,target in enumerate(targets): + for _ in range(100): + c = e.getClass(target) + source = javaclass.generateAST(c, makeGraph).print_() + + +def main(n): + l = [] + for i in range(n): + t0 = time.time() + decompileClass() + time_elapsed = time.time() - t0 + l.append(time_elapsed) + return l + +if __name__ == "__main__": + parser = optparse.OptionParser( + usage="%prog [options]", + description="Test the performance of the krakatau benchmark") + util.add_standard_options_to(parser) + options, args = parser.parse_args() + + util.run_benchmark(options, options.num_runs, main) diff --git a/own/cache.txt b/own/cache.txt new file mode 100644 --- /dev/null +++ b/own/cache.txt @@ -0,0 +1,13 @@ +java/lang/Object;SUPER,PUBLIC +java/lang/Object,javax/swing/plaf/nimbus/State;ABSTRACT,SUPER,PUBLIC +java/lang/Object,javax/swing/plaf/nimbus/State,javax/swing/plaf/nimbus/ToolBarSouthState;SUPER +java/lang/Object,java/lang/String;SUPER,FINAL,PUBLIC +java/lang/Object,java/lang/Throwable;SUPER,PUBLIC +java/lang/Object,java/lang/Throwable,java/lang/Exception;SUPER,PUBLIC +java/lang/Object,java/lang/Throwable,java/lang/Exception,java/lang/RuntimeException;SUPER,PUBLIC +java/lang/Object,java/lang/Throwable,java/lang/Exception,java/lang/RuntimeException,java/lang/IllegalMonitorStateException;SUPER,PUBLIC +java/lang/Object,java/awt/Component;ABSTRACT,SUPER,PUBLIC +java/lang/Object,java/awt/Component,java/awt/Container;SUPER,PUBLIC +java/lang/Object,java/awt/Component,java/awt/Container,javax/swing/JComponent;ABSTRACT,SUPER,PUBLIC +java/lang/Object,java/awt/Component,java/awt/Container,javax/swing/JComponent,javax/swing/JToolBar;SUPER,PUBLIC +java/lang/Object,java/lang/Throwable,java/lang/Exception,java/lang/RuntimeException,java/lang/ClassCastException;SUPER,PUBLIC diff --git a/own/krakatau/Krakatau/.gitattributes b/own/krakatau/Krakatau/.gitattributes new file mode 100644 --- /dev/null +++ b/own/krakatau/Krakatau/.gitattributes @@ -0,0 +1,2 @@ +* text=auto +*.test binary \ No newline at end of file diff --git a/own/krakatau/Krakatau/.gitignore b/own/krakatau/Krakatau/.gitignore new file mode 100644 --- /dev/null +++ b/own/krakatau/Krakatau/.gitignore @@ -0,0 +1,6 @@ +*.pyc +*.pyo +test*.py +Krakatau/plugins/* +cache.txt +tests/*.test diff --git a/own/krakatau/Krakatau/Documentation/assembler.txt b/own/krakatau/Krakatau/Documentation/assembler.txt new file mode 100644 --- /dev/null +++ b/own/krakatau/Krakatau/Documentation/assembler.txt @@ -0,0 +1,88 @@ +Krakatau Assembler Syntax + +This guide is intended to help write bytecode assembly files for use with the Krakatau assembler. It assumes that you are already familiar with the JVM classfile format and how to write bytecode. If not, you can find a simple tutorial to writing bytecode at https://greyhat.gatech.edu/wiki/index.php?title=Java_Bytecode_Tutorial. You can also find some examples of assembler files in the examples directory. + +Krakatau syntax is largely backwards compatible with the classic Jasmin assembler syntax. In a couple of places, backwards compatibility is broken either by the introduction of new keywords or to fix ambiguities in the Jasmin syntax. However, Krakatau is not necessarily compatible with the extensions introduced by JasminXT. + +The basic format for an assembler file consists of a list of classfile entries. Each entry will result in the generation of a seperate classfile, so a single assembly file can contain multiple classes where convienent. These entries are completely independent - mutiple classes never share constant pool entries, fields, methods, or directives, even the version directive. Each one has the format + +.bytecode major minor (optional) +class directives +.class classref +.super classref +interface declarations +class directives +topitems +.end class + +The .end class on the final entry may be ommitted. So the simplest possible assembler file to declare a class named Foo would be + +.class Foo +.super java/lang/Object + +To declare three classes A, B, and C in the same file with B and C inheriting from A and different versions, you could do + +.class A +.super java/lang/Object +.end class +.class B +.super A +.end class +.class C +.super A + +The classfile version is specified by the .bytecode directive. It is specified by major, minor, a pair of decimal integers. If ommitted, the default is version 49.0. So the following is equivalent to the earlier example + +.bytecode 49 0 +.class Foo +.super java/lang/Object + +Other class directives include .runtimevisible, .runtimeinvisible, .signature, .attribute, .source, .inner, .innerlength, and .enclosing. These are used to control the attributes of the class and will be covered later. + +Topitems are the actual meat of the class. There are three types: fields, methods, and constant definitions. The last is unique to Krakatau and is closely related to the rest of the syntax. In Krakatau, there are multiple ways to specify a constant pool entry. The most common are via WORD tokens, symbolic references and numerical references. The later constist of square brackets with lowercase alphanumerics and underscores inside. + +When you specify .class Foo, the string Foo isn't directly included in the output. The classfile format says that the class field is actually a two byte index into the constant pool of the classfile. This points to a Class_info which points to a Utf8_info which holds the actual name of the class. Therefore, Krakatau implicitly creates constant pool entries and inserts the appropriate references. But this process can be controlled more directly. + +Instead of writing +.class Foo +.super java/lang/Object + +You could explicitly write out all the classfile references as follows + +.class [foocls] +.super [objcls] + +.const [foocls] = Class [fooutf] +.const [fooutf] = Utf8 Foo +.const [objcls] = Class [objutf] +.const [objutf] = Utf8 java/lang/Object + +There are two types of references. If the contents are a decimal int, then it is a direct numerical reference to a particular slot in the constant pool. You are responsible for making sure that everything is consistent and that the contents of that slot are valid. This option is most useful for specifiying the null entry [0]. For example, to express the Object class itself, one would do + +.class java/lang/Object +.super [0] + +If the contents are any other nonempty lowercase alphanumeric + underscores string, it is interperted as a symbolic reference. This is a reference to some slot but you don't care which one. Krakatau will pick an available slot and fill it in automatically. Symbolic references may be ommitted from the generated classfile if unused or merged with identical entries, including automatically generated entries. + +With that out of the way, the basic form of a constant definition is + +.const ref = entrytype arguments + +You can also just define one reference in terms of another. You are responsible for making sure there are no circular references or duplicated definitions. If not, unpredictable results may occur. + +Examples include + +.const [1] = Class Foo +.const [1] = Class [fooutf] +.const [89] = Long 1234567L +.const [mynat] = NameAndType main ([Ljava/lang/String;)V +.const [myref] = [myotherref] +.const [really42] = [42] + + + + + + + + diff --git a/own/krakatau/Krakatau/Krakatau/__init__.py b/own/krakatau/Krakatau/Krakatau/__init__.py new file mode 100644 --- /dev/null +++ b/own/krakatau/Krakatau/Krakatau/__init__.py @@ -0,0 +1,6 @@ +'''Monkeypatch a fix for bugs.python.org/issue9825 in case users are running an old version.''' +import collections +try: + del collections.OrderedDict.__del__ +except AttributeError: + pass \ No newline at end of file diff --git a/own/krakatau/Krakatau/Krakatau/assembler/__init__.py b/own/krakatau/Krakatau/Krakatau/assembler/__init__.py new file mode 100644 diff --git a/own/krakatau/Krakatau/Krakatau/assembler/assembler.py b/own/krakatau/Krakatau/Krakatau/assembler/assembler.py new file mode 100644 --- /dev/null +++ b/own/krakatau/Krakatau/Krakatau/assembler/assembler.py @@ -0,0 +1,580 @@ +import collections +import struct, operator + +from . import instructions, codes +from .. import constant_pool +from ..classfile import ClassFile +from ..method import Method +from ..field import Field + +class AssemblerError(Exception): + def __init__(self, message, data=None): + super(AssemblerError, self).__init__(message) + self.data = data + +def error(msg): + raise AssemblerError(msg) + +class PoolRef(object): + def __init__(self, *args, **kwargs): + self.index = kwargs.get('index') + self.lbl = kwargs.get('lbl') + self.args = args + + def toIndex(self, pool, forbidden=(), **kwargs): + if self.index is not None: + return self.index + if self.lbl: + self.index = pool.getLabel(self.lbl, forbidden, **kwargs) + else: + self.args = [(x.toIndex(pool) if isinstance(x, PoolRef) else x) for x in self.args] + self.index = pool.getItem(*self.args, **kwargs) + return self.index + +class PoolInfo(object): + def __init__(self): + self.pool = constant_pool.ConstPool() + self.lbls = {} + self.fixed = {} # constant pool entries in a specific slot + self.bootstrap = [] #entries for the BootstrapMethods attribute if any + + def getLabel(self, lbl, forbidden=(), **kwargs): + if lbl in forbidden: + error('Circular constant pool reference: ' + ', '.join(forbidden)) + forbidden = forbidden + (lbl,) + return self.lbls[lbl].toIndex(self, forbidden, **kwargs) + + def getItem(self, type_, *args, **kwargs): + if type_ == 'InvokeDynamic': + self.bootstrap.append(args[:-1]) + args = len(self.bootstrap)-1, args[-1] + return self.pool.addItem((type_, tuple(args)), **kwargs) + + def Utf8(self, s): + return self.getItem('Utf8', s) + + def assignFixedSlots(self): + self.pool.reserved.update(self.fixed) + for i,v in self.fixed.items(): + if v.args and v.args[0] in ('Double','Long'): + self.pool.reserved.add(i+1) + + #TODO - order these in terms of dependencies? + for index, value in self.fixed.items(): + used = value.toIndex(self, index=index) + if used != index: #we need to copy an existing item + self.pool.copyItem(used, index) + +_format_ops = collections.defaultdict(tuple) +_format_ops[''] = instructions.instrs_noarg +_format_ops['>B'] = 'iload', 'lload', 'fload', 'dload', 'aload', 'istore', 'lstore', 'fstore', 'dstore', 'astore', 'ret' +_format_ops['>h'] = 'ifeq', 'ifne', 'iflt', 'ifge', 'ifgt', 'ifle', 'if_icmpeq', 'if_icmpne', 'if_icmplt', 'if_icmpge', 'if_icmpgt', 'if_icmple', 'if_acmpeq', 'if_acmpne', 'goto', 'jsr', 'ifnull', 'ifnonnull' +_format_ops['>H'] = 'ldc_w', 'ldc2_w', 'getstatic', 'putstatic', 'getfield', 'putfield', 'invokevirtual', 'invokespecial', 'invokestatic', 'new', 'anewarray', 'checkcast', 'instanceof' + +_format_ops['>b'] += 'bipush', +_format_ops['>Bb'] += 'iinc', +_format_ops['>h'] += 'sipush', +_format_ops['>HB'] += 'multianewarray', +_format_ops['>HBB'] += 'invokeinterface', +_format_ops['>HH'] += 'invokedynamic', +_format_ops['>B'] += 'ldc', 'newarray' +_format_ops['>i'] += 'goto_w', 'jsr_w' + +op_structs = {} +for fmt, ops in _format_ops.items(): + _s = struct.Struct(fmt) + for _op in ops: + op_structs[_op] = _s + +def getPadding(pos): + return (3-pos) % 4 + +def getInstrLen(instr, pos): + op = instr[0] + if op in op_structs: + return 1 + op_structs[op].size + elif op == 'wide': + return 2 + 2 * len(instr[1][1]) + else: + padding = getPadding(pos) + count = len(instr[1][1]) + if op == 'tableswitch': + return 13 + padding + 4*count + else: + return 9 + padding + 8*count + +def assembleInstruction(instr, labels, pos, pool): + def lbl2Off(lbl): + if lbl not in labels: + del labels[None] + error('Undefined label: {}\nDefined labels for current method are: {}'.format(lbl, ', '.join(sorted(labels)))) + return labels[lbl] - pos + + op = instr[0] + first = chr(instructions.allinstructions.index(op)) + + instr = [(x.toIndex(pool) if isinstance(x, PoolRef) else x) for x in instr[1:]] + if op in instructions.instrs_lbl: + instr[0] = lbl2Off(instr[0]) + if op in op_structs: + rest = op_structs[op].pack(*instr) + return first+rest + elif op == 'wide': + subop, args = instr[0] + prefix = chr(instructions.allinstructions.index(subop)) + fmt = '>Hh' if len(args) > 1 else '>H' + rest = struct.pack(fmt, *args) + return first + prefix + rest + else: + padding = getPadding(pos) + param, jumps, default = instr[0] + default = lbl2Off(default) + + if op == 'tableswitch': + jumps = map(lbl2Off, jumps) + low, high = param, param + len(jumps)-1 + temp = struct.Struct('>i') + part1 = first + '\0'*padding + struct.pack('>iii', default, low, high) + return part1 + ''.join(map(temp.pack, jumps)) + elif op == 'lookupswitch': + jumps = {k:lbl2Off(lbl) for k,lbl in jumps} + jumps = sorted(jumps.items()) + temp = struct.Struct('>ii') + part1 = first + '\0'*padding + struct.pack('>ii', default, len(jumps)) + part2 = ''.join(map(temp.pack, *zip(*jumps))) if jumps else '' + return part1 + part2 + +def groupList(pairs): + d = collections.defaultdict(list) + for k,v in pairs: + d[k].append(v) + return d + +def splitList(pairs): + d = groupList(pairs) + return d[False], d[True] + +def assembleCodeAttr(statements, pool, version, addLineNumbers, jasmode): + directives, lines = splitList(statements) + dir_offsets = collections.defaultdict(list) + + offsets = [] + labels = {} + pos = 0 + #first run through to calculate bytecode offsets + #this is greatly complicated due to the need to + #handle Jasmine line number directives + for t, statement in statements: + if t: + lbl, instr = statement + labels[lbl] = pos + if instr is not None: + offsets.append(pos) + pos += getInstrLen(instr, pos) + #some directives require us to keep track of the corresponding bytecode offset + elif statement[0] in ('.line','.stackmap'): + dir_offsets[statement[0]].append(pos) + code_len = pos + + code_bytes = '' + for lbl, instr in lines: + if instr is not None: + code_bytes += assembleInstruction(instr, labels, len(code_bytes), pool) + assert(len(code_bytes) == code_len) + + directive_dict = groupList(directives) + limits = groupList(directive_dict['.limit']) + + stack = min(limits['stack'] + [65535]) + locals_ = min(limits['locals'] + [65535]) + + excepts = [] + for name, start, end, target in directive_dict['.catch']: + #Hack for compatibility with Jasmin + if jasmode and name.args and (name.args[1].args == ('Utf8','all')): + name.index = 0 + vals = labels[start], labels[end], labels[target], name.toIndex(pool) + excepts.append(struct.pack('>HHHH',*vals)) + + attributes = [] + + #StackMapTable + def pack_vt(vt): + s = chr(codes.vt_codes[vt[0]]) + if vt[0] == 'Object': + s += struct.pack('>H', vt[1].toIndex(pool)) + elif vt[0] == 'Uninitialized': + s += struct.pack('>H', labels[vt[1]]) + return s + + if directive_dict['.stackmap']: + frames = [] + last_pos = -1 + + for pos, info in zip(dir_offsets['.stackmap'], directive_dict['.stackmap']): + offset = pos - last_pos - 1 + last_pos = pos + assert(offset >= 0) + + tag = info[0] + if tag == 'same': + if offset >= 64: + error('Max offset on a same frame is 63.') + frames.append(chr(offset)) + elif tag == 'same_locals_1_stack_item': + if offset >= 64: + error('Max offset on a same_locals_1_stack_item frame is 63.') + frames.append(chr(64 + offset) + pack_vt(info[2][0])) + elif tag == 'same_locals_1_stack_item_extended': + frames.append(struct.pack('>BH', 247, offset) + pack_vt(info[2][0])) + elif tag == 'chop': + if not (1 <= info[1] <= 3): + error('Chop frame can only remove 1-3 locals') + frames.append(struct.pack('>BH', 251-info[1], offset)) + elif tag == 'same_extended': + frames.append(struct.pack('>BH', 251, offset)) + elif tag == 'append': + local_vts = map(pack_vt, info[2]) + if not (1 <= len(local_vts) <= 3): + error('Append frame can only add 1-3 locals') + frames.append(struct.pack('>BH', 251+len(local_vts), offset) + ''.join(local_vts)) + elif tag == 'full': + local_vts = map(pack_vt, info[2]) + stack_vts = map(pack_vt, info[3]) + frame = struct.pack('>BH', 255, offset) + frame += struct.pack('>H', len(local_vts)) + ''.join(local_vts) + frame += struct.pack('>H', len(stack_vts)) + ''.join(stack_vts) + frames.append(frame) + + sm_body = ''.join(frames) + sm_attr = struct.pack('>HIH', pool.Utf8("StackMapTable"), len(sm_body)+2, len(frames)) + sm_body + attributes.append(sm_attr) + + #line number attribute + if addLineNumbers and not directive_dict['line']: + dir_offsets['line'] = directive_dict['line'] = offsets + if directive_dict['line']: + lntable = [struct.pack('>HH',x,y) for x,y in zip(dir_offsets['line'], directive_dict['line'])] + ln_attr = struct.pack('>HIH', pool.Utf8("LineNumberTable"), 2+4*len(lntable), len(lntable)) + ''.join(lntable) + attributes.append(ln_attr) + + if directive_dict['.var']: + sfunc = struct.Struct('>HHHHH').pack + vartable = [] + for index, name, desc, start, end in directive_dict['.var']: + start, end = labels[start], labels[end] + name, desc = name.toIndex(pool), desc.toIndex(pool) + vartable.append(sfunc(start, end-start, name, desc, index)) + var_attr = struct.pack('>HIH', pool.Utf8("LocalVariableTable"), 2+10*len(vartable), len(vartable)) + ''.join(vartable) + attributes.append(var_attr) + + if not code_len: + return None + + for attrname, data in directive_dict['.codeattribute']: + attr = struct.pack('>HI', attrname.toIndex(pool), len(data)) + data + attributes.append(attr) + + + #Old versions use shorter fields for stack, locals, and code length + header_fmt = '>HHI' if version > (45,2) else '>BBH' + + name_ind = pool.Utf8("Code") + attr_len = struct.calcsize(header_fmt) + 4 + len(code_bytes) + 8*len(excepts) + sum(map(len, attributes)) + + assembled_bytes = struct.pack('>HI', name_ind, attr_len) + assembled_bytes += struct.pack(header_fmt, stack, locals_, len(code_bytes)) + assembled_bytes += code_bytes + assembled_bytes += struct.pack('>H', len(excepts)) + ''.join(excepts) + assembled_bytes += struct.pack('>H', len(attributes)) + ''.join(attributes) + return assembled_bytes + +def _assembleEVorAnnotationSub(pool, init_args, isAnnot): + #call types + C_ANNOT, C_ANNOT2, C_EV = range(3) + init_callt = C_ANNOT if isAnnot else C_EV + + stack = [(init_callt, init_args)] + parts = [] + add = parts.append + + while stack: + callt, args = stack.pop() + + if callt == C_ANNOT: + typeref, keylines = args + add(struct.pack('>HH', typeref.toIndex(pool), len(keylines))) + for pair in reversed(keylines): + stack.append((C_ANNOT2, pair)) + + elif callt == C_ANNOT2: + name, val = args + add(struct.pack('>H', name.toIndex(pool))) + stack.append((C_EV, val)) + + elif callt == C_EV: + tag, data = args + assert(tag in codes.et_rtags) + add(tag) + + if tag in 'BCDFIJSZsc': + add(struct.pack('>H', data[0].toIndex(pool))) + elif tag == 'e': + add(struct.pack('>HH', data[0].toIndex(pool), data[1].toIndex(pool))) + elif tag == '@': + stack.append((C_ANNOT, data[0])) + elif tag == '[': + add(struct.pack('>H', len(data[1]))) + for arrval in reversed(data[1]): + stack.append((C_EV, arrval)) + return ''.join(parts) + +def assembleElementValue(val, pool): + return _assembleEVorAnnotationSub(pool, val, False) + +def assembleAnnotation(annotation, pool): + return _assembleEVorAnnotationSub(pool, annotation, True) + +def assembleMethod(header, statements, pool, version, addLineNumbers, jasmode): + mflags, (name, desc) = header + name = name.toIndex(pool) + desc = desc.toIndex(pool) + + flagbits = map(Method.flagVals.get, mflags) + flagbits = reduce(operator.__or__, flagbits, 0) + + meth_statements, code_statements = splitList(statements) + + method_attributes = [] + code_attr = assembleCodeAttr(code_statements, pool, version, addLineNumbers, jasmode) + if code_attr is not None: + method_attributes.append(code_attr) + + directive_dict = groupList(meth_statements) + if directive_dict['.throws']: + t_inds = [struct.pack('>H', x.toIndex(pool)) for x in directive_dict['.throws']] + throw_attr = struct.pack('>HIH', pool.Utf8("Exceptions"), 2+2*len(t_inds), len(t_inds)) + ''.join(t_inds) + method_attributes.append(throw_attr) + + #Runtime annotations + for vis in ('Invisible','Visible'): + paramd = groupList(directive_dict['.runtime'+vis.lower()]) + + if None in paramd: + del paramd[None] + + if paramd: + parts = [] + for i in range(max(paramd)): + annotations = [assembleAnnotation(a, pool) for a in paramd[i]] + part = struct.pack('>H', len(annotations)) + ''.join(annotations) + parts.append(part) + attrlen = 1+sum(map(len, parts)) + attr = struct.pack('>HIB', pool.Utf8("Runtime{}ParameterAnnotations".format(vis)), attrlen, len(parts)) + ''.join(parts) + method_attributes.append(attr) + + if '.annotationdefault' in directive_dict: + val = directive_dict['.annotationdefault'][0] + data = assembleElementValue(val, pool) + attr = struct.pack('>HI', pool.Utf8("AnnotationDefault"), len(data)) + data + method_attributes.append(attr) + + assembleClassFieldMethodAttributes(method_attributes.append, directive_dict, pool) + return struct.pack('>HHHH', flagbits, name, desc, len(method_attributes)) + ''.join(method_attributes) + +def getLdcRefs(statements): + lines = [x[1][1] for x in statements if x[0] and x[1][0]] + instructions = [x[1] for x in lines if x[1] is not None] + + for instr in instructions: + op = instr[0] + if op == 'ldc': + yield instr[1] + +def addLdcRefs(methods, pool): + def getRealRef(ref, forbidden=()): + '''Get the root PoolRef associated with a given PoolRef, following labels''' + if ref.index is None and ref.lbl: + if ref.lbl in forbidden: + error('Circular constant pool reference: ' + ', '.join(forbidden)) + forbidden = forbidden + (ref.lbl,) + return getRealRef(pool.lbls[ref.lbl], forbidden) #recursive call + return ref + + #We attempt to estimate how many slots are needed after merging identical entries + #So we can reserve the correct number of slots without leaving unused gaps + #However, in complex cases, such as string/class/mt referring to an explicit + #reference, we may overestimate + ldc_refs = collections.defaultdict(set) + + for header, statements in methods: + for ref in getLdcRefs(statements): + ref = getRealRef(ref) + if ref.index is not None: + continue + + type_ = ref.args[0] + if type_ in ('Int','Float'): + key = ref.args[1] + elif type_ in ('String','Class','MethodType'): + uref = getRealRef(ref.args[1]) + key = uref.index, uref.args[1:] + else: #for MethodHandles, don't even bother trying to estimate merging + key = ref.args[1:] + ldc_refs[type_].add(key) + + #TODO - make this a little cleaner so we don't have to mess with the ConstantPool internals + num = sum(map(len, ldc_refs.values())) + slots = [pool.pool.getAvailableIndex() for _ in range(num)] + pool.pool.reserved.update(slots) + + for type_ in ('Int','Float'): + for arg in ldc_refs[type_]: + pool.getItem(type_, arg, index=slots.pop()) + for type_ in ('String','Class','MethodType'): + for ind,args in ldc_refs[type_]: + arg = ind if ind is not None else pool.Utf8(*args) + pool.getItem(type_, arg, index=slots.pop()) + for type_ in ('MethodHandle',): + for code, ref in ldc_refs[type_]: + pool.getItem(type_, code, ref.toIndex(pool), index=slots.pop()) + assert(not slots) + assert(not pool.pool.reserved) + +def assembleClassFieldMethodAttributes(addcb, directive_dict, pool): + for vis in ('Invisible','Visible'): + paramd = groupList(directive_dict['.runtime'+vis.lower()]) + if None in paramd: + annotations = [assembleAnnotation(a, pool) for a in paramd[None]] + attrlen = 2+sum(map(len, annotations)) + attr = struct.pack('>HIH', pool.Utf8("Runtime{}Annotations".format(vis)), attrlen, len(annotations)) + ''.join(annotations) + addcb(attr) + + for name in directive_dict['.signature']: + attr = struct.pack('>HIH', pool.Utf8("Signature"), 2, name.toIndex(pool)) + addcb(attr) + + #.innerlength directive overrides the normal attribute length calculation + hasoverride = len(directive_dict['.innerlength']) > 0 + + for name, data in directive_dict['.attribute']: + name_ind = name.toIndex(pool) + + if hasoverride and pool.pool.getArgsCheck('Utf8', name_ind) == 'InnerClasses': + attrlen = directive_dict['.innerlength'][0] + else: + attrlen = len(data) + + attr = struct.pack('>HI', name_ind, attrlen) + data + addcb(attr) + +def assembleClassAttributes(addcb, directive_dict, pool, addLineNumbers, jasmode, filename): + + sourcefile = directive_dict.get('.source',[None])[0] #PoolRef or None + if jasmode and not sourcefile: + sourcefile = pool.Utf8(filename) + elif addLineNumbers and not sourcefile: + sourcefile = pool.Utf8("SourceFile") + if sourcefile: + attr = struct.pack('>HIH', pool.Utf8("SourceFile"), 2, sourcefile.toIndex(pool)) + addcb(attr) + + if '.inner' in directive_dict: + parts = [] + for inner, outer, name, flags in directive_dict['.inner']: + flagbits = map(ClassFile.flagVals.get, flags) + flagbits = reduce(operator.__or__, flagbits, 0) + part = struct.pack('>HHHH', inner.toIndex(pool), outer.toIndex(pool), name.toIndex(pool), flagbits) + parts.append(part) + + #.innerlength directive overrides the normal attribute length calculation + innerlen = 2+8*len(parts) if '.innerlength' not in directive_dict else directive_dict['.innerlength'][0] + attr = struct.pack('>HIH', pool.Utf8("InnerClasses"), innerlen, len(parts)) + ''.join(parts) + addcb(attr) + + if '.enclosing' in directive_dict: + class_, nat = directive_dict['.enclosing'][0] + attr = struct.pack('>HIHH', pool.Utf8("EnclosingMethod"), 4, class_.toIndex(pool), nat.toIndex(pool)) + addcb(attr) + + assembleClassFieldMethodAttributes(addcb, directive_dict, pool) + + +def assemble(tree, addLineNumbers, jasmode, filename): + pool = PoolInfo() + version, cattrs1, classdec, superdec, interface_decs, cattrs2, topitems = tree + if not version: #default to version 49.0 except in Jasmin compatibility mode + version = (45,3) if jasmode else (49,0) + + #scan topitems, plus statements in each method to get cpool directives + interfaces = [] + fields = [] + methods = [] + attributes = [] + + directive_dict = groupList(cattrs1 + cattrs2) + top_d = groupList(topitems) + + for slot, value in top_d['const']: + if slot.index is not None: + pool.fixed[slot.index] = value + else: + pool.lbls[slot.lbl] = value + pool.assignFixedSlots() + + #Now find all cp references used in an ldc instruction + #Since they must be <=255, we give them priority in assigning slots + #to maximize the chance of a successful assembly + addLdcRefs(top_d['method'], pool) + + for flags, name, desc, const, field_directives in top_d['field']: + flagbits = map(Field.flagVals.get, flags) + flagbits = reduce(operator.__or__, flagbits, 0) + name = name.toIndex(pool) + desc = desc.toIndex(pool) + + fattrs = [] + if const is not None: + attr = struct.pack('>HIH', pool.Utf8("ConstantValue"), 2, const.toIndex(pool)) + fattrs.append(attr) + + assembleClassFieldMethodAttributes(fattrs.append, groupList(field_directives), pool) + + field_code = struct.pack('>HHHH', flagbits, name, desc, len(fattrs)) + ''.join(fattrs) + fields.append(field_code) + + for header, statements in top_d['method']: + methods.append(assembleMethod(header, statements, pool, version, addLineNumbers, jasmode)) + + if pool.bootstrap: + entries = [struct.pack('>H' + 'H'*len(bsargs), bsargs[0], len(bsargs)-1, *bsargs[1:]) for bsargs in pool.bootstrap] + attrbody = ''.join(entries) + attrhead = struct.pack('>HIH', pool.Utf8("BootstrapMethods"), 2+len(attrbody), len(entries)) + attributes.append(attrhead + attrbody) + + #Explicit class attributes + assembleClassAttributes(attributes.append, directive_dict, pool, addLineNumbers, jasmode, filename) + + interfaces = [struct.pack('>H', x.toIndex(pool)) for x in interface_decs] + intf, cflags, this = classdec + cflags = set(cflags) + if intf: + cflags.add('INTERFACE') + if jasmode: + cflags.add('SUPER') + + flagbits = map(ClassFile.flagVals.get, cflags) + flagbits = reduce(operator.__or__, flagbits, 0) + this = this.toIndex(pool) + super_ = superdec.toIndex(pool) + + major, minor = version + class_code = '\xCA\xFE\xBA\xBE' + struct.pack('>HH', minor, major) + class_code += pool.pool.bytes() + class_code += struct.pack('>HHH', flagbits, this, super_) + for stuff in (interfaces, fields, methods, attributes): + bytes_ = struct.pack('>H', len(stuff)) + ''.join(stuff) + class_code += bytes_ + + name = pool.pool.getArgs(this)[0] + return name, class_code \ No newline at end of file diff --git a/own/krakatau/Krakatau/Krakatau/assembler/codes.py b/own/krakatau/Krakatau/Krakatau/assembler/codes.py new file mode 100644 --- /dev/null +++ b/own/krakatau/Krakatau/Krakatau/assembler/codes.py @@ -0,0 +1,11 @@ +_handle_types = 'getField getStatic putField putStatic invokeVirtual invokeStatic invokeSpecial newInvokeSpecial invokeInterface'.split() +handle_codes = dict(zip(_handle_types, range(1,10))) + +newarr_codes = dict(zip('boolean char float double byte short int long'.split(), range(4,12))) + +vt_keywords = ['Top','Integer','Float','Double','Long','Null','UninitializedThis','Object','Uninitialized'] +vt_codes = {k:i for i,k in enumerate(vt_keywords)} + + +et_rtags = dict(zip('BCDFIJSZsce@[', 'byte char double int float long short boolean string class enum annotation array'.split())) +et_tags = {v:k for k,v in et_rtags.items()} \ No newline at end of file diff --git a/own/krakatau/Krakatau/Krakatau/assembler/disassembler.py b/own/krakatau/Krakatau/Krakatau/assembler/disassembler.py new file mode 100644 --- /dev/null +++ b/own/krakatau/Krakatau/Krakatau/assembler/disassembler.py @@ -0,0 +1,539 @@ +import collections +import re + +from . import instructions, tokenize, parse, assembler, codes +from ..binUnpacker import binUnpacker +from ..classfile import ClassFile + +MAX_INLINE_LENGTH = 50 + +rhandle_codes = {v:k for k,v in codes.handle_codes.items()} +rnewarr_codes = {v:k for k,v in codes.newarr_codes.items()} + +not_word_regex = '(?:{}|{}|{}|;)'.format(tokenize.int_base, tokenize.float_base, tokenize.t_CPINDEX) +not_word_regex = re.compile(not_word_regex, re.VERBOSE) +is_word_regex = re.compile(tokenize.t_WORD.__doc__+'$') +assert(is_word_regex.match("''") is None) + +def isWord(s): + '''Determine if s can be used as an inline word''' + if s in parse.badwords or (not_word_regex.match(s) is not None): + return False + #eliminate unprintable characters below 32 + #also, don't allow characters above 127 to keep things simpler + return (is_word_regex.match(s) is not None) and min(s) > ' ' and max(s) <= '\x7f' + +def rstring(s, allowWord=True): + '''Returns a representation of the string. If allowWord is true, it will be unquoted if possible''' + if allowWord and isWord(s): + return s + try: + if s.encode('ascii') == s: + return repr(str(s)) + except (UnicodeEncodeError, UnicodeDecodeError): + pass + return repr(s) + +class PoolManager(object): + def __init__(self, pool): + self.const_pool = pool #keep this around for the float conversion function + self.pool = pool.pool + self.bootstrap_methods = [] #filled in externally + self.used = set() #which cp entries are used non inline and so must be printed + + #For each type, store the function needed to generate the rhs of a constant pool specifier + temp1 = lambda ind: rstring(self.cparg1(ind)) + temp2 = lambda ind: self.utfref(self.cparg1(ind)) + + self.cpref_table = { + "Utf8": temp1, + + "Class": temp2, + "String": temp2, + "MethodType": temp2, + + "NameAndType": self.multiref, + "Field": self.multiref, + "Method": self.multiref, + "InterfaceMethod": self.multiref, + + "Int": self.ldc, + "Long": self.ldc, + "Float": self.ldc, + "Double": self.ldc, + + "MethodHandle": self.methodhandle_notref, + "InvokeDynamic": self.invokedynamic_notref, + } + + def cparg1(self, ind): + return self.pool[ind][1][0] + + def inlineutf(self, ind, allowWord=True): + '''Returns the word if it's short enough to inline, else None''' + arg = self.cparg1(ind) + rstr = rstring(arg, allowWord=allowWord) + if len(rstr) <= MAX_INLINE_LENGTH: + return rstr + return None + + def ref(self, ind): + self.used.add(ind) + return '[_{}]'.format(ind) + + def utfref(self, ind): + if ind == 0: + return '[0]' + inline = self.inlineutf(ind) + return inline if inline is not None else self.ref(ind) + + #Also works for Strings and MethodTypes + def classref(self, ind): + if ind == 0: + return '[0]' + inline = self.inlineutf(self.cparg1(ind)) + return inline if inline is not None else self.ref(ind) + + #For Field, Method, IMethod, and NameAndType. Effectively notref + def multiref(self, ind): + if ind == 0: + return '[0]' + typen, args = self.pool[ind] + if typen == "Utf8": + return self.utfref(ind) + elif typen == "Class": + return self.classref(ind) + return ' '.join(map(self.multiref, args)) + + #Special case for instruction fieldrefs as a workaround for Jasmin's awful syntax + def notjasref(self, ind): + typen, args = self.pool[ind] + cind = self.cparg1(ind) + inline = self.inlineutf(self.cparg1(cind)) + if inline is None: + return self.ref(ind) + return inline + ' ' + self.multiref(args[1]) + + def ldc(self, ind): + typen, args = self.pool[ind] + arg = args[0] + + if typen == 'String': + inline = self.inlineutf(arg, allowWord=False) + return inline if inline is not None else self.ref(ind) + elif typen in ('Int','Long','Float','Double'): + if typen == "Float" or typen == "Double": + arg = self.const_pool.getArgs(ind)[0] + + rstr = repr(arg).rstrip("Ll") + if typen == "Float" or typen == "Long": + rstr += typen[0] + return rstr + else: + return self.ref(ind) + + def methodhandle_notref(self, ind): + typen, args = self.pool[ind] + code = rhandle_codes[args[0]] + return code + ' ' + self.ref(args[1]) + + def invokedynamic_notref(self, ind): + typen, args = self.pool[ind] + bs_args = self.bootstrap_methods[args[0]] + + parts = [self.methodhandle_notref(bs_args[0])] + parts += map(self.ref, bs_args[1:]) + parts += [':', self.multiref(args[1])] + return ' '.join(parts) + + def printConstDefs(self, add): + defs = {} + + while self.used: + temp, self.used = self.used, set() + for ind in temp: + if ind in defs: + continue + typen = self.pool[ind][0] + defs[ind] = self.cpref_table[typen](ind) + + for ind in sorted(defs): + add('.const [_{}] = {} {}'.format(ind, self.pool[ind][0], defs[ind])) + +def getAttributeTriples(obj): #name_ind, name, data + return [(name_ind, name, data1) for (name_ind, data1), (name, data2) in zip(obj.attributes_raw, obj.attributes)] + +def getAttributesDict(obj): + d = collections.defaultdict(list) + for ind, name, attr in getAttributeTriples(obj): + d[name].append((ind, attr)) + return d + +fmt_lookup = {k:v.format for k,v in assembler.op_structs.items()} +def getInstruction(b, getlbl, poolm): + pos = b.off + op = b.get('B') + + name = instructions.allinstructions[op] + if name == 'wide': + name2 = instructions.allinstructions[b.get('B')] + if name2 == 'iinc': + args = list(b.get('>Hh')) + else: + args = [b.get('>H')] + + parts = [name, name2] + map(str, args) + return '\t' + ' '.join(parts) + elif name == 'tableswitch' or name == 'lookupswitch': + padding = assembler.getPadding(pos) + b.getRaw(padding) + + default = getlbl(b.get('>i')+pos) + + if name == 'lookupswitch': + num = b.get('>I') + entries = ['\t'+name] + entries += ['\t\t{} : {}'.format(b.get('>i'), getlbl(b.get('>i')+pos)) for _ in range(num)] + else: + low, high = b.get('>ii') + num = high-low+1 + entries = ['\t{} {}'.format(name, low)] + entries += ['\t\t{}'.format(getlbl(b.get('>i')+pos)) for _ in range(num)] + entries += ['\t\tdefault : {}'.format(default)] + return '\n'.join(entries) + else: + args = list(b.get(fmt_lookup[name], forceTuple=True)) + #remove extra padding 0 + if name in ('invokeinterface','invokedynamic'): + args = args[:-1] + + funcs = { + 'OP_CLASS': poolm.classref, + 'OP_CLASS_INT': poolm.classref, + 'OP_FIELD': poolm.notjasref, #this is a special case due to the jasmin thing + 'OP_METHOD': poolm.multiref, + 'OP_METHOD_INT': poolm.multiref, + 'OP_DYNAMIC': poolm.ref, + 'OP_LDC1': poolm.ldc, + 'OP_LDC2': poolm.ldc, + 'OP_NEWARR': rnewarr_codes.get, + } + + token_t = tokenize.wordget[name] + if token_t == 'OP_LBL': + assert(len(args) == 1) + args[0] = getlbl(args[0]+pos) + elif token_t in funcs: + args[0] = funcs[token_t](args[0]) + + parts = [name] + map(str, args) + return '\t' + ' '.join(parts) + +def disMethodCode(code, add, poolm): + if code is None: + return + add('\t; method code size: {} bytes'.format(code.codelen)) + add('\t.limit stack {}'.format(code.stack)) + add('\t.limit locals {}'.format(code.locals)) + + lbls = set() + def getlbl(x): + lbls.add(x) + return 'L'+str(x) + + for e in code.except_raw: + parts = poolm.classref(e.type_ind), getlbl(e.start), getlbl(e.end), getlbl(e.handler) + add('\t.catch {} from {} to {} using {}'.format(*parts)) + + code_attributes = getAttributesDict(code) + frames = getStackMapTable(code_attributes, poolm, getlbl) + + instrs = [] + b = binUnpacker(code.bytecode_raw) + while b.size(): + instrs.append((b.off, getInstruction(b, getlbl, poolm))) + instrs.append((b.off, None)) + + for off, instr in instrs: + if off in lbls: + add('L{}:'.format(off)) + if off in frames: + add(frames[off]) + if instr: + add(instr) + + #Generic code attributes + for name in code_attributes: + #We can't disassemble these because Jasmin's format for these attributes + #is overly cumbersome and not easy to disassemble into, but we can't just + #leave them as binary blobs either as they are verified by the JVM and the + #later two contain constant pool references which won't be preserved even + #if the bytecode isn't changed. For now, we just ommit them entirely. + #TODO - find a better solution + if name in ("LineNumberTable","LocalVariableTable","LocalVariableTypeTable"): + continue + + for name_ind, attr in code_attributes[name]: + add('.codeattribute {} {!r}'.format(poolm.utfref(name_ind), attr)) + +def getVerificationType(bytes_, poolm, getLbl): + s = codes.vt_keywords[bytes_.get('>B')] + if s == 'Object': + s += ' ' + poolm.classref(bytes_.get('>H')) + elif s == 'Uninitialized': + s += ' ' + getLbl(bytes_.get('>H')) + return s + +def getStackMapTable(code_attributes, poolm, getLbl): + smt_attrs = code_attributes['StackMapTable'] + + frames = {} + offset = 0 + + if smt_attrs: + assert(len(smt_attrs) == 1) + bytes_ = binUnpacker(smt_attrs.pop()[1]) + count = bytes_.get('>H') + getVT = lambda: getVerificationType(bytes_, poolm, getLbl) + + for _ in range(count): + tag = bytes_.get('>B') + header, contents = None, [] + + if 0 <= tag <= 63: + offset += tag + header = 'same' + elif 64 <= tag <= 127: + offset += tag - 64 + header = 'same_locals_1_stack_item' + contents.append('\tstack ' + getVT()) + elif tag == 247: + offset += bytes_.get('>H') + header = 'same_locals_1_stack_item_extended' + contents.append('\tstack ' + getVT()) + elif 248 <= tag <= 250: + offset += bytes_.get('>H') + header = 'chop ' + str(251-tag) + elif tag == 251: + offset += bytes_.get('>H') + header = 'same_extended' + elif 252 <= tag <= 254: + offset += bytes_.get('>H') + header = 'append' + contents.append('\tlocals ' + ' '.join(getVT() for _ in range(tag-251))) + elif tag == 255: + offset += bytes_.get('>H') + header = 'full' + local_count = bytes_.get('>H') + contents.append('\tlocals ' + ' '.join(getVT() for _ in range(local_count))) + stack_count = bytes_.get('>H') + contents.append('\tstack ' + ' '.join(getVT() for _ in range(stack_count))) + + if contents: + contents.append('.end stack') + contents = ['.stack ' + header] + contents + frame = '\n'.join(contents) + frames[offset] = frame + offset += 1 #frames after the first have an offset one larger than the listed offset + return frames + +def disCFMAttribute(name_ind, name, bytes_, add, poolm): + for vis in ('Visible', 'Invisible'): + if name == 'Runtime{}Annotations'.format(vis): + count = bytes_.get('>H') + for _ in range(count): + disAnnotation(bytes_, '.runtime{} '.format(vis.lower()), add, poolm, '') + if count: #otherwise we'll create an empty generic attribute + return + + if name == "Signature": + add('.signature {}'.format(poolm.utfref(bytes_.get('>H')))) + return + #Create generic attribute if it can't be represented by a standard directive + add('.attribute {} {!r}'.format(poolm.utfref(name_ind), bytes_.getRaw(bytes_.size()))) + +def disMethodAttribute(name_ind, name, bytes_, add, poolm): + if name == 'Code': + return + elif name == 'AnnotationDefault': + disElementValue(bytes_, '.annotationdefault ', add, poolm, '') + return + elif name == 'Exceptions': + count = bytes_.get('>H') + for _ in range(count): + add('.throws ' + poolm.classref(bytes_.get('>H'))) + if count: #otherwise we'll create an empty generic attribute + return + + for vis in ('Visible', 'Invisible'): + if name == 'Runtime{}ParameterAnnotations'.format(vis): + for i in range(bytes_.get('>B')): + for _ in range(bytes_.get('>H')): + disAnnotation(bytes_, '.runtime{} parameter {} '.format(vis.lower(), i), add, poolm, '') + return #generic fallback on empty list not yet supported + + disCFMAttribute(name_ind, name, bytes_, add, poolm) + +def disMethod(method, add, poolm): + mflags = ' '.join(map(str.lower, method.flags)) + add('.method {} {} : {}'.format(mflags, poolm.utfref(method.name_id), poolm.utfref(method.desc_id))) + + for name_ind, name, attr in getAttributeTriples(method): + disMethodAttribute(name_ind, name, binUnpacker(attr), add, poolm) + + disMethodCode(method.code, add, poolm) + add('.end method') + +def _disEVorAnnotationSub(bytes_, add, poolm, isAnnot, init_prefix, init_indent): + C_ANNOT, C_ANNOT2, C_ANNOT3, C_EV, C_EV2 = range(5) + init_callt = C_ANNOT if isAnnot else C_EV + + stack = [(init_callt, init_prefix, init_indent)] + while stack: + callt, prefix, indent = stack.pop() + + if callt == C_ANNOT: + add(indent + prefix + 'annotation ' + poolm.utfref(bytes_.get('>H'))) + #ones we want to happen last should be first on the stack. Annot3 is the final call which ends the annotation + stack.append((C_ANNOT3, None, indent)) + stack.extend([(C_ANNOT2, None, indent)] * bytes_.get('>H')) + + elif callt == C_ANNOT2: + key = poolm.utfref(bytes_.get('>H')) + stack.append((C_EV, key + ' = ', indent+'\t')) + + elif callt == C_ANNOT3: + add(indent + '.end annotation') + + elif callt == C_EV: + tag = codes.et_rtags[bytes_.getRaw(1)] + if tag == 'annotation': + stack.append((C_ANNOT, prefix, indent + '\t')) + else: + if tag in ('byte','char','double','int','float','long','short','boolean','string'): + val = poolm.ldc(bytes_.get('>H')) + elif tag == 'class': + val = poolm.utfref(bytes_.get('>H')) + elif tag == 'enum': + val = poolm.utfref(bytes_.get('>H')) + ' ' + poolm.utfref(bytes_.get('>H')) + elif tag == 'array': + val = '' + + add(indent + '{} {} {}'.format(prefix, tag, val)) + if tag == 'array': + for _ in range(bytes_.get('>H')): + stack.append((C_EV, '', indent+'\t')) + stack.append((C_EV2, None, indent)) + + elif callt == C_EV2: + add(indent + '.end array') + +def disElementValue(bytes_, prefix, add, poolm, indent): + _disEVorAnnotationSub(bytes_, add, poolm, False, prefix, indent) + +def disAnnotation(bytes_, prefix, add, poolm, indent): + _disEVorAnnotationSub(bytes_, add, poolm, True, prefix, indent) + +#Todo - make fields automatically unpack this themselves +def getConstValue(field): + if not field.static: + return None + const_attrs = [attr for attr in field.attributes if attr[0] == 'ConstantValue'] + if const_attrs: + assert(len(const_attrs) == 1) + bytes_ = binUnpacker(const_attrs[0][1]) + return bytes_.get('>H') + +_classflags = [(v,k.lower()) for k,v in ClassFile.flagVals.items()] +def disInnerClassesAttribute(name_ind, length, bytes_, add, poolm): + count = bytes_.get('>H') + + if length != 2+8*count: + add('.innerlength {}'.format(length)) + + for _ in range(count): + inner, outer, innername, flagbits = bytes_.get('>HHHH') + + flags = [v for k,v in _classflags if k&flagbits] + inner = poolm.classref(inner) + outer = poolm.classref(outer) + innername = poolm.utfref(innername) + + add('.inner {} {} {} {}'.format(' '.join(flags), innername, inner, outer)) + + if not count: + add('.attribute InnerClasses "\\0\\0"') + +def disOtherClassAttribute(name_ind, name, bytes_, add, poolm): + assert(name != 'InnerClasses') + if name == 'EnclosingMethod': + cls, nat = bytes_.get('>HH') + add('.enclosing method {} {}'.format(poolm.classref(cls), poolm.multiref(nat))) + return + disCFMAttribute(name_ind, name, bytes_, add, poolm) + +def disassemble(cls): + lines = [] + add = lines.append + poolm = PoolManager(cls.cpool) + + # def add(s): print s + add('.version {0[0]} {0[1]}'.format(cls.version)) + + class_attributes = getAttributesDict(cls) + if 'SourceFile' in class_attributes: + bytes_ = binUnpacker(class_attributes['SourceFile'].pop()[1]) + val_ind = bytes_.get('>H') + add('.source {}'.format(poolm.utfref(val_ind))) + + if 'BootstrapMethods' in class_attributes: + bytes_ = binUnpacker(class_attributes['BootstrapMethods'].pop()[1]) + count = bytes_.get('>H') + for _ in range(count): + arg1, argc = bytes_.get('>HH') + args = (arg1,) + bytes_.get('>'+'H'*argc, forceTuple=True) + poolm.bootstrap_methods.append(args) + + cflags = ' '.join(map(str.lower, cls.flags)) + add('.class {} {}'.format(cflags, poolm.classref(cls.this))) + add('.super {}'.format(poolm.classref(cls.super))) + for ii in cls.interfaces_raw: + add('.implements {}'.format(poolm.classref(ii))) + + for name in class_attributes: + if name == "InnerClasses": + assert(len(class_attributes[name]) == 1) + for name_ind, (length, attr) in class_attributes[name]: + disInnerClassesAttribute(name_ind, length, binUnpacker(attr), add, poolm) + else: + for name_ind, attr in class_attributes[name]: + disOtherClassAttribute(name_ind, name, binUnpacker(attr), add, poolm) + + add('') + for field in cls.fields: + fflags = ' '.join(map(str.lower, field.flags)) + const = getConstValue(field) + + if const is not None: + add('.field {} {} {} = {}'.format(fflags, poolm.utfref(field.name_id), poolm.utfref(field.desc_id), poolm.ldc(const))) + else: + add('.field {} {} {}'.format(fflags, poolm.utfref(field.name_id), poolm.utfref(field.desc_id))) + + facount = 0 + for name_ind, name, attr in getAttributeTriples(field): + if name == 'ConstantValue' and field.static: + continue + disMethodAttribute(name_ind, name, binUnpacker(attr), add, poolm) + facount += 1 + if facount > 0: + add('.end field') + add('') + + add('') + + for method in cls.methods: + disMethod(method, add, poolm) + add('') + + poolm.printConstDefs(add) + return '\n'.join(lines) \ No newline at end of file diff --git a/own/krakatau/Krakatau/Krakatau/assembler/instructions.py b/own/krakatau/Krakatau/Krakatau/assembler/instructions.py new file mode 100644 --- /dev/null +++ b/own/krakatau/Krakatau/Krakatau/assembler/instructions.py @@ -0,0 +1,11 @@ +instrs_noarg = ('nop', 'aconst_null', 'iconst_m1', 'iconst_0', 'iconst_1', 'iconst_2', 'iconst_3', 'iconst_4', 'iconst_5', 'lconst_0', 'lconst_1', 'fconst_0', 'fconst_1', 'fconst_2', 'dconst_0', 'dconst_1', 'iload_0', 'iload_1', 'iload_2', 'iload_3', 'lload_0', 'lload_1', 'lload_2', 'lload_3', 'fload_0', 'fload_1', 'fload_2', 'fload_3', 'dload_0', 'dload_1', 'dload_2', 'dload_3', 'aload_0', 'aload_1', 'aload_2', 'aload_3', 'iaload', 'laload', 'faload', 'daload', 'aaload', 'baload', 'caload', 'saload', 'istore_0', 'istore_1', 'istore_2', 'istore_3', 'lstore_0', 'lstore_1', 'lstore_2', 'lstore_3', 'fstore_0', 'fstore_1', 'fstore_2', 'fstore_3', 'dstore_0', 'dstore_1', 'dstore_2', 'dstore_3', 'astore_0', 'astore_1', 'astore_2', 'astore_3', 'iastore', 'lastore', 'fastore', 'dastore', 'aastore', 'bastore', 'castore', 'sastore', 'pop', 'pop2', 'dup', 'dup_x1', 'dup_x2', 'dup2', 'dup2_x1', 'dup2_x2', 'swap', 'iadd', 'ladd', 'fadd', 'dadd', 'isub', 'lsub', 'fsub', 'dsub', 'imul', 'lmul', 'fmul', 'dmul', 'idiv', 'ldiv', 'fdiv', 'ddiv', 'irem', 'lrem', 'frem', 'drem', 'ineg', 'lneg', 'fneg', 'dneg', 'ishl', 'lshl', 'ishr', 'lshr', 'iushr', 'lushr', 'iand', 'land', 'ior', 'lor', 'ixor', 'lxor', 'i2l', 'i2f', 'i2d', 'l2i', 'l2f', 'l2d', 'f2i', 'f2l', 'f2d', 'd2i', 'd2l', 'd2f', 'i2b', 'i2c', 'i2s', 'lcmp', 'fcmpl', 'fcmpg', 'dcmpl', 'dcmpg', 'ireturn', 'lreturn', 'freturn', 'dreturn', 'areturn', 'return', 'arraylength', 'athrow', 'monitorenter', 'monitorexit') + +instrs_int = ('bipush', 'sipush', 'iload', 'lload', 'fload', 'dload', 'aload', 'istore', 'lstore', 'fstore', 'dstore', 'astore', 'ret') + +instrs_lbl = ('ifeq', 'ifne', 'iflt', 'ifge', 'ifgt', 'ifle', 'if_icmpeq', 'if_icmpne', 'if_icmplt', 'if_icmpge', 'if_icmpgt', 'if_icmple', 'if_acmpeq', 'if_acmpne', 'goto', 'jsr', 'ifnull', 'ifnonnull', 'goto_w', 'jsr_w') + +instrs_cp = ('ldc', 'ldc_w', 'ldc2_w', 'getstatic', 'putstatic', 'getfield', 'putfield', 'invokevirtual', 'invokespecial', 'invokestatic', 'invokedynamic', 'new', 'anewarray', 'checkcast', 'instanceof') + +instrs_other = ('iinc', 'tableswitch', 'lookupswitch', 'invokeinterface', 'newarray', 'wide', 'multianewarray') + +allinstructions = ('nop', 'aconst_null', 'iconst_m1', 'iconst_0', 'iconst_1', 'iconst_2', 'iconst_3', 'iconst_4', 'iconst_5', 'lconst_0', 'lconst_1', 'fconst_0', 'fconst_1', 'fconst_2', 'dconst_0', 'dconst_1', 'bipush', 'sipush', 'ldc', 'ldc_w', 'ldc2_w', 'iload', 'lload', 'fload', 'dload', 'aload', 'iload_0', 'iload_1', 'iload_2', 'iload_3', 'lload_0', 'lload_1', 'lload_2', 'lload_3', 'fload_0', 'fload_1', 'fload_2', 'fload_3', 'dload_0', 'dload_1', 'dload_2', 'dload_3', 'aload_0', 'aload_1', 'aload_2', 'aload_3', 'iaload', 'laload', 'faload', 'daload', 'aaload', 'baload', 'caload', 'saload', 'istore', 'lstore', 'fstore', 'dstore', 'astore', 'istore_0', 'istore_1', 'istore_2', 'istore_3', 'lstore_0', 'lstore_1', 'lstore_2', 'lstore_3', 'fstore_0', 'fstore_1', 'fstore_2', 'fstore_3', 'dstore_0', 'dstore_1', 'dstore_2', 'dstore_3', 'astore_0', 'astore_1', 'astore_2', 'astore_3', 'iastore', 'lastore', 'fastore', 'dastore', 'aastore', 'bastore', 'castore', 'sastore', 'pop', 'pop2', 'dup', 'dup_x1', 'dup_x2', 'dup2', 'dup2_x1', 'dup2_x2', 'swap', 'iadd', 'ladd', 'fadd', 'dadd', 'isub', 'lsub', 'fsub', 'dsub', 'imul', 'lmul', 'fmul', 'dmul', 'idiv', 'ldiv', 'fdiv', 'ddiv', 'irem', 'lrem', 'frem', 'drem', 'ineg', 'lneg', 'fneg', 'dneg', 'ishl', 'lshl', 'ishr', 'lshr', 'iushr', 'lushr', 'iand', 'land', 'ior', 'lor', 'ixor', 'lxor', 'iinc', 'i2l', 'i2f', 'i2d', 'l2i', 'l2f', 'l2d', 'f2i', 'f2l', 'f2d', 'd2i', 'd2l', 'd2f', 'i2b', 'i2c', 'i2s', 'lcmp', 'fcmpl', 'fcmpg', 'dcmpl', 'dcmpg', 'ifeq', 'ifne', 'iflt', 'ifge', 'ifgt', 'ifle', 'if_icmpeq', 'if_icmpne', 'if_icmplt', 'if_icmpge', 'if_icmpgt', 'if_icmple', 'if_acmpeq', 'if_acmpne', 'goto', 'jsr', 'ret', 'tableswitch', 'lookupswitch', 'ireturn', 'lreturn', 'freturn', 'dreturn', 'areturn', 'return', 'getstatic', 'putstatic', 'getfield', 'putfield', 'invokevirtual', 'invokespecial','invokestatic', 'invokeinterface', 'invokedynamic', 'new', 'newarray', 'anewarray', 'arraylength', 'athrow', 'checkcast', 'instanceof', 'monitorenter', 'monitorexit', 'wide', 'multianewarray', 'ifnull', 'ifnonnull', 'goto_w', 'jsr_w') \ No newline at end of file diff --git a/own/krakatau/Krakatau/Krakatau/assembler/parse.py b/own/krakatau/Krakatau/Krakatau/assembler/parse.py new file mode 100644 --- /dev/null +++ b/own/krakatau/Krakatau/Krakatau/assembler/parse.py @@ -0,0 +1,554 @@ +import ast, struct +import itertools + +from ..classfile import ClassFile +from ..method import Method +from ..field import Field + +#Important to import tokens here even though it appears unused, as ply uses it +from .tokenize import tokens, wordget, flags +from .assembler import PoolRef + +#Specify the starting symbol +start = 'top' + +############################################################################### +name_counter = itertools.count() +def addRule(func, name, *rhs_rules): + def _inner(p): + func(p) + _inner.__doc__ = name + ' : ' + '\n| '.join(rhs_rules) + fname = 'p_{}'.format(next(name_counter)) + globals()[fname] = _inner + +def list_sub(p):p[0] = p[1] + p[2:] +def listRule(name): #returns a list + name2 = name + 's' + addRule(list_sub, name2, '{} {}'.format(name2, name), 'empty') + +def nothing(p):pass +def assign1(p):p[0] = p[1] +def assign2(p):p[0] = p[2] +def upper1(p): p[0] = p[1].upper() + +# Common Rules ################################################################ +addRule(nothing, 'sep', 'sep NEWLINE', 'NEWLINE') + +def p_empty(p): + 'empty :' + p[0] = [] + +def p_intl(p): + '''intl : INT_LITERAL''' + p[0] = ast.literal_eval(p[1]) + +def p_longl(p): + '''longl : LONG_LITERAL''' + p[0] = ast.literal_eval(p[1][:-1]) + +#Todo - find a better way of handling floats +def parseFloat(s): + s = s[:-1] + if s.strip('-')[:2].lower() == '0x': + f = float.fromhex(s) + else: + f = float(s) + return struct.unpack('>i', struct.pack('>f', f))[0] + +def parseDouble(s): + if s.strip('-')[:2].lower() == '0x': + f = float.fromhex(s) + else: + f = float(s) + return struct.unpack('>q', struct.pack('>d', f))[0] + +def p_floatl(p): + '''floatl : FLOAT_LITERAL''' + p[0] = parseFloat(p[1]) +def p_doublel(p): + '''doublel : DOUBLE_LITERAL''' + p[0] = parseDouble(p[1]) + +#We can allow keywords as inline classnames as long as they aren't flag names +#which would be ambiguous. We don't allow directives to simplfy the grammar +#rules, since they wouldn't be valid identifiers anyway. +badwords = frozenset(map(str.lower, flags)) +badwords |= frozenset(k for k in wordget if '.' in k) +oktokens = frozenset(v for k,v in wordget.items() if k not in badwords) +addRule(assign1, 'notflag', 'WORD', 'STRING_LITERAL', *oktokens) + +def p_ref(p): + '''ref : CPINDEX''' + s = p[1][1:-1] + try: + i = int(s) + if 0 <= i <= 0xFFFF: + p[0] = PoolRef(index=i) + else: + p[0] = PoolRef(lbl=s) + except ValueError: + p[0] = PoolRef(lbl=s) + +def p_utf8_notref(p): + '''utf8_notref : notflag''' + p[0] = PoolRef('Utf8', p[1]) + +def p_class_notref(p): + '''class_notref : utf8_notref''' + p[0] = PoolRef('Class', p[1]) + +def p_string_notref(p): + '''string_notref : utf8_notref''' + p[0] = PoolRef('String', p[1]) + +def p_nat_notref(p): + '''nameandtype_notref : utf8ref utf8ref''' + p[0] = PoolRef('NameAndType', p[1], p[2]) + +def p_field_notref(p): + '''field_notref : classref nameandtyperef''' + p[0] = PoolRef('Field', p[1], p[2]) + +def p_method_notref(p): + '''method_notref : classref nameandtyperef''' + p[0] = PoolRef('Method', p[1], p[2]) + +def p_imethod_notref(p): + '''interfacemethod_notref : classref nameandtyperef''' + p[0] = PoolRef('InterfaceMethod', p[1], p[2]) + +#constant pool types related to InvokeDynamic handled later + +for _name in ('utf8','class', 'nameandtype', 'method', 'interfacemethod', 'methodhandle'): + addRule(assign1, '{}ref'.format(_name), '{}_notref'.format(_name), 'ref') + +############################################################################### +def p_classnoend(p): + '''classnoend : version_opt class_directive_lines classdec superdec interfacedecs class_directive_lines topitems''' + p[0] = tuple(p[1:]) + +addRule(assign1, 'classwithend', 'classnoend D_END CLASS sep') +listRule('classwithend') + +def p_top(p): + '''top : sep classwithends classnoend''' + p[0] = p[2] + [p[3]] +#case where all classes have an end +addRule(assign2, 'top', 'sep classwithends') + +def p_version(p): + '''version_opt : D_VERSION intl intl sep''' + p[0] = p[2], p[3] +addRule(assign1, 'version_opt', 'empty') + +############################################################################### +for c, type_ in zip('cmf', (ClassFile, Method, Field)): + _name = "{}flag".format(c) + addRule(upper1, _name, *list(type_.flagVals)) + listRule(_name) + +def p_classdec(p): + '''classdec : D_CLASS cflags classref sep + | D_INTERFACE cflags classref sep''' + #if interface, add interface to flags + p[0] = (p[1] == '.interface'), p[2], p[3] + +addRule(assign2, 'superdec', 'D_SUPER classref sep') +addRule(assign2, 'interfacedec', 'D_IMPLEMENTS classref sep') +listRule('interfacedec') + +addRule(assign1, 'class_directive', 'classattribute', 'innerlength_dir') +addRule(assign1, 'class_directive_line', 'class_directive sep') +listRule('class_directive_line') + +def p_topitem_c(p): + '''topitem : const_spec''' + p[0] = 'const', p[1] +def p_topitem_f(p): + '''topitem : field_spec''' + p[0] = 'field', p[1] +def p_topitem_m(p): + '''topitem : method_spec''' + p[0] = 'method', p[1] +listRule('topitem') + +############################################################################### +#invoke dynamic stuff +from .codes import handle_codes +_handle_token_types = set(wordget.get(x, 'WORD') for x in handle_codes) +def p_handle(p): + p[0] = handle_codes[p[1]] +p_handle.__doc__ = "handlecode : " + '\n| '.join(_handle_token_types) + +#The second argument's type depends on the code, so we require an explicit reference for simplicity +def p_methodhandle_notref(p): + '''methodhandle_notref : handlecode ref''' + p[0] = PoolRef('MethodHandle', p[1], p[2]) + +def p_methodtype_notref(p): + '''methodtype_notref : utf8_notref''' + p[0] = PoolRef('Methodtype', p[1]) + +addRule(assign1, 'bootstrap_arg', 'ref') #TODO - allow inline constants and strings? +listRule('bootstrap_arg') + +def p_invokedynamic_notref(p): + '''invokedynamic_notref : methodhandleref bootstrap_args COLON nameandtyperef''' + args = [p[1]] + p[2] + [p[4]] + p[0] = PoolRef('InvokeDynamic', *args) + +############################################################################### +def p_const_spec(p): + '''const_spec : D_CONST ref EQUALS const_rhs sep''' + p[0] = p[2], p[4] + +def assignPoolSingle(typen): + def inner(p): + p[0] = PoolRef(typen, p[2]) + return inner + +addRule(assign1, 'const_rhs', 'ref') +for tt in ['UTF8', 'CLASS','STRING','NAMEANDTYPE','FIELD','METHOD','INTERFACEMETHOD', + 'METHODHANDLE','METHODTYPE','INVOKEDYNAMIC']: + addRule(assign2, 'const_rhs', '{} {}_notref'.format(tt, tt.lower())) + +#these are special cases, since they take a single argument +#and the notref version can't have a ref as its argument due to ambiguity +for ptype in ('Class','String','MethodType'): + addRule(assignPoolSingle(ptype), 'const_rhs', ptype.upper() + ' ref') + +for ptype in ('Int','Float','Long','Double'): + addRule(assignPoolSingle(ptype), 'const_rhs', '{} {}l'.format(ptype.upper(), ptype.lower())) +############################################################################### + + +def p_field_spec(p): + '''field_spec : D_FIELD fflags utf8ref utf8ref field_constval fieldattribute_list''' + p[0] = p[2:7] + +addRule(nothing, 'field_constval', 'empty') +addRule(assign2, 'field_constval', 'EQUALS ref', + 'EQUALS ldc1_notref', + 'EQUALS ldc2_notref') + +#Sadly, we must only allow .end field when at least one attribute is specified +#in order to avoid grammatical ambiguity. JasminXT does not share this problem +#because it lacks the .end class syntax which causes the conflict +def p_field_attrlist1(p): + '''field_al_nonempty : fieldattribute sep field_al_nonempty''' + p[0] = [p[1]]+ p[3] +def p_field_attrlist2(p): + '''field_al_nonempty : fieldattribute sep D_END FIELD sep''' + p[0] = [p[1]] + +addRule(assign2, 'fieldattribute_list', 'sep field_al_nonempty', 'sep empty') + + +def p_method_spec(p): + '''method_spec : defmethod statements endmethod''' + p[0] = p[1],p[2] + +def p_defmethod_0(p): + '''defmethod : D_METHOD mflags jas_meth_namedesc sep''' + p[0] = p[2],p[3] +def p_defmethod_1(p): + '''defmethod : D_METHOD mflags utf8ref COLON utf8ref sep''' + p[0] = p[2],(p[3], p[5]) + +def p_jas_meth_namedesc(p): + '''jas_meth_namedesc : WORD''' + name, paren, desc = p[1].rpartition('(') + name = PoolRef('Utf8', name) + desc = PoolRef('Utf8', paren+desc) + p[0] = name, desc +addRule(nothing, 'endmethod', 'D_END METHOD sep') + +def p_statement_0(p): + '''statement : method_directive sep''' + p[0] = False, p[1] +def p_statement_1(p): + '''statement : code_directive sep''' + p[0] = True, (False, p[1]) +def p_statement_2(p): + '''statement : empty instruction sep + | lbldec instruction sep + | lbldec sep''' + p[0] = True, (True, ((p[1] or None), p[2])) +listRule('statement') + +addRule(assign1, 'lbldec', 'lbl COLON') +addRule(assign1, 'method_directive', 'methodattribute') +addRule(assign1, 'code_directive', 'limit_dir', 'except_dir','localvar_dir','linenumber_dir','stack_dir', 'generic_codeattribute_dir') + +def p_limit_dir(p): + '''limit_dir : D_LIMIT LOCALS intl + | D_LIMIT STACK intl''' + p[0] = p[1], (p[2], p[3]) + +def p_except_dir(p): + '''except_dir : D_CATCH classref FROM lbl TO lbl USING lbl''' + p[0] = p[1], (p[2], p[4], p[6], p[8]) + +def p_linenumber_dir(p): + '''linenumber_dir : D_LINE intl''' + p[0] = p[1], p[2] + +def p_localvar_dir(p): + '''localvar_dir : D_VAR intl IS utf8ref utf8ref FROM lbl TO lbl''' + p[0] = p[1], (p[2], p[4], p[5], p[7], p[9]) + +def p_instruction(p): + '''instruction : OP_NONE + | OP_INT intl + | OP_INT_INT intl intl + | OP_LBL lbl + | OP_FIELD fieldref_or_jas + | OP_METHOD methodref_or_jas + | OP_METHOD_INT imethodref_or_jas intl + | OP_DYNAMIC ref + | OP_CLASS classref + | OP_CLASS_INT classref intl + | OP_LDC1 ldc1_ref + | OP_LDC2 ldc2_ref + | OP_NEWARR nacode + | OP_LOOKUPSWITCH luswitch + | OP_TABLESWITCH tblswitch + | OP_WIDE wide_instr + ''' + if p[1] == 'invokenonvirtual': + p[1] = 'invokespecial' + p[0] = tuple(p[1:]) + #these instructions have 0 padding at the end + #this is kind of an ungly hack, but the best way I could think of + if p[1] in ('invokeinterface','invokedynamic'): + p[0] += (0,) + +addRule(assign1, 'lbl', 'WORD') +addRule(assign1, 'fieldref_or_jas', 'jas_fieldref', 'ref', 'inline_fieldref') +def p_jas_fieldref(p): + '''jas_fieldref : WORD WORD''' + class_, sep, name = p[1].replace('.','/').rpartition('/') + + desc = PoolRef('Utf8', p[2]) + class_ = PoolRef('Class', PoolRef('Utf8', class_)) + name = PoolRef('Utf8', name) + nt = PoolRef('NameAndType', name, desc) + p[0] = PoolRef('Field', class_, nt) + +#This is an ugly hack to work around the fact that Jasmin syntax would otherwise be impossible to +#handle with a LALR(1) parser +def p_inline_fieldref_1(p): + '''inline_fieldref : WORD nameandtyperef + | STRING_LITERAL nameandtyperef''' + class_ = PoolRef('Class', PoolRef('Utf8', p[1])) + p[0] = PoolRef('Field', class_, p[2]) +def p_inline_fieldref_2(p): + '''inline_fieldref : ref nameandtyperef''' + p[0] = PoolRef('Field', p[1], p[2]) + + +def p_jas_meth_classnamedesc(p): + '''jas_methodref : WORD''' + name, paren, desc = p[1].rpartition('(') + class_, sep, name = name.replace('.','/').rpartition('/') + desc = paren + desc + + class_ = PoolRef('Class', PoolRef('Utf8', class_)) + nt = PoolRef('NameAndType', PoolRef('Utf8', name), PoolRef('Utf8', desc)) + p[0] = class_, nt + +addRule(assign1, 'methodref_or_jas', 'methodref') +def p_methodref_or_jas(p): + '''methodref_or_jas : jas_methodref''' + p[0] = PoolRef('Method', *p[1]) + +addRule(assign1, 'imethodref_or_jas', 'interfacemethodref') +def p_imethodref_or_jas(p): + '''imethodref_or_jas : jas_methodref''' + p[0] = PoolRef('InterfaceMethod', *p[1]) + + +from .codes import newarr_codes +_newarr_token_types = set(wordget.get(x, 'WORD') for x in newarr_codes) +def p_nacode(p): + p[0] = newarr_codes[p[1]] +p_nacode.__doc__ = "nacode : " + '\n| '.join(_newarr_token_types) + +addRule(assign1, 'ldc1_ref', 'ldc1_notref', 'ref') +def p_ldc1_notref_string(p): + '''ldc1_notref : STRING_LITERAL''' + p[0] = PoolRef('String', PoolRef('Utf8', p[1])) +def p_ldc1_notref_int(p): + '''ldc1_notref : intl''' + p[0] = PoolRef('Int', p[1]) +def p_ldc1_notref_float(p): + '''ldc1_notref : floatl''' + p[0] = PoolRef('Float', p[1]) + +addRule(assign1, 'ldc2_ref', 'ldc2_notref', 'ref') +def p_ldc2_notref_long(p): + '''ldc2_notref : longl''' + p[0] = PoolRef('Long', p[1]) +def p_ldc2_notref_double(p): + '''ldc2_notref : doublel''' + p[0] = PoolRef('Double', p[1]) + +def p_defaultentry(p): + '''defaultentry : DEFAULT COLON lbl''' + p[0] = p[3] + +def p_luentry(p): + '''luentry : intl COLON lbl sep''' + p[0] = p[1], p[3] +listRule('luentry') + +addRule(assign1, 'tblentry', 'lbl sep') +listRule('tblentry') + +def p_lookupswitch(p): + '''luswitch : empty sep luentrys defaultentry''' + p[0] = p[1], p[3], p[4] + +def p_tableswitch(p): + '''tblswitch : intl sep tblentrys defaultentry''' + p[0] = p[1], p[3], p[4] + +def p_wide_instr(p): + '''wide_instr : OP_INT intl + | OP_INT_INT intl intl''' + p[0] = p[1], tuple(p[2:]) + +####################################################################### +# Explicit Attributes +addRule(assign1, 'cfmattribute', 'annotation_dir', 'signature_dir', 'generic_attribute_dir') +addRule(assign1, 'classattribute', 'cfmattribute', 'sourcefile_dir', 'inner_dir', 'enclosing_dir') +addRule(assign1, 'fieldattribute', 'cfmattribute') +addRule(assign1, 'methodattribute', 'cfmattribute', 'throws_dir', 'annotation_param_dir', 'annotation_def_dir') + +#Class, field, method +def p_annotation_dir(p): + '''annotation_dir : D_RUNTIMEVISIBLE annotation + | D_RUNTIMEINVISIBLE annotation''' + p[0] = p[1], (None, p[2]) + +def p_signature_dir(p): + '''signature_dir : D_SIGNATURE utf8ref''' + p[0] = p[1], p[2] + +#Class only +def p_sourcefile_dir(p): + '''sourcefile_dir : D_SOURCE utf8ref''' + p[0] = p[1], p[2] + +def p_inner_dir(p): + '''inner_dir : D_INNER cflags utf8ref classref classref''' + p[0] = p[1], (p[4],p[5],p[3],p[2]) #use JasminXT's (flags, name, inner, outer) order but switch internally to correct order + +def p_enclosing_dir(p): + '''enclosing_dir : D_ENCLOSING METHOD classref nameandtyperef''' + p[0] = p[1], (p[3], p[4]) + +#This is included here even though strictly speaking, it's not an attribute. Rather it's a directive that affects the assembly +#of the InnerClasses attribute +def p_innerlength_dir(p): + '''innerlength_dir : D_INNERLENGTH intl''' + p[0] = p[1], p[2] + + +#Method only +def p_throws_dir(p): + '''throws_dir : D_THROWS classref''' + p[0] = p[1], p[2] + +def p_annotation_param_dir(p): + '''annotation_param_dir : D_RUNTIMEVISIBLE PARAMETER intl annotation + | D_RUNTIMEINVISIBLE PARAMETER intl annotation''' + p[0] = p[1], (p[3], p[4]) +def p_annotation_def_dir(p): + '''annotation_def_dir : D_ANNOTATIONDEFAULT element_value''' + p[0] = p[1], p[2] + +#Generic +def p_generic_attribute_dir(p): + '''generic_attribute_dir : D_ATTRIBUTE utf8ref STRING_LITERAL''' + p[0] = p[1], (p[2], p[3]) + +def p_generic_codeattribute_dir(p): + '''generic_codeattribute_dir : D_CODEATTRIBUTE utf8ref STRING_LITERAL''' + p[0] = p[1], (p[2], p[3]) + +####################################################################### +#Stack map stuff +addRule(nothing, 'endstack', 'D_END STACK') #directives are not expected to end with a sep + +def assign1All(p):p[0] = tuple(p[1:]) +addRule(assign1All, 'verification_type', 'TOP', 'INTEGER', 'FLOAT', 'DOUBLE', 'LONG', 'NULL', 'UNINITIALIZEDTHIS', + 'OBJECT classref', 'UNINITIALIZED lbl') +listRule('verification_type') +addRule(assign2, 'locals_vtlist', 'LOCALS verification_types sep') +addRule(assign2, 'stack_vtlist', 'STACK verification_types sep') + +def p_stack_dir(p): + '''stack_dir_rest : SAME + | SAME_EXTENDED + | CHOP intl + | SAME_LOCALS_1_STACK_ITEM sep stack_vtlist endstack + | SAME_LOCALS_1_STACK_ITEM_EXTENDED sep stack_vtlist endstack + | APPEND sep locals_vtlist endstack + | FULL sep locals_vtlist stack_vtlist endstack''' + p[0] = '.stackmap', tuple(p[1:]) +addRule(assign2, 'stack_dir', 'D_STACK stack_dir_rest') +####################################################################### +#Annotation stuff +from .codes import et_tags +primtags = set(wordget.get(x, 'WORD') for x in 'byte char double int float long short boolean string'.split()) +addRule(assign1, 'primtag', *primtags) +addRule(assign1, 'ldc_any', 'ldc1_notref', 'ldc2_notref', 'ref') + +def p_element_value_0(p): + '''element_value : primtag ldc_any + | CLASS utf8ref + | ENUM utf8ref utf8ref + | ARRAY sep element_array''' + p[0] = et_tags[p[1]], tuple(p[2:]) +def p_element_value_1(p): + '''element_value : annotation''' + p[0] = '@', (p[1],) + +addRule(assign1, 'element_value_line', 'element_value sep') +listRule('element_value_line') +addRule(assign1, 'element_array', 'element_value_lines D_END ARRAY') + +def p_key_ev_line(p): + '''key_ev_line : utf8ref EQUALS element_value_line''' + p[0] = p[1], p[3] +listRule('key_ev_line') + +def p_annotation(p): + '''annotation : ANNOTATION utf8ref sep key_ev_lines D_END ANNOTATION''' + p[0] = p[2], p[4] +####################################################################### + +def p_error(p): + if p is None: + print "Syntax error: unexpected EOF" + else: #remember to subtract 1 from line number since we had a newline at the start of the file + print "Syntax error at line {}: unexpected token {!r}".format(p.lineno-1, p.value) + + #Ugly hack since Ply doesn't provide any useful error information + import inspect + frame = inspect.currentframe() + cvars = frame.f_back.f_locals + print 'Expected:', ', '.join(cvars['actions'][cvars['state']].keys()) + print 'Found:', cvars['ltype'] + print 'Current stack:', cvars['symstack'] + + #Discard the rest of the input so that Ply doesn't attempt error recovery + from ply import yacc + tok = yacc.token() + while tok is not None: + tok = yacc.token() + +def makeParser(**kwargs): + from ply import yacc + return yacc.yacc(**kwargs) \ No newline at end of file diff --git a/own/krakatau/Krakatau/Krakatau/assembler/tokenize.py b/own/krakatau/Krakatau/Krakatau/assembler/tokenize.py new file mode 100644 --- /dev/null +++ b/own/krakatau/Krakatau/Krakatau/assembler/tokenize.py @@ -0,0 +1,140 @@ +import ast + +from ..classfile import ClassFile +from ..method import Method +from ..field import Field +from .. import constant_pool +from . import instructions as ins +from . import codes + +directives = 'CLASS','INTERFACE','SUPER','IMPLEMENTS','CONST','FIELD','METHOD','END','LIMIT','CATCH','SOURCE','LINE','VAR','THROWS', +directives += 'VERSION', 'STACK', 'RUNTIMEVISIBLE', 'RUNTIMEINVISIBLE', 'ANNOTATIONDEFAULT', 'INNER', 'ENCLOSING', 'SIGNATURE', +directives += 'ATTRIBUTE', 'CODEATTRIBUTE', 'INNERLENGTH' +keywords = ['CLASS','METHOD','FIELD','LOCALS','STACK','FROM','TO','USING','DEFAULT','IS'] +keywords += ['SAME','SAME_LOCALS_1_STACK_ITEM','SAME_LOCALS_1_STACK_ITEM_EXTENDED','CHOP','SAME_EXTENDED','APPEND','FULL'] +keywords += ['ANNOTATION','ARRAY','PARAMETER'] +flags = ClassFile.flagVals.keys() + Method.flagVals.keys() + Field.flagVals.keys() + +lowwords = set().union(keywords, flags) +casewords = set().union(codes.vt_keywords, constant_pool.name2Type.keys()) + +wordget = {} +wordget.update({w.lower():w.upper() for w in lowwords}) +wordget.update({w:w.upper() for w in casewords}) +wordget.update({'.'+w.lower():'D_'+w for w in directives}) + +assert(set(wordget).isdisjoint(ins.allinstructions)) +for op in ins.instrs_noarg: + wordget[op] = 'OP_NONE' +for op in ins.instrs_int: + wordget[op] = 'OP_INT' +for op in ins.instrs_lbl: + wordget[op] = 'OP_LBL' +for op in ('getstatic', 'putstatic', 'getfield', 'putfield'): + wordget[op] = 'OP_FIELD' +#support invokenonvirtual for backwards compatibility with Jasmin +for op in ('invokevirtual', 'invokespecial', 'invokestatic', 'invokenonvirtual'): + wordget[op] = 'OP_METHOD' +for op in ('new', 'anewarray', 'checkcast', 'instanceof'): + wordget[op] = 'OP_CLASS' +for op in ('wide','lookupswitch','tableswitch'): + wordget[op] = 'OP_' + op.upper() + +wordget['ldc'] = 'OP_LDC1' +wordget['ldc_w'] = 'OP_LDC1' +wordget['ldc2_w'] = 'OP_LDC2' +wordget['iinc'] = 'OP_INT_INT' +wordget['newarray'] = 'OP_NEWARR' +wordget['multianewarray'] = 'OP_CLASS_INT' +wordget['invokeinterface'] = 'OP_METHOD_INT' +wordget['invokedynamic'] = 'OP_DYNAMIC' + +for op in ins.allinstructions: + wordget.setdefault(op,op.upper()) + +#special PLY value From noreply at buildbot.pypy.org Mon Dec 8 16:45:01 2014 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 8 Dec 2014 16:45:01 +0100 (CET) Subject: [pypy-commit] benchmarks default: (cfbolz, arigo) Message-ID: <20141208154501.88B5B1D35D9@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r283:56cceac3bdf5 Date: 2014-12-08 15:45 +0000 http://bitbucket.org/pypy/benchmarks/changeset/56cceac3bdf5/ Log: (cfbolz, arigo) Add bm_krakatau. diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -82,7 +82,7 @@ 'spectral-norm', 'chaos', 'telco', 'go', 'pyflate-fast', 'raytrace-simple', 'crypto_pyaes', 'bm_mako', 'bm_chameleon', 'json_bench', 'pidigits', 'hexiom2', 'eparse', 'deltablue', - 'bm_dulwich_log']: + 'bm_dulwich_log', 'bm_krakatau']: _register_new_bm(name, name, globals(), **opts.get(name, {})) for name in ['names', 'iteration', 'tcp', 'pb', ]:#'web']:#, 'accepts']: diff --git a/own/bm_krakatau.py b/own/bm_krakatau.py --- a/own/bm_krakatau.py +++ b/own/bm_krakatau.py @@ -1,9 +1,9 @@ -import sys, os +import sys, os, cStringIO import time import util, optparse -sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'krakatau/Krakatau')) -print sys.path +this_dir = os.path.dirname(__file__) +sys.path.insert(0, os.path.join(this_dir, 'krakatau/Krakatau')) import Krakatau.ssa from Krakatau.environment import Environment @@ -34,7 +34,7 @@ return s def decompileClass(): - path = ['krakatau/rt.jar'] + path = [os.path.join(this_dir, 'krakatau/rt.jar')] targets = ['javax/swing/plaf/nimbus/ToolBarSouthState'] e = Environment() for part in path: @@ -49,11 +49,16 @@ def main(n): l = [] - for i in range(n): - t0 = time.time() - decompileClass() - time_elapsed = time.time() - t0 - l.append(time_elapsed) + old_stdout = sys.stdout + sys.stdout = cStringIO.StringIO() + try: + for i in range(n): + t0 = time.time() + decompileClass() + time_elapsed = time.time() - t0 + l.append(time_elapsed) + finally: + sys.stdout = old_stdout return l if __name__ == "__main__": From noreply at buildbot.pypy.org Mon Dec 8 17:15:26 2014 From: noreply at buildbot.pypy.org (arigo) Date: Mon, 8 Dec 2014 17:15:26 +0100 (CET) Subject: [pypy-commit] benchmarks default: (cfbolz, arigo) Message-ID: <20141208161526.8ADDB1D35D6@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r284:ed338f71e5f7 Date: 2014-12-08 16:15 +0000 http://bitbucket.org/pypy/benchmarks/changeset/ed338f71e5f7/ Log: (cfbolz, arigo) Add the MDP code (Robert Grosse on pypy-dev) diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -82,7 +82,7 @@ 'spectral-norm', 'chaos', 'telco', 'go', 'pyflate-fast', 'raytrace-simple', 'crypto_pyaes', 'bm_mako', 'bm_chameleon', 'json_bench', 'pidigits', 'hexiom2', 'eparse', 'deltablue', - 'bm_dulwich_log', 'bm_krakatau']: + 'bm_dulwich_log', 'bm_krakatau', 'bm_mdp']: _register_new_bm(name, name, globals(), **opts.get(name, {})) for name in ['names', 'iteration', 'tcp', 'pb', ]:#'web']:#, 'accepts']: diff --git a/own/bm_mdp.py b/own/bm_mdp.py new file mode 100644 --- /dev/null +++ b/own/bm_mdp.py @@ -0,0 +1,299 @@ +import collections, time +from collections import defaultdict as ddict +from fractions import Fraction as frac + +def tarjanSCC(roots, getChildren): + """Return a list of strongly connected components in a graph. If getParents is passed instead of getChildren, the result will be topologically sorted. + + roots - list of root nodes to search from + getChildren - function which returns children of a given node + """ + + sccs = [] + indexCounter = itertools.count() + index = {} + lowlink = {} + removed = set() + subtree = [] + + #Use iterative version to avoid stack limits for large datasets + stack = [(node, 0) for node in roots] + while stack: + current, state = stack.pop() + if state == 0: #before recursing + if current not in index: #if it's in index, it was already visited (possibly earlier on the current search stack) + lowlink[current] = index[current] = next(indexCounter) + subtree.append(current) + + stack.append((current, 1)) + stack.extend((child, 0) for child in getChildren(current) if child not in removed) + else: #after recursing + children = [child for child in getChildren(current) if child not in removed] + for child in children: + if index[child] <= index[current]: #backedge (or selfedge) + lowlink[current] = min(lowlink[current], index[child]) + else: + lowlink[current] = min(lowlink[current], lowlink[child]) + assert(lowlink[current] <= index[current]) + + if index[current] == lowlink[current]: + scc = [] + while not scc or scc[-1] != current: + scc.append(subtree.pop()) + + sccs.append(tuple(scc)) + removed.update(scc) + return sccs + +def topoSort(roots, getParents): + """Return a topological sorting of nodes in a graph. + + roots - list of root nodes to search from + getParents - function which returns the parents of a given node + """ + + results = [] + visited = set() + + #Use iterative version to avoid stack limits for large datasets + stack = [(node,0) for node in roots] + while stack: + current, state = stack.pop() + if state == 0: #before recursing + if current not in visited: + visited.add(current) + stack.append((current,1)) + stack.extend((parent,0) for parent in getParents(current)) + else: #after recursing + assert(current in visited) + results.append(current) + return results + +def getDamages(L, A, D, B, stab, te): + x = (2*L)//5 + x = ((x+2)*A*B)//(D*50) + 2 + if stab: + x += x // 2 + x = int(x * te) + return [(x*z)//255 for z in range(217,256)] + +def getCritDist(L, p, A1, A2, D1, D2, B, stab, te): + p = min(p, frac(1)) + norm = getDamages(L, A1, D1, B, stab, te) + crit = getDamages(L*2, A2, D2, B, stab, te) + + dist = ddict(frac) + for mult, vals in zip([1-p, p], [norm, crit]): + mult /= len(vals) + for x in vals: + dist[x] += mult + return dist + +def getAvg(dd): + return float(sum(k*v for k,v in dd)) + +def plus12(x): return x + x//8 +def plus50(x): return x + x//2 + +def replace(t, i, v): + if t[i] != v: + temp = t[:i] + (v,) + t[i+1:] + t = type(t)._make(temp) + return t + + +poke_stats_t = collections.namedtuple('poke_stats_t', ['lvl', 'basespeed', 'hp', 'atk', 'df', 'speed', 'spec']) +stats_t = collections.namedtuple('stats_t', ['atk', 'df', 'speed', 'spec']) +NOMODS = stats_t(0,0,0,0) + + +fixeddata_t = collections.namedtuple('fixeddata_t', ['maxhp', 'stats', 'lvl', 'badges','basespeed']) +halfstate_t = collections.namedtuple('halfstate_t', ['fixed','hp','status','statmods','stats']) + + +_statmod_table = [frac(i,2) for i in range(3,9)] +_statmod_table = [1/x for x in reversed(_statmod_table)] + [frac(1)] + _statmod_table + +def applyHPChange(hstate, change): + hp = min(hstate.fixed.maxhp, max(0, hstate.hp + change)) + return hstate._replace(hp=hp) + +def applyBadgeBoosts(badges, stats): + return stats_t(*[(plus12(x) if b else x) for x,b in zip(stats, badges)]) + +attack_stats_t = collections.namedtuple('attack_stats_t', ['power', 'isspec', 'stab', 'te', 'crit']) +attack_data = { + 'Ember': attack_stats_t(40, True, True, 0.5, False), + 'Dig': attack_stats_t(100, False, False, 1, False), + 'Slash': attack_stats_t(70, False, False, 1, True), + 'Water Gun': attack_stats_t(40, True, True, 2, False), + 'Bubblebeam': attack_stats_t(65, True, True, 2, False), +} + +def _applyActionSide1(state, act): + me, them, extra = state + + if act == 'Super Potion': + me = applyHPChange(me, 50) + return {(me, them, extra): frac(1)} + + mdata = attack_data[act] + aind = 3 if mdata.isspec else 0 + dind = 3 if mdata.isspec else 1 + pdiv = 64 if mdata.crit else 512 + dmg_dist = getCritDist(me.fixed.lvl, frac(me.fixed.basespeed, pdiv), + me.stats[aind], me.fixed.stats[aind], them.stats[dind], them.fixed.stats[dind], + mdata.power, mdata.stab, mdata.te) + + dist = ddict(frac) + for dmg, p in dmg_dist.items(): + them2 = applyHPChange(them, -dmg) + dist[me, them2, extra] += p + return dist + +def _applyAction(state, side, act): + if side == 0: + return _applyActionSide1(state, act) + else: + me, them, extra = state + dist = _applyActionSide1((them, me, extra), act) + return {(k[1], k[0], k[2]): v for k,v in dist.items()} + +def printstate(state): + return 'char {} star {}'.format(state[0].hp, state[1].hp) +def printsp(sp): + return '[{}, {}, {}]'.format(sp[0], printstate(sp[1]), ', '.join(map(str, sp[2:]))) + +class Battle(object): + def __init__(self): + self.successors = {} + self.min = ddict(float) + self.max = ddict(lambda:1.0) + self.frozen = set() + + self.win = 4, True + self.loss = 4, False + self.max[self.loss] = 0.0 + self.min[self.win] = 1.0 + self.frozen.update([self.win, self.loss]) + + def _getSuccessorsA(self, statep): + st, state = statep + for action in ['Dig', 'Super Potion']: + yield (1, state, action) + + def _applyActionPair(self, state, side1, act1, side2, act2, dist, pmult): + for newstate, p in _applyAction(state, side1, act1).items(): + if newstate[0].hp == 0: + newstatep = self.loss + elif newstate[1].hp == 0: + newstatep = self.win + else: + newstatep = 2, newstate, side2, act2 + dist[newstatep] += p*pmult + + def _getSuccessorsB(self, statep): + st, state, action = statep + dist = ddict(frac) + for eact, p in [('Water Gun', frac(64, 130)), ('Bubblebeam', frac(66, 130))]: + priority1 = state[0].stats.speed + 10000*(action == 'Super Potion') + priority2 = state[1].stats.speed + 10000*(action == 'X Defend') + + if priority1 > priority2: + self._applyActionPair(state, 0, action, 1, eact, dist, p) + elif priority1 < priority2: + self._applyActionPair(state, 1, eact, 0, action, dist, p) + else: + self._applyActionPair(state, 0, action, 1, eact, dist, p/2) + self._applyActionPair(state, 1, eact, 0, action, dist, p/2) + + return {k:float(p) for k,p in dist.items() if p>0} + + def _getSuccessorsC(self, statep): + st, state, side, action = statep + dist = ddict(frac) + for newstate, p in _applyAction(state, side, action).items(): + if newstate[0].hp == 0: + newstatep = self.loss + elif newstate[1].hp == 0: + newstatep = self.win + else: + newstatep = 0, newstate + dist[newstatep] += p + return {k:float(p) for k,p in dist.items() if p>0} + + def getSuccessors(self, statep): + try: + return self.successors[statep] + except KeyError: + st = statep[0] + if st == 0: + result = list(self._getSuccessorsA(statep)) + else: + if st == 1: + dist = self._getSuccessorsB(statep) + elif st == 2: + dist = self._getSuccessorsC(statep) + result = sorted(dist.items(), key=lambda t:(-t[1], t[0])) + self.successors[statep] = result + return result + + def getSuccessorsList(self, statep): + if statep[0] == 4: + return [] + temp = self.getSuccessors(statep) + if statep[0] != 0: + temp = zip(*temp)[0] if temp else [] + return temp + + def evaluate(self, tolerance=0.15): + badges = 1, 0, 0, 0 + + starfixed = fixeddata_t(59, stats_t(40, 44, 56, 50), 11, NOMODS, 115) + starhalf = halfstate_t(starfixed, 59, 0, NOMODS, stats_t(40, 44, 56, 50)) + charfixed = fixeddata_t(63, stats_t(39, 34, 46, 38), 26, badges, 65) + charhalf = halfstate_t(charfixed, 63, 0, NOMODS, applyBadgeBoosts(badges, stats_t(39, 34, 46, 38))) + initial_state = charhalf, starhalf, 0 + initial_statep = 0, initial_state + + dmin, dmax, frozen = self.min, self.max, self.frozen + stateps = topoSort([initial_statep], self.getSuccessorsList) + + itercount = 0 + while dmax[initial_statep] - dmin[initial_statep] > tolerance: + itercount += 1 + #print itercount, dmax[initial_statep] - dmin[initial_statep], len(frozen) + + for sp in stateps: + if sp in frozen: + continue + + if sp[0] == 0: #choice node + dmin[sp] = max(dmin[sp2] for sp2 in self.getSuccessors(sp)) + dmax[sp] = max(dmax[sp2] for sp2 in self.getSuccessors(sp)) + else: + dmin[sp] = sum(dmin[sp2]*p for sp2,p in self.getSuccessors(sp)) + dmax[sp] = sum(dmax[sp2]*p for sp2,p in self.getSuccessors(sp)) + if dmin[sp] >= dmax[sp]: + dmax[sp] = dmin[sp] = (dmin[sp] + dmax[sp])/2 + frozen.add(sp) + return (dmax[initial_statep] + dmin[initial_statep])/2 + +def main(n): + l = [] + for i in range(n): + t0 = time.time() + Battle().evaluate(0.192) + time_elapsed = time.time() - t0 + l.append(time_elapsed) + return l + +if __name__ == "__main__": + import util, optparse + parser = optparse.OptionParser( + usage="%prog [options]", + description="Test the performance of the MDP benchmark") + util.add_standard_options_to(parser) + options, args = parser.parse_args() + + util.run_benchmark(options, options.num_runs, main) From noreply at buildbot.pypy.org Tue Dec 9 16:07:03 2014 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 9 Dec 2014 16:07:03 +0100 (CET) Subject: [pypy-commit] pypy default: Kill old test. Fix old test. Message-ID: <20141209150703.21F7B1C09B2@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r74859:b23bf64e6925 Date: 2014-12-09 15:06 +0000 http://bitbucket.org/pypy/pypy/changeset/b23bf64e6925/ Log: Kill old test. Fix old test. diff --git a/rpython/jit/metainterp/test/test_list.py b/rpython/jit/metainterp/test/test_list.py --- a/rpython/jit/metainterp/test/test_list.py +++ b/rpython/jit/metainterp/test/test_list.py @@ -97,28 +97,6 @@ assert res == f(10) self.check_resops(setarrayitem_gc=0, call=0, getarrayitem_gc=0) - def test_vlist_alloc_and_set(self): - # the check_loops fails, because [non-null] * n is only supported - # if n < 15 (otherwise it is implemented as a residual call) - jitdriver = JitDriver(greens = [], reds = ['n']) - def f(n): - l = [1] * 20 - while n > 0: - jitdriver.can_enter_jit(n=n) - jitdriver.jit_merge_point(n=n) - l = [1] * 20 - l[3] = 5 - x = l[-17] + l[5] - 1 - if n < 3: - return x - n -= 1 - return l[0] - - res = self.meta_interp(f, [10], listops=True) - assert res == f(10) - py.test.skip("'[non-null] * n' for n >= 15 gives a residual call so far") - self.check_loops(setarrayitem_gc=0, getarrayitem_gc=0, call=0) - def test_arraycopy_simpleoptimize(self): def f(): l = [1, 2, 3, 4] diff --git a/rpython/jit/metainterp/test/test_send.py b/rpython/jit/metainterp/test/test_send.py --- a/rpython/jit/metainterp/test/test_send.py +++ b/rpython/jit/metainterp/test/test_send.py @@ -385,8 +385,7 @@ self.check_target_token_count(4) def test_two_behaviors(self): - py.test.skip("XXX fix me!!!!!!! problem in optimize.py") - myjitdriver = JitDriver(greens = [], reds = ['x', 'y']) + myjitdriver = JitDriver(greens = [], reds = ['y', 'x']) class Int: def __init__(self, value): self.value = value @@ -402,11 +401,6 @@ return x.value res = self.meta_interp(f, [len(cases)]) assert res == 110 - # The generated loops don't contain a new_with_vtable at all. This - # is true if we replace "if cases[y]" above with "if not cases[y]" - # -- so there is no good reason that it fails. - self.check_loops(new_with_vtable=0) - self.check_trace_count(2) def test_behavior_change_after_a_while(self): myjitdriver = JitDriver(greens = [], reds = ['y', 'x']) From noreply at buildbot.pypy.org Tue Dec 9 16:32:04 2014 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 9 Dec 2014 16:32:04 +0100 (CET) Subject: [pypy-commit] pypy default: Add "--verbose" as a cmdline option to translate.py Message-ID: <20141209153204.2CD4C1D3650@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r74860:4a5992cc2afd Date: 2014-12-09 16:30 +0100 http://bitbucket.org/pypy/pypy/changeset/4a5992cc2afd/ Log: Add "--verbose" as a cmdline option to translate.py diff --git a/rpython/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -129,7 +129,8 @@ default=False, cmdline=None), # misc - BoolOption("verbose", "Print extra information", default=False), + BoolOption("verbose", "Print extra information", default=False, + cmdline="--verbose"), StrOption("cc", "Specify compiler to use for compiling generated C", cmdline="--cc"), StrOption("profopt", "Specify profile based optimization script", cmdline="--profopt"), From noreply at buildbot.pypy.org Tue Dec 9 16:32:05 2014 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 9 Dec 2014 16:32:05 +0100 (CET) Subject: [pypy-commit] pypy default: (tanzim, arigo) Message-ID: <20141209153205.835D21D3650@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r74861:d49c95b3abf7 Date: 2014-12-09 16:31 +0100 http://bitbucket.org/pypy/pypy/changeset/d49c95b3abf7/ Log: (tanzim, arigo) Ignore the jit_force_virtualizables that are common in or around pypy's interpreter main loop. diff --git a/rpython/translator/backendopt/inline.py b/rpython/translator/backendopt/inline.py --- a/rpython/translator/backendopt/inline.py +++ b/rpython/translator/backendopt/inline.py @@ -478,6 +478,7 @@ 'malloc': 2, 'instrument_count': 0, 'debug_assert': -1, + 'jit_force_virtualizable': 0, } def block_weight(block, weights=OP_WEIGHTS): diff --git a/rpython/translator/backendopt/storesink.py b/rpython/translator/backendopt/storesink.py --- a/rpython/translator/backendopt/storesink.py +++ b/rpython/translator/backendopt/storesink.py @@ -5,7 +5,7 @@ from rpython.translator import simplify def has_side_effects(op): - if op.opname == 'debug_assert': + if op.opname == 'debug_assert' or op.opname == 'jit_force_virtualizable': return False try: return getattr(llop, op.opname).sideeffects From noreply at buildbot.pypy.org Tue Dec 9 16:32:07 2014 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 9 Dec 2014 16:32:07 +0100 (CET) Subject: [pypy-commit] pypy default: merge heads Message-ID: <20141209153207.DA3A51D3650@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r74862:b32441833d66 Date: 2014-12-09 16:31 +0100 http://bitbucket.org/pypy/pypy/changeset/b32441833d66/ Log: merge heads diff too long, truncating to 2000 out of 6151 lines diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst --- a/pypy/doc/embedding.rst +++ b/pypy/doc/embedding.rst @@ -6,6 +6,10 @@ C. It was developed in collaboration with Roberto De Ioris from the `uwsgi`_ project. The `PyPy uwsgi plugin`_ is a good example of using the embedding API. +**NOTE**: As of 1st of December, PyPy comes with ``--shared`` by default +on linux, linux64 and windows. We will make it the default on all platforms +by the time of the next release. + The first thing that you need is to compile PyPy yourself with the option ``--shared``. We plan to make ``--shared`` the default in the future. Consult the `how to compile PyPy`_ doc for details. This will result in ``libpypy.so`` diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst --- a/pypy/doc/project-ideas.rst +++ b/pypy/doc/project-ideas.rst @@ -35,6 +35,13 @@ PyPy's bytearray type is very inefficient. It would be an interesting task to look into possible optimizations on this. +Implement AF_XXX packet types for PyPy +-------------------------------------- + +PyPy is missing AF_XXX types of sockets. Implementing it is easy-to-medium +task. `bug report`_ + +.. _`bug report`: https://bitbucket.org/pypy/pypy/issue/1942/support-for-af_xxx-sockets#more Implement copy-on-write list slicing ------------------------------------ diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -52,7 +52,8 @@ if not OPENSSL_NO_SSL2: constants["PROTOCOL_SSLv2"] = PY_SSL_VERSION_SSL2 -constants["PROTOCOL_SSLv3"] = PY_SSL_VERSION_SSL3 +if not OPENSSL_NO_SSL3: + constants["PROTOCOL_SSLv3"] = PY_SSL_VERSION_SSL3 constants["PROTOCOL_SSLv23"] = PY_SSL_VERSION_SSL23 constants["PROTOCOL_TLSv1"] = PY_SSL_VERSION_TLS1 @@ -656,7 +657,7 @@ # set up context if protocol == PY_SSL_VERSION_TLS1: method = libssl_TLSv1_method() - elif protocol == PY_SSL_VERSION_SSL3: + elif protocol == PY_SSL_VERSION_SSL3 and not OPENSSL_NO_SSL3: method = libssl_SSLv3_method() elif protocol == PY_SSL_VERSION_SSL2 and not OPENSSL_NO_SSL2: method = libssl_SSLv2_method() diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py --- a/pypy/module/micronumpy/boxes.py +++ b/pypy/module/micronumpy/boxes.py @@ -59,9 +59,9 @@ _mixin_ = True def reduce(self, space): - numpypy = space.getbuiltinmodule("_numpypy") - assert isinstance(numpypy, MixedModule) - multiarray = numpypy.get("multiarray") + _numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(_numpypy, MixedModule) + multiarray = _numpypy.get("multiarray") assert isinstance(multiarray, MixedModule) scalar = multiarray.get("scalar") @@ -167,7 +167,7 @@ if len(args_w) >= 1: for w_arg in args_w: try: - idx = support.index_w(space, w_arg) + support.index_w(space, w_arg) except OperationError: raise oefmt(space.w_TypeError, "an integer is required") raise oefmt(space.w_ValueError, "axes don't match array") diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -34,8 +34,8 @@ SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any", - "unegative", "flat", "tostring","count_nonzero", - "argsort"] + "unegative", "flat", "tostring", "count_nonzero", + "argsort", "cumsum", "logical_xor_reduce"] TWO_ARG_FUNCTIONS = ["dot", 'take', 'searchsorted'] TWO_ARG_FUNCTIONS_OR_NONE = ['view', 'astype'] THREE_ARG_FUNCTIONS = ['where'] @@ -559,6 +559,11 @@ w_res = arr.descr_any(interp.space) elif self.name == "all": w_res = arr.descr_all(interp.space) + elif self.name == "cumsum": + w_res = arr.descr_cumsum(interp.space) + elif self.name == "logical_xor_reduce": + logical_xor = ufuncs.get(interp.space).logical_xor + w_res = logical_xor.reduce(interp.space, arr, None) elif self.name == "unegative": neg = ufuncs.get(interp.space).negative w_res = neg.call(interp.space, [arr]) diff --git a/pypy/module/micronumpy/descriptor.py b/pypy/module/micronumpy/descriptor.py --- a/pypy/module/micronumpy/descriptor.py +++ b/pypy/module/micronumpy/descriptor.py @@ -286,7 +286,6 @@ def descr_hash(self, space): return space.wrap(self._compute_hash(space, 0x345678)) - def descr_str(self, space): if self.fields: return space.str(self.descr_get_descr(space)) diff --git a/pypy/module/micronumpy/flatiter.py b/pypy/module/micronumpy/flatiter.py --- a/pypy/module/micronumpy/flatiter.py +++ b/pypy/module/micronumpy/flatiter.py @@ -22,6 +22,9 @@ def get_shape(self): return self.shape + def get_size(self): + return self.base().get_size() + def create_iter(self, shape=None, backward_broadcast=False): assert isinstance(self.base(), W_NDimArray) return self.base().create_iter() @@ -41,8 +44,8 @@ return space.wrap(self.state.index) def descr_coords(self, space): - self.state = self.iter.update(self.state) - return space.newtuple([space.wrap(c) for c in self.state.indices]) + coords = self.iter.indices(self.state) + return space.newtuple([space.wrap(c) for c in coords]) def descr_iter(self): return self @@ -54,7 +57,7 @@ if self.iter.done(self.state): raise OperationError(space.w_StopIteration, space.w_None) w_res = self.iter.getitem(self.state) - self.state = self.iter.next(self.state) + self.iter.next(self.state, mutate=True) return w_res def descr_getitem(self, space, w_idx): @@ -71,7 +74,7 @@ base.get_order(), w_instance=base) return loop.flatiter_getitem(res, self.iter, state, step) finally: - self.state = self.iter.reset(self.state) + self.iter.reset(self.state, mutate=True) def descr_setitem(self, space, w_idx, w_value): if not (space.isinstance_w(w_idx, space.w_int) or @@ -91,7 +94,7 @@ arr = convert_to_array(space, w_value) loop.flatiter_setitem(space, dtype, arr, self.iter, state, step, length) finally: - self.state = self.iter.reset(self.state) + self.iter.reset(self.state, mutate=True) W_FlatIterator.typedef = TypeDef("numpy.flatiter", diff --git a/pypy/module/micronumpy/iterators.py b/pypy/module/micronumpy/iterators.py --- a/pypy/module/micronumpy/iterators.py +++ b/pypy/module/micronumpy/iterators.py @@ -41,16 +41,6 @@ from pypy.module.micronumpy.base import W_NDimArray from pypy.module.micronumpy.flagsobj import _update_contiguous_flags -class OpFlag(object): - def __init__(self): - self.rw = '' - self.broadcast = True - self.force_contig = False - self.force_align = False - self.native_byte_order = False - self.tmp_copy = '' - self.allocate = False - class PureShapeIter(object): def __init__(self, shape, idx_w): @@ -87,26 +77,24 @@ class IterState(object): - _immutable_fields_ = ['iterator', 'index', 'indices', 'offset'] + _immutable_fields_ = ['iterator', '_indices'] def __init__(self, iterator, index, indices, offset): self.iterator = iterator self.index = index - self.indices = indices + self._indices = indices self.offset = offset class ArrayIter(object): _immutable_fields_ = ['contiguous', 'array', 'size', 'ndim_m1', 'shape_m1[*]', 'strides[*]', 'backstrides[*]', 'factors[*]', - 'slice_shape', 'slice_stride', 'slice_backstride', - 'track_index', 'operand_type', 'slice_operand_type'] + 'track_index'] track_index = True @jit.unroll_safe - def __init__(self, array, size, shape, strides, backstrides, op_flags=OpFlag()): - from pypy.module.micronumpy import concrete + def __init__(self, array, size, shape, strides, backstrides): assert len(shape) == len(strides) == len(backstrides) _update_contiguous_flags(array) self.contiguous = (array.flags & NPY.ARRAY_C_CONTIGUOUS and @@ -118,12 +106,6 @@ self.shape_m1 = [s - 1 for s in shape] self.strides = strides self.backstrides = backstrides - self.slice_shape = 1 - self.slice_stride = -1 - if strides: - self.slice_stride = strides[-1] - self.slice_backstride = 1 - self.slice_operand_type = concrete.SliceArray ndim = len(shape) factors = [0] * ndim @@ -133,32 +115,35 @@ else: factors[ndim-i-1] = factors[ndim-i] * shape[ndim-i] self.factors = factors - if op_flags.rw == 'r': - self.operand_type = concrete.ConcreteNonWritableArrayWithBase - else: - self.operand_type = concrete.ConcreteArrayWithBase @jit.unroll_safe - def reset(self, state=None): + def reset(self, state=None, mutate=False): + index = 0 if state is None: indices = [0] * len(self.shape_m1) else: assert state.iterator is self - indices = state.indices + indices = state._indices for i in xrange(self.ndim_m1, -1, -1): indices[i] = 0 - return IterState(self, 0, indices, self.array.start) + offset = self.array.start + if not mutate: + return IterState(self, index, indices, offset) + state.index = index + state.offset = offset @jit.unroll_safe - def next(self, state): + def next(self, state, mutate=False): assert state.iterator is self index = state.index if self.track_index: index += 1 - indices = state.indices + indices = state._indices offset = state.offset if self.contiguous: offset += self.array.dtype.elsize + elif self.ndim_m1 == 0: + offset += self.strides[0] else: for i in xrange(self.ndim_m1, -1, -1): idx = indices[i] @@ -169,13 +154,18 @@ else: indices[i] = 0 offset -= self.backstrides[i] - return IterState(self, index, indices, offset) + if not mutate: + return IterState(self, index, indices, offset) + state.index = index + state.offset = offset @jit.unroll_safe def goto(self, index): offset = self.array.start if self.contiguous: offset += index * self.array.dtype.elsize + elif self.ndim_m1 == 0: + offset += index * self.strides[0] else: current = index for i in xrange(len(self.shape_m1)): @@ -184,20 +174,20 @@ return IterState(self, index, None, offset) @jit.unroll_safe - def update(self, state): + def indices(self, state): assert state.iterator is self assert self.track_index - if not self.contiguous: - return state + indices = state._indices + if not (self.contiguous or self.ndim_m1 == 0): + return indices current = state.index - indices = state.indices for i in xrange(len(self.shape_m1)): if self.factors[i] != 0: indices[i] = current / self.factors[i] current %= self.factors[i] else: indices[i] = 0 - return IterState(self, state.index, indices, state.offset) + return indices def done(self, state): assert state.iterator is self @@ -216,12 +206,6 @@ assert state.iterator is self self.array.setitem(state.offset, elem) - def getoperand(self, st, base): - impl = self.operand_type - res = impl([], self.array.dtype, self.array.order, [], [], - self.array.storage, base) - res.start = st.offset - return res def AxisIter(array, shape, axis, cumulative): strides = array.get_strides() @@ -245,42 +229,3 @@ size /= shape[axis] shape[axis] = backstrides[axis] = 0 return ArrayIter(array, size, shape, array.strides, backstrides) - -class SliceIter(ArrayIter): - ''' - used with external loops, getitem and setitem return a SliceArray - view into the original array - ''' - _immutable_fields_ = ['base', 'slice_shape[*]', 'slice_stride[*]', 'slice_backstride[*]'] - - def __init__(self, array, size, shape, strides, backstrides, slice_shape, - slice_stride, slice_backstride, op_flags, base): - from pypy.module.micronumpy import concrete - ArrayIter.__init__(self, array, size, shape, strides, backstrides, op_flags) - self.slice_shape = slice_shape - self.slice_stride = slice_stride - self.slice_backstride = slice_backstride - self.base = base - if op_flags.rw == 'r': - self.slice_operand_type = concrete.NonWritableSliceArray - else: - self.slice_operand_type = concrete.SliceArray - - def getitem(self, state): - # XXX cannot be called - must return a boxed value - assert False - - def getitem_bool(self, state): - # XXX cannot be called - must return a boxed value - assert False - - def setitem(self, state, elem): - # XXX cannot be called - must return a boxed value - assert False - - def getoperand(self, state, base): - assert state.iterator is self - impl = self.slice_operand_type - arr = impl(state.offset, [self.slice_stride], [self.slice_backstride], - [self.slice_shape], self.array, self.base) - return arr diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py --- a/pypy/module/micronumpy/loop.py +++ b/pypy/module/micronumpy/loop.py @@ -42,23 +42,38 @@ # TODO handle __array_priorities__ and maybe flip the order + if w_lhs.get_size() == 1: + w_left = w_lhs.get_scalar_value().convert_to(space, calc_dtype) + left_iter = left_state = None + else: + w_left = None + left_iter, left_state = w_lhs.create_iter(shape) + left_iter.track_index = False + + if w_rhs.get_size() == 1: + w_right = w_rhs.get_scalar_value().convert_to(space, calc_dtype) + right_iter = right_state = None + else: + w_right = None + right_iter, right_state = w_rhs.create_iter(shape) + right_iter.track_index = False + if out is None: out = W_NDimArray.from_shape(space, shape, res_dtype, w_instance=lhs_for_subtype) - left_iter, left_state = w_lhs.create_iter(shape) - right_iter, right_state = w_rhs.create_iter(shape) out_iter, out_state = out.create_iter(shape) - left_iter.track_index = right_iter.track_index = False shapelen = len(shape) while not out_iter.done(out_state): call2_driver.jit_merge_point(shapelen=shapelen, func=func, calc_dtype=calc_dtype, res_dtype=res_dtype) - w_left = left_iter.getitem(left_state).convert_to(space, calc_dtype) - w_right = right_iter.getitem(right_state).convert_to(space, calc_dtype) + if left_iter: + w_left = left_iter.getitem(left_state).convert_to(space, calc_dtype) + left_state = left_iter.next(left_state) + if right_iter: + w_right = right_iter.getitem(right_state).convert_to(space, calc_dtype) + right_state = right_iter.next(right_state) out_iter.setitem(out_state, func(calc_dtype, w_left, w_right).convert_to( space, res_dtype)) - left_state = left_iter.next(left_state) - right_state = right_iter.next(right_state) out_state = out_iter.next(out_state) return out @@ -68,11 +83,12 @@ reds='auto') def call1(space, shape, func, calc_dtype, res_dtype, w_obj, out): + obj_iter, obj_state = w_obj.create_iter(shape) + obj_iter.track_index = False + if out is None: out = W_NDimArray.from_shape(space, shape, res_dtype, w_instance=w_obj) - obj_iter, obj_state = w_obj.create_iter(shape) out_iter, out_state = out.create_iter(shape) - obj_iter.track_index = False shapelen = len(shape) while not out_iter.done(out_state): call1_driver.jit_merge_point(shapelen=shapelen, func=func, @@ -89,17 +105,14 @@ def setslice(space, shape, target, source): if not shape: - # XXX - simplify - target_iter, target_state = target.create_iter(shape) - source_iter, source_state = source.create_iter(shape) dtype = target.dtype - val = source_iter.getitem(source_state) + val = source.getitem(source.start) if dtype.is_str_or_unicode(): val = dtype.coerce(space, val) else: val = val.convert_to(space, dtype) - target_iter.setitem(target_state, val) - return target + target.setitem(target.start, val) + return target return _setslice(space, shape, target, source) def _setslice(space, shape, target, source): @@ -107,6 +120,7 @@ # array implementations, not arrays target_iter, target_state = target.create_iter(shape) source_iter, source_state = source.create_iter(shape) + source_iter.track_index = False dtype = target.dtype shapelen = len(shape) while not target_iter.done(target_state): @@ -152,6 +166,7 @@ def compute_reduce_cumulative(space, obj, out, calc_dtype, func, identity): obj_iter, obj_state = obj.create_iter() out_iter, out_state = out.create_iter() + out_iter.track_index = False if identity is None: cur_value = obj_iter.getitem(obj_state).convert_to(space, calc_dtype) out_iter.setitem(out_state, cur_value) @@ -225,10 +240,9 @@ state = x_state return out -axis_reduce__driver = jit.JitDriver(name='numpy_axis_reduce', - greens=['shapelen', - 'func', 'dtype'], - reds='auto') +axis_reduce_driver = jit.JitDriver(name='numpy_axis_reduce', + greens=['shapelen', 'func', 'dtype'], + reds='auto') def do_axis_reduce(space, shape, func, arr, dtype, axis, out, identity, cumulative, temp): @@ -241,21 +255,24 @@ temp_iter = out_iter # hack temp_state = out_state arr_iter, arr_state = arr.create_iter() + arr_iter.track_index = False if identity is not None: identity = identity.convert_to(space, dtype) shapelen = len(shape) while not out_iter.done(out_state): - axis_reduce__driver.jit_merge_point(shapelen=shapelen, func=func, - dtype=dtype) - assert not arr_iter.done(arr_state) + axis_reduce_driver.jit_merge_point(shapelen=shapelen, func=func, + dtype=dtype) w_val = arr_iter.getitem(arr_state).convert_to(space, dtype) - out_state = out_iter.update(out_state) - if out_state.indices[axis] == 0: + arr_state = arr_iter.next(arr_state) + + out_indices = out_iter.indices(out_state) + if out_indices[axis] == 0: if identity is not None: w_val = func(dtype, identity, w_val) else: cur = temp_iter.getitem(temp_state) w_val = func(dtype, cur, w_val) + out_iter.setitem(out_state, w_val) out_state = out_iter.next(out_state) if cumulative: @@ -263,7 +280,6 @@ temp_state = temp_iter.next(temp_state) else: temp_state = out_state - arr_state = arr_iter.next(arr_state) return out @@ -382,9 +398,9 @@ while not arr_iter.done(arr_state): nonzero_driver.jit_merge_point(shapelen=shapelen, dims=dims, dtype=dtype) if arr_iter.getitem_bool(arr_state): - arr_state = arr_iter.update(arr_state) + arr_indices = arr_iter.indices(arr_state) for d in dims: - res_iter.setitem(res_state, box(arr_state.indices[d])) + res_iter.setitem(res_state, box(arr_indices[d])) res_state = res_iter.next(res_state) arr_state = arr_iter.next(arr_state) return res diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py --- a/pypy/module/micronumpy/ndarray.py +++ b/pypy/module/micronumpy/ndarray.py @@ -1139,9 +1139,9 @@ from pypy.interpreter.mixedmodule import MixedModule from pypy.module.micronumpy.concrete import SliceArray - numpypy = space.getbuiltinmodule("_numpypy") - assert isinstance(numpypy, MixedModule) - multiarray = numpypy.get("multiarray") + _numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(_numpypy, MixedModule) + multiarray = _numpypy.get("multiarray") assert isinstance(multiarray, MixedModule) reconstruct = multiarray.get("_reconstruct") parameters = space.newtuple([self.getclass(space), space.newtuple( diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py --- a/pypy/module/micronumpy/nditer.py +++ b/pypy/module/micronumpy/nditer.py @@ -6,7 +6,7 @@ from pypy.module.micronumpy import ufuncs, support, concrete from pypy.module.micronumpy.base import W_NDimArray, convert_to_array from pypy.module.micronumpy.descriptor import decode_w_dtype -from pypy.module.micronumpy.iterators import ArrayIter, SliceIter, OpFlag +from pypy.module.micronumpy.iterators import ArrayIter from pypy.module.micronumpy.strides import (calculate_broadcast_strides, shape_agreement, shape_agreement_multiple) @@ -36,6 +36,16 @@ return ret +class OpFlag(object): + def __init__(self): + self.rw = '' + self.broadcast = True + self.force_contig = False + self.force_align = False + self.native_byte_order = False + self.tmp_copy = '' + self.allocate = False + def parse_op_flag(space, lst): op_flag = OpFlag() for w_item in lst: @@ -142,11 +152,73 @@ raise NotImplementedError('not implemented yet') -def get_iter(space, order, arr, shape, dtype, op_flags): +class OperandIter(ArrayIter): + _immutable_fields_ = ['slice_shape', 'slice_stride', 'slice_backstride', + 'operand_type', 'base'] + + def getitem(self, state): + # cannot be called - must return a boxed value + assert False + + def getitem_bool(self, state): + # cannot be called - must return a boxed value + assert False + + def setitem(self, state, elem): + # cannot be called - must return a boxed value + assert False + + +class ConcreteIter(OperandIter): + def __init__(self, array, size, shape, strides, backstrides, + op_flags, base): + OperandIter.__init__(self, array, size, shape, strides, backstrides) + self.slice_shape = 1 + self.slice_stride = -1 + if strides: + self.slice_stride = strides[-1] + self.slice_backstride = 1 + if op_flags.rw == 'r': + self.operand_type = concrete.ConcreteNonWritableArrayWithBase + else: + self.operand_type = concrete.ConcreteArrayWithBase + self.base = base + + def getoperand(self, state): + assert state.iterator is self + impl = self.operand_type + res = impl([], self.array.dtype, self.array.order, [], [], + self.array.storage, self.base) + res.start = state.offset + return res + + +class SliceIter(OperandIter): + def __init__(self, array, size, shape, strides, backstrides, slice_shape, + slice_stride, slice_backstride, op_flags, base): + OperandIter.__init__(self, array, size, shape, strides, backstrides) + self.slice_shape = slice_shape + self.slice_stride = slice_stride + self.slice_backstride = slice_backstride + if op_flags.rw == 'r': + self.operand_type = concrete.NonWritableSliceArray + else: + self.operand_type = concrete.SliceArray + self.base = base + + def getoperand(self, state): + assert state.iterator is self + impl = self.operand_type + arr = impl(state.offset, [self.slice_stride], [self.slice_backstride], + [self.slice_shape], self.array, self.base) + return arr + + +def get_iter(space, order, arr, shape, dtype, op_flags, base): imp = arr.implementation backward = is_backward(imp, order) if arr.is_scalar(): - return ArrayIter(imp, 1, [], [], [], op_flags=op_flags) + return ConcreteIter(imp, 1, [], [], [], op_flags, base) if (imp.strides[0] < imp.strides[-1] and not backward) or \ (imp.strides[0] > imp.strides[-1] and backward): # flip the strides. Is this always true for multidimension? @@ -161,7 +233,7 @@ backstrides = imp.backstrides r = calculate_broadcast_strides(strides, backstrides, imp.shape, shape, backward) - return ArrayIter(imp, imp.get_size(), shape, r[0], r[1], op_flags=op_flags) + return ConcreteIter(imp, imp.get_size(), shape, r[0], r[1], op_flags, base) def calculate_ndim(op_in, oa_ndim): if oa_ndim >=0: @@ -398,7 +470,7 @@ self.iters = [] for i in range(len(self.seq)): it = get_iter(space, self.order, self.seq[i], self.shape, - self.dtypes[i], self.op_flags[i]) + self.dtypes[i], self.op_flags[i], self) it.contiguous = False self.iters.append((it, it.reset())) @@ -437,7 +509,7 @@ return space.wrap(self) def getitem(self, it, st): - res = it.getoperand(st, self) + res = it.getoperand(st) return W_NDimArray(res) def descr_getitem(self, space, w_idx): diff --git a/pypy/module/micronumpy/test/test_arrayops.py b/pypy/module/micronumpy/test/test_arrayops.py --- a/pypy/module/micronumpy/test/test_arrayops.py +++ b/pypy/module/micronumpy/test/test_arrayops.py @@ -3,13 +3,13 @@ class AppTestNumSupport(BaseNumpyAppTest): def test_zeros(self): - from numpypy import zeros + from numpy import zeros a = zeros(3) assert len(a) == 3 assert a[0] == a[1] == a[2] == 0 def test_empty(self): - from numpypy import empty + from numpy import empty import gc for i in range(1000): a = empty(3) @@ -26,26 +26,26 @@ "empty() returned a zeroed out array every time") def test_where(self): - from numpypy import where, ones, zeros, array + from numpy import where, ones, zeros, array a = [1, 2, 3, 0, -3] a = where(array(a) > 0, ones(5), zeros(5)) assert (a == [1, 1, 1, 0, 0]).all() def test_where_differing_dtypes(self): - from numpypy import array, ones, zeros, where + from numpy import array, ones, zeros, where a = [1, 2, 3, 0, -3] a = where(array(a) > 0, ones(5, dtype=int), zeros(5, dtype=float)) assert (a == [1, 1, 1, 0, 0]).all() def test_where_broadcast(self): - from numpypy import array, where + from numpy import array, where a = where(array([[1, 2, 3], [4, 5, 6]]) > 3, [1, 1, 1], 2) assert (a == [[2, 2, 2], [1, 1, 1]]).all() a = where(True, [1, 1, 1], 2) assert (a == [1, 1, 1]).all() def test_where_errors(self): - from numpypy import where, array + from numpy import where, array raises(ValueError, "where([1, 2, 3], [3, 4, 5])") raises(ValueError, "where([1, 2, 3], [3, 4, 5], [6, 7])") assert where(True, 1, 2) == array(1) @@ -58,14 +58,14 @@ # xxx def test_where_invalidates(self): - from numpypy import where, ones, zeros, array + from numpy import where, ones, zeros, array a = array([1, 2, 3, 0, -3]) b = where(a > 0, ones(5), zeros(5)) a[0] = 0 assert (b == [1, 1, 1, 0, 0]).all() def test_dot_basic(self): - from numpypy import array, dot, arange + from numpy import array, dot, arange a = array(range(5)) assert dot(a, a) == 30.0 @@ -100,7 +100,7 @@ assert (dot([[1,2],[3,4]],[5,6]) == [17, 39]).all() def test_dot_constant(self): - from numpypy import array, dot + from numpy import array, dot a = array(range(5)) b = a.dot(2.5) for i in xrange(5): @@ -111,7 +111,7 @@ assert c == 12.0 def test_dot_out(self): - from numpypy import arange, dot + from numpy import arange, dot a = arange(12).reshape(3, 4) b = arange(12).reshape(4, 3) out = arange(9).reshape(3, 3) @@ -124,19 +124,19 @@ 'right type, nr dimensions, and be a C-Array)') def test_choose_basic(self): - from numpypy import array + from numpy import array a, b, c = array([1, 2, 3]), array([4, 5, 6]), array([7, 8, 9]) r = array([2, 1, 0]).choose([a, b, c]) assert (r == [7, 5, 3]).all() def test_choose_broadcast(self): - from numpypy import array + from numpy import array a, b, c = array([1, 2, 3]), [4, 5, 6], 13 r = array([2, 1, 0]).choose([a, b, c]) assert (r == [13, 5, 3]).all() def test_choose_out(self): - from numpypy import array + from numpy import array a, b, c = array([1, 2, 3]), [4, 5, 6], 13 r = array([2, 1, 0]).choose([a, b, c], out=None) assert (r == [13, 5, 3]).all() @@ -146,7 +146,7 @@ assert (a == [13, 5, 3]).all() def test_choose_modes(self): - from numpypy import array + from numpy import array a, b, c = array([1, 2, 3]), [4, 5, 6], 13 raises(ValueError, "array([3, 1, 0]).choose([a, b, c])") raises(ValueError, "array([3, 1, 0]).choose([a, b, c], mode='raises')") @@ -158,20 +158,20 @@ assert (r == [4, 5, 3]).all() def test_choose_dtype(self): - from numpypy import array + from numpy import array a, b, c = array([1.2, 2, 3]), [4, 5, 6], 13 r = array([2, 1, 0]).choose([a, b, c]) assert r.dtype == float def test_choose_dtype_out(self): - from numpypy import array + from numpy import array a, b, c = array([1, 2, 3]), [4, 5, 6], 13 x = array([0, 0, 0], dtype='i2') r = array([2, 1, 0]).choose([a, b, c], out=x) assert r.dtype == 'i2' def test_put_basic(self): - from numpypy import arange, array + from numpy import arange, array a = arange(5) a.put([0, 2], [-44, -55]) assert (a == array([-44, 1, -55, 3, 4])).all() @@ -183,7 +183,7 @@ assert (a == array([0, 7, 2, 3, 4])).all() def test_put_modes(self): - from numpypy import array, arange + from numpy import array, arange a = arange(5) a.put(22, -5, mode='clip') assert (a == array([0, 1, 2, 3, -5])).all() diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py --- a/pypy/module/micronumpy/test/test_base.py +++ b/pypy/module/micronumpy/test/test_base.py @@ -14,15 +14,12 @@ else: from . import dummy_module as numpy sys.modules['numpy'] = numpy - sys.modules['numpypy'] = numpy else: import os path = os.path.dirname(__file__) + '/dummy_module.py' cls.space.appexec([cls.space.wrap(path)], """(path): import imp - numpy = imp.load_source('numpy', path) - import sys - sys.modules['numpypy'] = numpy + imp.load_source('numpy', path) """) cls.w_non_native_prefix = cls.space.wrap(NPY.OPPBYTE) cls.w_native_prefix = cls.space.wrap(NPY.NATBYTE) diff --git a/pypy/module/micronumpy/test/test_complex.py b/pypy/module/micronumpy/test/test_complex.py --- a/pypy/module/micronumpy/test/test_complex.py +++ b/pypy/module/micronumpy/test/test_complex.py @@ -132,13 +132,13 @@ cls.w_c_pow = cls.space.wrap(interp2app(cls_c_pow)) def test_fabs(self): - from numpypy import fabs, dtype + from numpy import fabs, dtype a = dtype('complex128').type(complex(-5., 5.)) raises(TypeError, fabs, a) def test_fmax(self): - from numpypy import fmax, array + from numpy import fmax, array nnan, nan, inf, ninf = float('-nan'), float('nan'), float('inf'), float('-inf') a = array((complex(ninf, 10), complex(10, ninf), complex( inf, 10), complex(10, inf), @@ -165,7 +165,7 @@ assert (fmax(a, b) == res).all() def test_fmin(self): - from numpypy import fmin, array + from numpy import fmin, array nnan, nan, inf, ninf = float('-nan'), float('nan'), float('inf'), float('-inf') a = array((complex(ninf, 10), complex(10, ninf), complex( inf, 10), complex(10, inf), @@ -192,11 +192,11 @@ assert (fmin(a, b) == res).all() def test_signbit(self): - from numpypy import signbit + from numpy import signbit raises(TypeError, signbit, complex(1,1)) def test_reciprocal(self): - from numpypy import array, reciprocal + from numpy import array, reciprocal inf = float('inf') nan = float('nan') #complex @@ -218,21 +218,21 @@ assert (a[0].imag - e.imag) < rel_err def test_floorceiltrunc(self): - from numpypy import array, floor, ceil, trunc + from numpy import array, floor, ceil, trunc a = array([ complex(-1.4, -1.4), complex(-1.5, -1.5)]) raises(TypeError, floor, a) raises(TypeError, ceil, a) raises(TypeError, trunc, a) def test_copysign(self): - from numpypy import copysign, dtype + from numpy import copysign, dtype complex128 = dtype('complex128').type a = complex128(complex(-5., 5.)) b = complex128(complex(0., 0.)) raises(TypeError, copysign, a, b) def test_exp2(self): - from numpypy import array, exp2 + from numpy import array, exp2 inf = float('inf') ninf = -float('inf') nan = float('nan') @@ -268,7 +268,7 @@ def test_expm1(self): import math, cmath - from numpypy import array, expm1 + from numpy import array, expm1 inf = float('inf') ninf = -float('inf') nan = float('nan') @@ -307,7 +307,7 @@ self.rAlmostEqual(t1, t2, rel_err=rel_err, msg=msg) def test_not_complex(self): - from numpypy import (radians, deg2rad, degrees, rad2deg, + from numpy import (radians, deg2rad, degrees, rad2deg, logaddexp, logaddexp2, fmod, arctan2) raises(TypeError, radians, complex(90,90)) @@ -320,7 +320,7 @@ raises (TypeError, fmod, complex(90,90), 3) def test_isnan_isinf(self): - from numpypy import isnan, isinf, array + from numpy import isnan, isinf, array assert (isnan(array([0.2+2j, complex(float('inf'),0), complex(0,float('inf')), complex(0,float('nan')), complex(float('nan'), 0)], dtype=complex)) == \ @@ -333,7 +333,7 @@ def test_square(self): - from numpypy import square + from numpy import square assert square(complex(3, 4)) == complex(3,4) * complex(3, 4) def test_power_simple(self): @@ -364,8 +364,8 @@ self.rAlmostEqual(float(n_r_a[i].imag), float(p_r[i].imag), msg=msg) def test_conjugate(self): - from numpypy import conj, conjugate, dtype - import numpypy as np + from numpy import conj, conjugate, dtype + import numpy as np c0 = dtype('complex128').type(complex(2.5, 0)) c1 = dtype('complex64').type(complex(1, 2)) @@ -390,7 +390,7 @@ def test_logn(self): import math, cmath # log and log10 are tested in math (1:1 from rcomplex) - from numpypy import log2, array, log1p + from numpy import log2, array, log1p inf = float('inf') ninf = -float('inf') nan = float('nan') @@ -447,7 +447,7 @@ self.rAlmostEqual(t1, t2, rel_err=rel_err, msg=msg) def test_logical_ops(self): - from numpypy import logical_and, logical_or, logical_xor, logical_not + from numpy import logical_and, logical_or, logical_xor, logical_not c1 = complex(1, 1) c3 = complex(3, 0) @@ -461,7 +461,7 @@ assert (logical_not([c1, c0]) == [False, True]).all() def test_minimum(self): - from numpypy import array, minimum + from numpy import array, minimum a = array([-5.0+5j, -5.0-5j, -0.0-10j, 1.0+10j]) b = array([ 3.0+10.0j, 3.0, -2.0+2.0j, -3.0+4.0j]) @@ -470,7 +470,7 @@ assert c[i] == min(a[i], b[i]) def test_maximum(self): - from numpypy import array, maximum + from numpy import array, maximum a = array([-5.0+5j, -5.0-5j, -0.0-10j, 1.0+10j]) b = array([ 3.0+10.0j, 3.0, -2.0+2.0j, -3.0+4.0j]) @@ -480,10 +480,10 @@ def test_basic(self): import sys - from numpypy import (dtype, add, array, dtype, + from numpy import (dtype, add, array, dtype, subtract as sub, multiply, divide, negative, absolute as abs, floor_divide, real, imag, sign) - from numpypy import (equal, not_equal, greater, greater_equal, less, + from numpy import (equal, not_equal, greater, greater_equal, less, less_equal, isnan) assert real(4.0) == 4.0 assert imag(0.0) == 0.0 @@ -579,7 +579,7 @@ assert repr(abs(inf_c)) == 'inf' assert repr(abs(complex(float('nan'), float('nan')))) == 'nan' # numpy actually raises an AttributeError, - # but numpypy raises a TypeError + # but numpy.raises a TypeError if '__pypy__' in sys.builtin_module_names: exct, excm = TypeError, 'readonly attribute' else: @@ -592,7 +592,7 @@ assert(imag(c2) == 4.0) def test_conj(self): - from numpypy import array + from numpy import array a = array([1 + 2j, 1 - 2j]) assert (a.conj() == [1 - 2j, 1 + 2j]).all() @@ -603,7 +603,7 @@ if self.isWindows: skip('windows does not support c99 complex') import sys - import numpypy as np + import numpy as np rAlmostEqual = self.rAlmostEqual for t, testcases in ( @@ -658,6 +658,6 @@ sys.stderr.write('\n') def test_complexbox_to_pycomplex(self): - from numpypy import dtype + from numpy import dtype x = dtype('complex128').type(3.4j) assert complex(x) == 3.4j diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -23,7 +23,7 @@ from numpy.core.multiarray import typeinfo except ImportError: # running on dummy module - from numpypy import typeinfo + from numpy import typeinfo assert typeinfo['Number'] == np.number assert typeinfo['LONGLONG'] == ('q', 9, 64, 8, 9223372036854775807L, -9223372036854775808L, np.longlong) @@ -39,7 +39,7 @@ np.dtype('int').type) def test_dtype_basic(self): - from numpypy import dtype + from numpy import dtype import sys d = dtype('?') @@ -104,7 +104,7 @@ assert d.shape == () def test_dtype_eq(self): - from numpypy import dtype + from numpy import dtype assert dtype("int8") == "int8" assert "int8" == dtype("int8") @@ -112,7 +112,7 @@ assert dtype(bool) == bool def test_dtype_aliases(self): - from numpypy import dtype + from numpy import dtype assert dtype('bool8') is dtype('bool') assert dtype('byte') is dtype('int8') assert dtype('ubyte') is dtype('uint8') @@ -132,7 +132,7 @@ assert dtype('clongdouble').num in (15, 16) def test_dtype_with_types(self): - from numpypy import dtype + from numpy import dtype assert dtype(bool).num == 0 if self.ptr_size == 4: @@ -156,7 +156,7 @@ assert dtype('complex').num == 15 def test_array_dtype_attr(self): - from numpypy import array, dtype + from numpy import array, dtype a = array(range(5), long) assert a.dtype is dtype(long) @@ -182,7 +182,7 @@ assert np.dtype('S5').isbuiltin == 0 def test_repr_str(self): - from numpypy import dtype + from numpy import dtype b = dtype(int).newbyteorder().newbyteorder().byteorder assert '.dtype' in repr(dtype) d = dtype('?') @@ -208,7 +208,7 @@ assert str(d) == "|V16" def test_bool_array(self): - from numpypy import array, False_, True_ + from numpy import array, False_, True_ a = array([0, 1, 2, 2.5], dtype='?') assert a[0] is False_ @@ -216,7 +216,7 @@ assert a[i] is True_ def test_copy_array_with_dtype(self): - from numpypy import array, longlong, False_ + from numpy import array, longlong, False_ a = array([0, 1, 2, 3], dtype=long) # int on 64-bit, long in 32-bit @@ -230,35 +230,35 @@ assert b[0] is False_ def test_zeros_bool(self): - from numpypy import zeros, False_ + from numpy import zeros, False_ a = zeros(10, dtype=bool) for i in range(10): assert a[i] is False_ def test_ones_bool(self): - from numpypy import ones, True_ + from numpy import ones, True_ a = ones(10, dtype=bool) for i in range(10): assert a[i] is True_ def test_zeros_long(self): - from numpypy import zeros, longlong + from numpy import zeros, longlong a = zeros(10, dtype=long) for i in range(10): assert isinstance(a[i], longlong) assert a[1] == 0 def test_ones_long(self): - from numpypy import ones, longlong + from numpy import ones, longlong a = ones(10, dtype=long) for i in range(10): assert isinstance(a[i], longlong) assert a[1] == 1 def test_overflow(self): - from numpypy import array, dtype + from numpy import array, dtype assert array([128], 'b')[0] == -128 assert array([256], 'B')[0] == 0 assert array([32768], 'h')[0] == -32768 @@ -273,7 +273,7 @@ raises(OverflowError, "array([2**64], 'Q')") def test_bool_binop_types(self): - from numpypy import array, dtype + from numpy import array, dtype types = [ '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd', 'e' @@ -285,7 +285,7 @@ assert (a + array([0], t)).dtype is dtype(t) def test_binop_types(self): - from numpypy import array, dtype + from numpy import array, dtype tests = [('b','B','h'), ('b','h','h'), ('b','H','i'), ('b','i','i'), ('b','l','l'), ('b','q','q'), ('b','Q','d'), ('B','h','h'), ('B','H','H'), ('B','i','i'), ('B','I','I'), ('B','l','l'), @@ -309,7 +309,7 @@ assert (d1, d2) == (d1, d2) and d3 is dtype(dout) def test_add(self): - import numpypy as np + import numpy as np for dtype in ["int8", "int16", "I"]: a = np.array(range(5), dtype=dtype) b = a + a @@ -325,22 +325,22 @@ assert len(d) == 2 def test_shape(self): - from numpypy import dtype + from numpy import dtype assert dtype(long).shape == () def test_cant_subclass(self): - from numpypy import dtype + from numpy import dtype # You can't subclass dtype raises(TypeError, type, "Foo", (dtype,), {}) def test_can_subclass(self): - import numpypy - class xyz(numpypy.void): + import numpy + class xyz(numpy.void): pass assert True def test_index(self): - import numpypy as np + import numpy as np for dtype in [np.int8, np.int16, np.int32, np.int64]: a = np.array(range(10), dtype=dtype) b = np.array([0] * 10, dtype=dtype) @@ -348,7 +348,7 @@ a[idx] += 1 def test_hash(self): - import numpypy as numpy + import numpy for tp, value in [ (numpy.int8, 4), (numpy.int16, 5), @@ -392,9 +392,10 @@ t5 = dtype([('x', '' @@ -479,7 +480,7 @@ class AppTestTypes(BaseAppTestDtypes): def test_abstract_types(self): - import numpypy as numpy + import numpy raises(TypeError, numpy.generic, 0) raises(TypeError, numpy.number, 0) @@ -525,16 +526,16 @@ #assert a.dtype is numpy.dtype('|V4') def test_new(self): - import numpypy as np + import numpy as np assert np.int_(4) == 4 assert np.float_(3.4) == 3.4 def test_pow(self): - from numpypy import int_ + from numpy import int_ assert int_(4) ** 2 == 16 def test_bool(self): - import numpypy as numpy + import numpy assert numpy.bool_.mro() == [numpy.bool_, numpy.generic, object] assert numpy.bool_(3) is numpy.True_ @@ -549,7 +550,7 @@ assert numpy.bool_("False") is numpy.True_ def test_int8(self): - import numpypy as numpy + import numpy assert numpy.int8.mro() == [numpy.int8, numpy.signedinteger, numpy.integer, numpy.number, @@ -573,7 +574,7 @@ assert numpy.int8('128') == -128 def test_uint8(self): - import numpypy as numpy + import numpy assert numpy.uint8.mro() == [numpy.uint8, numpy.unsignedinteger, numpy.integer, numpy.number, @@ -598,7 +599,7 @@ assert numpy.uint8('256') == 0 def test_int16(self): - import numpypy as numpy + import numpy x = numpy.int16(3) assert x == 3 @@ -640,7 +641,7 @@ assert numpy.uint32('4294967296') == 0 def test_int_(self): - import numpypy as numpy + import numpy assert numpy.int_ is numpy.dtype(int).type assert numpy.int_.mro() == [numpy.int_, numpy.signedinteger, @@ -751,7 +752,7 @@ def test_complex_format(self): import sys - import numpypy as numpy + import numpy for complex_ in (numpy.complex128, numpy.complex64,): for real, imag, should in [ @@ -791,7 +792,7 @@ assert "{:g}".format(numpy.complex_(0.5+1.5j)) == '{:g}'.format(0.5+1.5j) def test_complex(self): - import numpypy as numpy + import numpy assert numpy.complex_ is numpy.complex128 assert numpy.csingle is numpy.complex64 @@ -811,7 +812,7 @@ assert d.char == 'F' def test_subclass_type(self): - import numpypy as numpy + import numpy class X(numpy.float64): def m(self): @@ -825,12 +826,12 @@ assert b.dtype.type is numpy.float64 def test_long_as_index(self): - from numpypy import int_, float64 + from numpy import int_, float64 assert (1, 2, 3)[int_(1)] == 2 raises(TypeError, lambda: (1, 2, 3)[float64(1)]) def test_int(self): - from numpypy import int32, int64, int_ + from numpy import int32, int64, int_ import sys assert issubclass(int_, int) if sys.maxint == (1<<31) - 1: @@ -841,7 +842,7 @@ assert int_ is int64 def test_various_types(self): - import numpypy as numpy + import numpy assert numpy.int16 is numpy.short assert numpy.int8 is numpy.byte @@ -863,7 +864,7 @@ assert not issubclass(numpy.longfloat, numpy.float64) def test_mro(self): - import numpypy as numpy + import numpy assert numpy.int16.__mro__ == (numpy.int16, numpy.signedinteger, numpy.integer, numpy.number, @@ -872,7 +873,7 @@ def test_operators(self): from operator import truediv - from numpypy import float64, int_, True_, False_ + from numpy import float64, int_, True_, False_ assert 5 / int_(2) == int_(2) assert truediv(int_(3), int_(2)) == float64(1.5) assert truediv(3, int_(2)) == float64(1.5) @@ -898,7 +899,7 @@ def test_alternate_constructs(self): import numpy as np - from numpypy import dtype + from numpy import dtype nnp = self.non_native_prefix byteorder = self.native_prefix assert dtype('i8') == dtype(byteorder + 'i8') == dtype('=i8') == dtype(long) @@ -921,7 +922,7 @@ assert d.str == '|S0' def test_dtype_str(self): - from numpypy import dtype + from numpy import dtype byteorder = self.native_prefix assert dtype('i8').str == byteorder + 'i8' assert dtype('i8').isnative == False def test_any_all_nonzero(self): - import numpypy as numpy + import numpy x = numpy.bool_(True) assert x.any() is numpy.True_ assert x.all() is numpy.True_ @@ -999,7 +1000,7 @@ assert x.__nonzero__() is True def test_ravel(self): - from numpypy import float64, int8, array + from numpy import float64, int8, array x = float64(42.5).ravel() assert x.dtype == float64 assert (x == array([42.5])).all() @@ -1022,7 +1023,7 @@ class AppTestStrUnicodeDtypes(BaseNumpyAppTest): def test_mro(self): - from numpypy import str_, unicode_, character, flexible, generic + from numpy import str_, unicode_, character, flexible, generic import sys if '__pypy__' in sys.builtin_module_names: assert str_.mro() == [str_, character, flexible, generic, @@ -1036,7 +1037,7 @@ flexible, generic, object] def test_str_dtype(self): - from numpypy import dtype, str_ + from numpy import dtype, str_ raises(TypeError, "dtype('Sx')") for t in ['S8', '|S8', '=S8']: @@ -1057,7 +1058,7 @@ assert d.str == '|S1' def test_unicode_dtype(self): - from numpypy import dtype, unicode_ + from numpy import dtype, unicode_ raises(TypeError, "dtype('Ux')") d = dtype('U8') @@ -1069,11 +1070,11 @@ assert d.num == 19 def test_string_boxes(self): - from numpypy import str_ + from numpy import str_ assert isinstance(str_(3), str_) def test_unicode_boxes(self): - from numpypy import unicode_ + from numpy import unicode_ import sys if '__pypy__' in sys.builtin_module_names: exc = raises(NotImplementedError, unicode_, 3) @@ -1084,7 +1085,7 @@ def test_character_dtype(self): import numpy as np - from numpypy import array, character + from numpy import array, character x = array([["A", "B"], ["C", "D"]], character) assert (x == [["A", "B"], ["C", "D"]]).all() d = np.dtype('c') @@ -1097,7 +1098,7 @@ spaceconfig = dict(usemodules=["micronumpy", "struct", "binascii"]) def test_create(self): - from numpypy import dtype, void + from numpy import dtype, void raises(ValueError, "dtype([('x', int), ('x', float)])") d = dtype([("x", " Author: Laurence Tratt Branch: recursion_and_inlining Changeset: r74863:fe3efdc5abfa Date: 2014-12-08 15:22 +0000 http://bitbucket.org/pypy/pypy/changeset/fe3efdc5abfa/ Log: Use framestack instead of portal_trace_positions. The latter does not, despite first appearences, model the frame stack: it models all call positions the portal has gone through in its history. If I'd looked more carefully, I might have noticed that the portal has a semi-hidden framestack attribute, which has a semi- hidden greenkey attribute. This records exactly what we want, and also solves the problem that we're no longer tied to being the main jitcode. diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -958,27 +958,29 @@ # loop. portal_code = targetjitdriver_sd.mainjitcode inline = True - if self.metainterp.is_main_jitcode(portal_code): - count = 0 - for gk, _ in self.metainterp.portal_trace_positions: - if gk is None: - continue - assert len(gk) == len(greenboxes) - i = 0 - for i in range(len(gk)): - if not gk[i].same_constant(greenboxes[i]): - break - else: - count += 1 - memmgr = self.metainterp.staticdata.warmrunnerdesc.memory_manager - if count >= memmgr.max_unroll_recursion: - # This function is recursive and has exceeded the - # maximum number of unrollings we allow. We want to stop - # inlining it further and to make sure that, if it - # hasn't happened already, the function is traced - # separately as soon as possible. - warmrunnerstate.dont_trace_here(greenboxes) - inline = False + count = 0 + for f in self.metainterp.framestack: + if f.jitcode is not portal_code: + continue + gk = f.greenkey + if gk is None: + continue + assert len(gk) == len(greenboxes) + i = 0 + for i in range(len(gk)): + if not gk[i].same_constant(greenboxes[i]): + break + else: + count += 1 + memmgr = self.metainterp.staticdata.warmrunnerdesc.memory_manager + if count >= memmgr.max_unroll_recursion: + # This function is recursive and has exceeded the + # maximum number of unrollings we allow. We want to stop + # inlining it further and to make sure that, if it + # hasn't happened already, the function is traced + # separately as soon as possible. + warmrunnerstate.dont_trace_here(greenboxes) + inline = False if inline: return self.metainterp.perform_call(portal_code, allboxes, greenkey=greenboxes) From noreply at buildbot.pypy.org Tue Dec 9 17:29:46 2014 From: noreply at buildbot.pypy.org (ltratt) Date: Tue, 9 Dec 2014 17:29:46 +0100 (CET) Subject: [pypy-commit] pypy recursion_and_inlining: We no longer need a separate inline variable. Message-ID: <20141209162946.C30F61C09B2@cobra.cs.uni-duesseldorf.de> Author: Laurence Tratt Branch: recursion_and_inlining Changeset: r74864:b02aa3253678 Date: 2014-12-08 15:39 +0000 http://bitbucket.org/pypy/pypy/changeset/b02aa3253678/ Log: We no longer need a separate inline variable. diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -957,7 +957,6 @@ # recursion, which would be equivalent to unrolling a while # loop. portal_code = targetjitdriver_sd.mainjitcode - inline = True count = 0 for f in self.metainterp.framestack: if f.jitcode is not portal_code: @@ -980,8 +979,7 @@ # hasn't happened already, the function is traced # separately as soon as possible. warmrunnerstate.dont_trace_here(greenboxes) - inline = False - if inline: + else: return self.metainterp.perform_call(portal_code, allboxes, greenkey=greenboxes) assembler_call = True From noreply at buildbot.pypy.org Tue Dec 9 17:29:47 2014 From: noreply at buildbot.pypy.org (ltratt) Date: Tue, 9 Dec 2014 17:29:47 +0100 (CET) Subject: [pypy-commit] pypy recursion_and_inlining: Test that recursing past a specified threshold turns off recursion inlining. Message-ID: <20141209162947.F23691C09B2@cobra.cs.uni-duesseldorf.de> Author: Laurence Tratt Branch: recursion_and_inlining Changeset: r74865:64b3af5150aa Date: 2014-12-09 15:44 +0000 http://bitbucket.org/pypy/pypy/changeset/64b3af5150aa/ Log: Test that recursing past a specified threshold turns off recursion inlining. diff --git a/rpython/jit/metainterp/test/test_recursive.py b/rpython/jit/metainterp/test/test_recursive.py --- a/rpython/jit/metainterp/test/test_recursive.py +++ b/rpython/jit/metainterp/test/test_recursive.py @@ -1112,6 +1112,37 @@ assert res == 2095 self.check_resops(call_assembler=12) + def test_inline_recursion_limit(self): + driver = JitDriver(greens = ["threshold", "loop"], reds=["i"]) + @dont_look_inside + def f(): + set_param(driver, "max_unroll_recursion", 10) + def portal(threshold, loop, i): + f() + if i > threshold: + return i + while True: + driver.jit_merge_point(threshold=threshold, loop=loop, i=i) + if loop: + portal(threshold, False, 0) + else: + portal(threshold, False, i + 1) + return i + if i > 10: + return 1 + i += 1 + driver.can_enter_jit(threshold=threshold, loop=loop, i=i) + + res1 = portal(10, True, 0) + res2 = self.meta_interp(portal, [10, True, 0], inline=True) + assert res1 == res2 + self.check_resops(call_assembler=2) + + res1 = portal(9, True, 0) + res2 = self.meta_interp(portal, [9, True, 0], inline=True) + assert res1 == res2 + self.check_resops(call_assembler=0) + def test_handle_jitexception_in_portal(self): # a test for _handle_jitexception_in_portal in blackhole.py driver = JitDriver(greens = ['codeno'], reds = ['i', 'str'], From noreply at buildbot.pypy.org Tue Dec 9 17:29:49 2014 From: noreply at buildbot.pypy.org (ltratt) Date: Tue, 9 Dec 2014 17:29:49 +0100 (CET) Subject: [pypy-commit] pypy recursion_and_inlining: Add output to JIT logging informing people of when recursive functions have stopped being inlined. Message-ID: <20141209162949.3311E1C09B2@cobra.cs.uni-duesseldorf.de> Author: Laurence Tratt Branch: recursion_and_inlining Changeset: r74866:8b9a6b6f9c9d Date: 2014-12-09 15:44 +0000 http://bitbucket.org/pypy/pypy/changeset/8b9a6b6f9c9d/ Log: Add output to JIT logging informing people of when recursive functions have stopped being inlined. diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -978,6 +978,9 @@ # inlining it further and to make sure that, if it # hasn't happened already, the function is traced # separately as soon as possible. + if have_debug_prints(): + loc = targetjitdriver_sd.warmstate.get_location_str(greenboxes) + debug_print("recursive function (not inlined):", loc) warmrunnerstate.dont_trace_here(greenboxes) else: return self.metainterp.perform_call(portal_code, allboxes, From noreply at buildbot.pypy.org Tue Dec 9 17:29:55 2014 From: noreply at buildbot.pypy.org (ltratt) Date: Tue, 9 Dec 2014 17:29:55 +0100 (CET) Subject: [pypy-commit] pypy recursion_and_inlining: Merge default. Message-ID: <20141209162955.7959C1C09B2@cobra.cs.uni-duesseldorf.de> Author: Laurence Tratt Branch: recursion_and_inlining Changeset: r74867:fd5a11ac1b71 Date: 2014-12-09 15:48 +0000 http://bitbucket.org/pypy/pypy/changeset/fd5a11ac1b71/ Log: Merge default. diff too long, truncating to 2000 out of 18633 lines diff --git a/lib-python/2.7/subprocess.py b/lib-python/2.7/subprocess.py --- a/lib-python/2.7/subprocess.py +++ b/lib-python/2.7/subprocess.py @@ -655,6 +655,21 @@ """Create new Popen instance.""" _cleanup() + # --- PyPy hack, see _pypy_install_libs_after_virtualenv() --- + # match arguments passed by different versions of virtualenv + if args[1:] in ( + ['-c', 'import sys; print(sys.prefix)'], # 1.6 10ba3f3c + ['-c', "\nimport sys\nprefix = sys.prefix\n" # 1.7 0e9342ce + "if sys.version_info[0] == 3:\n" + " prefix = prefix.encode('utf8')\n" + "if hasattr(sys.stdout, 'detach'):\n" + " sys.stdout = sys.stdout.detach()\n" + "elif hasattr(sys.stdout, 'buffer'):\n" + " sys.stdout = sys.stdout.buffer\nsys.stdout.write(prefix)\n"], + ['-c', 'import sys;out=sys.stdout;getattr(out, "buffer"' + ', out).write(sys.prefix.encode("utf-8"))']): # 1.7.2 a9454bce + _pypy_install_libs_after_virtualenv(args[0]) + if not isinstance(bufsize, (int, long)): raise TypeError("bufsize must be an integer") @@ -1560,6 +1575,27 @@ self.send_signal(signal.SIGKILL) +def _pypy_install_libs_after_virtualenv(target_executable): + # https://bitbucket.org/pypy/pypy/issue/1922/future-proofing-virtualenv + # + # PyPy 2.4.1 turned --shared on by default. This means the pypy binary + # depends on the 'libpypy-c.so' shared library to be able to run. + # The virtualenv code existing at the time did not account for this + # and would break. Try to detect that we're running under such a + # virtualenv in the "Testing executable with" phase and copy the + # library ourselves. + caller = sys._getframe(2) + if ('virtualenv_version' in caller.f_globals and + 'copyfile' in caller.f_globals): + dest_dir = sys.pypy_resolvedirof(target_executable) + src_dir = sys.pypy_resolvedirof(sys.executable) + for libname in ['libpypy-c.so']: + dest_library = os.path.join(dest_dir, libname) + src_library = os.path.join(src_dir, libname) + if os.path.exists(src_library): + caller.f_globals['copyfile'](src_library, dest_library) + + def _demo_posix(): # # Example 1: Simple redirection: Get process list diff --git a/lib-python/conftest.py b/lib-python/conftest.py --- a/lib-python/conftest.py +++ b/lib-python/conftest.py @@ -59,7 +59,7 @@ def __init__(self, basename, core=False, compiler=None, usemodules='', skip=None): self.basename = basename - self._usemodules = usemodules.split() + ['signal', 'rctime', 'itertools', '_socket'] + self._usemodules = usemodules.split() + ['signal', 'time', 'itertools', '_socket'] self._compiler = compiler self.core = core self.skip = skip diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py --- a/pypy/config/pypyoption.py +++ b/pypy/config/pypyoption.py @@ -29,7 +29,7 @@ # --allworkingmodules working_modules = default_modules.copy() working_modules.update([ - "_socket", "unicodedata", "mmap", "fcntl", "_locale", "pwd", "rctime" , + "_socket", "unicodedata", "mmap", "fcntl", "_locale", "pwd", "time" , "select", "zipimport", "_lsprof", "crypt", "signal", "_rawffi", "termios", "zlib", "bz2", "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO", "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array", @@ -40,7 +40,7 @@ translation_modules = default_modules.copy() translation_modules.update([ - "fcntl", "rctime", "select", "signal", "_rawffi", "zlib", "struct", "_md5", + "fcntl", "time", "select", "signal", "_rawffi", "zlib", "struct", "_md5", "cStringIO", "array", "binascii", # the following are needed for pyrepl (and hence for the # interactive prompt/pdb) @@ -64,19 +64,15 @@ default_modules.add("_locale") if sys.platform == "sunos5": - working_modules.remove('mmap') # depend on ctypes, can't get at c-level 'errono' - working_modules.remove('rctime') # depend on ctypes, missing tm_zone/tm_gmtoff - working_modules.remove('signal') # depend on ctypes, can't get at c-level 'errono' working_modules.remove('fcntl') # LOCK_NB not defined working_modules.remove("_minimal_curses") working_modules.remove("termios") - working_modules.remove("_multiprocessing") # depends on rctime if "cppyy" in working_modules: working_modules.remove("cppyy") # depends on ctypes module_dependencies = { - '_multiprocessing': [('objspace.usemodules.rctime', True), + '_multiprocessing': [('objspace.usemodules.time', True), ('objspace.usemodules.thread', True)], 'cpyext': [('objspace.usemodules.array', True)], 'cppyy': [('objspace.usemodules.cpyext', True)], diff --git a/pypy/doc/config/objspace.usemodules.rctime.txt b/pypy/doc/config/objspace.usemodules.rctime.txt deleted file mode 100644 --- a/pypy/doc/config/objspace.usemodules.rctime.txt +++ /dev/null @@ -1,7 +0,0 @@ -Use the 'rctime' module. - -'rctime' is our `rffi`_ based implementation of the builtin 'time' module. -It supersedes the less complete :config:`objspace.usemodules.time`, -at least for C-like targets (the C and LLVM backends). - -.. _`rffi`: ../rffi.html diff --git a/pypy/doc/config/objspace.usemodules.time.txt b/pypy/doc/config/objspace.usemodules.time.txt --- a/pypy/doc/config/objspace.usemodules.time.txt +++ b/pypy/doc/config/objspace.usemodules.time.txt @@ -1,5 +1,1 @@ Use the 'time' module. - -Obsolete; use :config:`objspace.usemodules.rctime` for our up-to-date version -of the application-level 'time' module, at least for C-like targets (the C -and LLVM backends). diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst --- a/pypy/doc/cpython_differences.rst +++ b/pypy/doc/cpython_differences.rst @@ -205,23 +205,28 @@ The above is true both in CPython and in PyPy. Differences can occur about whether a built-in function or method will call an overridden method of *another* object than ``self``. -In PyPy, they are generally always called, whereas not in -CPython. For example, in PyPy, ``dict1.update(dict2)`` -considers that ``dict2`` is just a general mapping object, and -will thus call overridden ``keys()`` and ``__getitem__()`` -methods on it. So the following code prints ``42`` on PyPy -but ``foo`` on CPython:: +In PyPy, they are often called in cases where CPython would not. +Two examples:: - >>>> class D(dict): - .... def __getitem__(self, key): - .... return 42 - .... - >>>> - >>>> d1 = {} - >>>> d2 = D(a='foo') - >>>> d1.update(d2) - >>>> print d1['a'] - 42 + class D(dict): + def __getitem__(self, key): + return "%r from D" % (key,) + + class A(object): + pass + + a = A() + a.__dict__ = D() + a.foo = "a's own foo" + print a.foo + # CPython => a's own foo + # PyPy => 'foo' from D + + glob = D(foo="base item") + loc = {} + exec "print foo" in glob, loc + # CPython => base item + # PyPy => 'foo' from D Mutating classes of objects which are already used as dictionary keys @@ -292,6 +297,9 @@ above types will return a value that is computed from the argument, and can thus be larger than ``sys.maxint`` (i.e. it can be an arbitrary long). +Notably missing from the list above are ``str`` and ``unicode``. If your +code relies on comparing strings with ``is``, then it might break in PyPy. + Miscellaneous ------------- diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst --- a/pypy/doc/embedding.rst +++ b/pypy/doc/embedding.rst @@ -6,6 +6,10 @@ C. It was developed in collaboration with Roberto De Ioris from the `uwsgi`_ project. The `PyPy uwsgi plugin`_ is a good example of using the embedding API. +**NOTE**: As of 1st of December, PyPy comes with ``--shared`` by default +on linux, linux64 and windows. We will make it the default on all platforms +by the time of the next release. + The first thing that you need is to compile PyPy yourself with the option ``--shared``. We plan to make ``--shared`` the default in the future. Consult the `how to compile PyPy`_ doc for details. This will result in ``libpypy.so`` diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst --- a/pypy/doc/project-ideas.rst +++ b/pypy/doc/project-ideas.rst @@ -35,6 +35,13 @@ PyPy's bytearray type is very inefficient. It would be an interesting task to look into possible optimizations on this. +Implement AF_XXX packet types for PyPy +-------------------------------------- + +PyPy is missing AF_XXX types of sockets. Implementing it is easy-to-medium +task. `bug report`_ + +.. _`bug report`: https://bitbucket.org/pypy/pypy/issue/1942/support-for-af_xxx-sockets#more Implement copy-on-write list slicing ------------------------------------ diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst --- a/pypy/doc/whatsnew-head.rst +++ b/pypy/doc/whatsnew-head.rst @@ -43,3 +43,11 @@ .. branch nditer-external_loop Implement `external_loop` arguement to numpy's nditer + +.. branch kill-rctime + +Rename pypy/module/rctime to pypy/module/time, since it contains the implementation of the 'time' module. + +.. branch: ssa-flow + +Use SSA form for flow graphs inside build_flow() and part of simplify_graph() diff --git a/pypy/interpreter/astcompiler/assemble.py b/pypy/interpreter/astcompiler/assemble.py --- a/pypy/interpreter/astcompiler/assemble.py +++ b/pypy/interpreter/astcompiler/assemble.py @@ -1,15 +1,13 @@ -""" -Python control flow graph generation and bytecode assembly. -""" +"""Python control flow graph generation and bytecode assembly.""" -from pypy.interpreter.astcompiler import ast, symtable -from pypy.interpreter import pycode +from rpython.rlib import rfloat +from rpython.rlib.objectmodel import we_are_translated + +from pypy.interpreter.astcompiler import ast, misc, symtable +from pypy.interpreter.error import OperationError +from pypy.interpreter.pycode import PyCode from pypy.tool import stdlib_opcode as ops -from pypy.interpreter.error import OperationError -from rpython.rlib.objectmodel import we_are_translated -from rpython.rlib import rfloat - class Instruction(object): """Represents a single opcode.""" @@ -21,14 +19,12 @@ self.has_jump = False def size(self): - """Return the size of bytes of this instruction when it is encoded.""" + """Return the size of bytes of this instruction when it is + encoded. + """ if self.opcode >= ops.HAVE_ARGUMENT: - if self.arg > 0xFFFF: - return 6 - else: - return 3 - else: - return 1 + return (6 if self.arg > 0xFFFF else 3) + return 1 def jump_to(self, target, absolute=False): """Indicate the target this jump instruction. @@ -54,9 +50,9 @@ class Block(object): """A basic control flow block. - It has one entry point and several possible exit points. Its instructions - may be jumps to other blocks, or if control flow reaches the end of the - block, it continues to next_block. + It has one entry point and several possible exit points. Its + instructions may be jumps to other blocks, or if control flow + reaches the end of the block, it continues to next_block. """ def __init__(self): @@ -71,10 +67,10 @@ stack.append(nextblock) def post_order(self): - """Return this block and its children in post order. - This means that the graph of blocks is first cleaned up to - ignore back-edges, thus turning it into a DAG. Then the DAG - is linearized. For example: + """Return this block and its children in post order. This means + that the graph of blocks is first cleaned up to ignore + back-edges, thus turning it into a DAG. Then the DAG is + linearized. For example: A --> B -\ => [A, D, B, C] \-> D ---> C @@ -105,7 +101,9 @@ return resultblocks def code_size(self): - """Return the encoded size of all the instructions in this block.""" + """Return the encoded size of all the instructions in this + block. + """ i = 0 for instr in self.instructions: i += instr.size() @@ -141,6 +139,7 @@ i += 1 return result + def _list_to_dict(l, offset=0): result = {} index = offset @@ -300,11 +299,11 @@ def _resolve_block_targets(self, blocks): """Compute the arguments of jump instructions.""" last_extended_arg_count = 0 - # The reason for this loop is extended jumps. EXTENDED_ARG extends the - # bytecode size, so it might invalidate the offsets we've already given. - # Thus we have to loop until the number of extended args is stable. Any - # extended jump at all is extremely rare, so performance is not too - # concerning. + # The reason for this loop is extended jumps. EXTENDED_ARG + # extends the bytecode size, so it might invalidate the offsets + # we've already given. Thus we have to loop until the number of + # extended args is stable. Any extended jump at all is + # extremely rare, so performance is not too concerning. while True: extended_arg_count = 0 offset = 0 @@ -330,7 +329,8 @@ instr.opcode = ops.JUMP_ABSOLUTE absolute = True elif target_op == ops.RETURN_VALUE: - # Replace JUMP_* to a RETURN into just a RETURN + # Replace JUMP_* to a RETURN into + # just a RETURN instr.opcode = ops.RETURN_VALUE instr.arg = 0 instr.has_jump = False @@ -345,7 +345,8 @@ instr.arg = jump_arg if jump_arg > 0xFFFF: extended_arg_count += 1 - if extended_arg_count == last_extended_arg_count and not force_redo: + if (extended_arg_count == last_extended_arg_count and + not force_redo): break else: last_extended_arg_count = extended_arg_count @@ -360,12 +361,14 @@ while True: try: w_key = space.next(w_iter) - except OperationError, e: + except OperationError as e: if not e.match(space, space.w_StopIteration): raise break w_index = space.getitem(w_consts, w_key) - consts_w[space.int_w(w_index)] = space.getitem(w_key, first) + w_constant = space.getitem(w_key, first) + w_constant = misc.intern_if_common_string(space, w_constant) + consts_w[space.int_w(w_index)] = w_constant return consts_w def _get_code_flags(self): @@ -433,15 +436,16 @@ continue addr = offset - current_off # Python assumes that lineno always increases with - # increasing bytecode address (lnotab is unsigned char). - # Depending on when SET_LINENO instructions are emitted this - # is not always true. Consider the code: + # increasing bytecode address (lnotab is unsigned + # char). Depending on when SET_LINENO instructions + # are emitted this is not always true. Consider the + # code: # a = (1, # b) - # In the bytecode stream, the assignment to "a" occurs after - # the loading of "b". This works with the C Python compiler - # because it only generates a SET_LINENO instruction for the - # assignment. + # In the bytecode stream, the assignment to "a" + # occurs after the loading of "b". This works with + # the C Python compiler because it only generates a + # SET_LINENO instruction for the assignment. if line or addr: while addr > 255: push(chr(255)) @@ -484,22 +488,22 @@ free_names = _list_from_dict(self.free_vars, len(cell_names)) flags = self._get_code_flags() | self.compile_info.flags bytecode = ''.join([block.get_code() for block in blocks]) - return pycode.PyCode(self.space, - self.argcount, - len(self.var_names), - stack_depth, - flags, - bytecode, - list(consts_w), - names, - var_names, - self.compile_info.filename, - self.name, - self.first_lineno, - lnotab, - free_names, - cell_names, - self.compile_info.hidden_applevel) + return PyCode(self.space, + self.argcount, + len(self.var_names), + stack_depth, + flags, + bytecode, + list(consts_w), + names, + var_names, + self.compile_info.filename, + self.name, + self.first_lineno, + lnotab, + free_names, + cell_names, + self.compile_info.hidden_applevel) def _list_from_dict(d, offset=0): @@ -510,134 +514,134 @@ _static_opcode_stack_effects = { - ops.NOP : 0, - ops.STOP_CODE : 0, + ops.NOP: 0, + ops.STOP_CODE: 0, - ops.POP_TOP : -1, - ops.ROT_TWO : 0, - ops.ROT_THREE : 0, - ops.ROT_FOUR : 0, - ops.DUP_TOP : 1, + ops.POP_TOP: -1, + ops.ROT_TWO: 0, + ops.ROT_THREE: 0, + ops.ROT_FOUR: 0, + ops.DUP_TOP: 1, - ops.UNARY_POSITIVE : 0, - ops.UNARY_NEGATIVE : 0, - ops.UNARY_NOT : 0, - ops.UNARY_CONVERT : 0, - ops.UNARY_INVERT : 0, + ops.UNARY_POSITIVE: 0, + ops.UNARY_NEGATIVE: 0, + ops.UNARY_NOT: 0, + ops.UNARY_CONVERT: 0, + ops.UNARY_INVERT: 0, - ops.LIST_APPEND : -1, - ops.SET_ADD : -1, - ops.MAP_ADD : -2, - ops.STORE_MAP : -2, + ops.LIST_APPEND: -1, + ops.SET_ADD: -1, + ops.MAP_ADD: -2, + ops.STORE_MAP: -2, - ops.BINARY_POWER : -1, - ops.BINARY_MULTIPLY : -1, - ops.BINARY_DIVIDE : -1, - ops.BINARY_MODULO : -1, - ops.BINARY_ADD : -1, - ops.BINARY_SUBTRACT : -1, - ops.BINARY_SUBSCR : -1, - ops.BINARY_FLOOR_DIVIDE : -1, - ops.BINARY_TRUE_DIVIDE : -1, - ops.BINARY_LSHIFT : -1, - ops.BINARY_RSHIFT : -1, - ops.BINARY_AND : -1, - ops.BINARY_OR : -1, - ops.BINARY_XOR : -1, + ops.BINARY_POWER: -1, + ops.BINARY_MULTIPLY: -1, + ops.BINARY_DIVIDE: -1, + ops.BINARY_MODULO: -1, + ops.BINARY_ADD: -1, + ops.BINARY_SUBTRACT: -1, + ops.BINARY_SUBSCR: -1, + ops.BINARY_FLOOR_DIVIDE: -1, + ops.BINARY_TRUE_DIVIDE: -1, + ops.BINARY_LSHIFT: -1, + ops.BINARY_RSHIFT: -1, + ops.BINARY_AND: -1, + ops.BINARY_OR: -1, + ops.BINARY_XOR: -1, - ops.INPLACE_FLOOR_DIVIDE : -1, - ops.INPLACE_TRUE_DIVIDE : -1, - ops.INPLACE_ADD : -1, - ops.INPLACE_SUBTRACT : -1, - ops.INPLACE_MULTIPLY : -1, - ops.INPLACE_DIVIDE : -1, - ops.INPLACE_MODULO : -1, - ops.INPLACE_POWER : -1, - ops.INPLACE_LSHIFT : -1, - ops.INPLACE_RSHIFT : -1, - ops.INPLACE_AND : -1, - ops.INPLACE_OR : -1, - ops.INPLACE_XOR : -1, + ops.INPLACE_FLOOR_DIVIDE: -1, + ops.INPLACE_TRUE_DIVIDE: -1, + ops.INPLACE_ADD: -1, + ops.INPLACE_SUBTRACT: -1, + ops.INPLACE_MULTIPLY: -1, + ops.INPLACE_DIVIDE: -1, + ops.INPLACE_MODULO: -1, + ops.INPLACE_POWER: -1, + ops.INPLACE_LSHIFT: -1, + ops.INPLACE_RSHIFT: -1, + ops.INPLACE_AND: -1, + ops.INPLACE_OR: -1, + ops.INPLACE_XOR: -1, - ops.SLICE+0 : 1, - ops.SLICE+1 : 0, - ops.SLICE+2 : 0, - ops.SLICE+3 : -1, - ops.STORE_SLICE+0 : -2, - ops.STORE_SLICE+1 : -3, - ops.STORE_SLICE+2 : -3, - ops.STORE_SLICE+3 : -4, - ops.DELETE_SLICE+0 : -1, - ops.DELETE_SLICE+1 : -2, - ops.DELETE_SLICE+2 : -2, - ops.DELETE_SLICE+3 : -3, + ops.SLICE+0: 1, + ops.SLICE+1: 0, + ops.SLICE+2: 0, + ops.SLICE+3: -1, + ops.STORE_SLICE+0: -2, + ops.STORE_SLICE+1: -3, + ops.STORE_SLICE+2: -3, + ops.STORE_SLICE+3: -4, + ops.DELETE_SLICE+0: -1, + ops.DELETE_SLICE+1: -2, + ops.DELETE_SLICE+2: -2, + ops.DELETE_SLICE+3: -3, - ops.STORE_SUBSCR : -2, - ops.DELETE_SUBSCR : -2, + ops.STORE_SUBSCR: -2, + ops.DELETE_SUBSCR: -2, - ops.GET_ITER : 0, - ops.FOR_ITER : 1, - ops.BREAK_LOOP : 0, - ops.CONTINUE_LOOP : 0, - ops.SETUP_LOOP : 0, + ops.GET_ITER: 0, + ops.FOR_ITER: 1, + ops.BREAK_LOOP: 0, + ops.CONTINUE_LOOP: 0, + ops.SETUP_LOOP: 0, - ops.PRINT_EXPR : -1, - ops.PRINT_ITEM : -1, - ops.PRINT_NEWLINE : 0, - ops.PRINT_ITEM_TO : -2, - ops.PRINT_NEWLINE_TO : -1, + ops.PRINT_EXPR: -1, + ops.PRINT_ITEM: -1, + ops.PRINT_NEWLINE: 0, + ops.PRINT_ITEM_TO: -2, + ops.PRINT_NEWLINE_TO: -1, - ops.WITH_CLEANUP : -1, - ops.POP_BLOCK : 0, - ops.END_FINALLY : -1, - ops.SETUP_WITH : 1, - ops.SETUP_FINALLY : 0, - ops.SETUP_EXCEPT : 0, + ops.WITH_CLEANUP: -1, + ops.POP_BLOCK: 0, + ops.END_FINALLY: -1, + ops.SETUP_WITH: 1, + ops.SETUP_FINALLY: 0, + ops.SETUP_EXCEPT: 0, - ops.LOAD_LOCALS : 1, - ops.RETURN_VALUE : -1, - ops.EXEC_STMT : -3, - ops.YIELD_VALUE : 0, - ops.BUILD_CLASS : -2, - ops.BUILD_MAP : 1, - ops.BUILD_SET : 1, - ops.COMPARE_OP : -1, + ops.LOAD_LOCALS: 1, + ops.RETURN_VALUE: -1, + ops.EXEC_STMT: -3, + ops.YIELD_VALUE: 0, + ops.BUILD_CLASS: -2, + ops.BUILD_MAP: 1, + ops.BUILD_SET: 1, + ops.COMPARE_OP: -1, - ops.LOOKUP_METHOD : 1, + ops.LOOKUP_METHOD: 1, - ops.LOAD_NAME : 1, - ops.STORE_NAME : -1, - ops.DELETE_NAME : 0, + ops.LOAD_NAME: 1, + ops.STORE_NAME: -1, + ops.DELETE_NAME: 0, - ops.LOAD_FAST : 1, - ops.STORE_FAST : -1, - ops.DELETE_FAST : 0, + ops.LOAD_FAST: 1, + ops.STORE_FAST: -1, + ops.DELETE_FAST: 0, - ops.LOAD_ATTR : 0, - ops.STORE_ATTR : -2, - ops.DELETE_ATTR : -1, + ops.LOAD_ATTR: 0, + ops.STORE_ATTR: -2, + ops.DELETE_ATTR: -1, - ops.LOAD_GLOBAL : 1, - ops.STORE_GLOBAL : -1, - ops.DELETE_GLOBAL : 0, + ops.LOAD_GLOBAL: 1, + ops.STORE_GLOBAL: -1, + ops.DELETE_GLOBAL: 0, - ops.LOAD_CLOSURE : 1, - ops.LOAD_DEREF : 1, - ops.STORE_DEREF : -1, + ops.LOAD_CLOSURE: 1, + ops.LOAD_DEREF: 1, + ops.STORE_DEREF: -1, - ops.LOAD_CONST : 1, + ops.LOAD_CONST: 1, - ops.IMPORT_STAR : -1, - ops.IMPORT_NAME : -1, - ops.IMPORT_FROM : 1, + ops.IMPORT_STAR: -1, + ops.IMPORT_NAME: -1, + ops.IMPORT_FROM: 1, - ops.JUMP_FORWARD : 0, - ops.JUMP_ABSOLUTE : 0, - ops.JUMP_IF_TRUE_OR_POP : 0, - ops.JUMP_IF_FALSE_OR_POP : 0, - ops.POP_JUMP_IF_TRUE : -1, - ops.POP_JUMP_IF_FALSE : -1, - ops.JUMP_IF_NOT_DEBUG : 0, + ops.JUMP_FORWARD: 0, + ops.JUMP_ABSOLUTE: 0, + ops.JUMP_IF_TRUE_OR_POP: 0, + ops.JUMP_IF_FALSE_OR_POP: 0, + ops.POP_JUMP_IF_TRUE: -1, + ops.POP_JUMP_IF_FALSE: -1, + ops.JUMP_IF_NOT_DEBUG: 0, ops.BUILD_LIST_FROM_ARG: 1, } diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py --- a/pypy/interpreter/astcompiler/misc.py +++ b/pypy/interpreter/astcompiler/misc.py @@ -106,3 +106,13 @@ except IndexError: return name return "_%s%s" % (klass[i:], name) + + +def intern_if_common_string(space, w_const): + # only intern identifier-like strings + if not space.is_w(space.type(w_const), space.w_str): + return w_const + for c in space.str_w(w_const): + if not (c.isalnum() or c == '_'): + return w_const + return space.new_interned_w_str(w_const) diff --git a/pypy/interpreter/astcompiler/optimize.py b/pypy/interpreter/astcompiler/optimize.py --- a/pypy/interpreter/astcompiler/optimize.py +++ b/pypy/interpreter/astcompiler/optimize.py @@ -272,6 +272,11 @@ if w_const is None: return tup consts_w[i] = w_const + # intern the string constants packed into the tuple here, + # because assemble.py will see the result as just a tuple constant + for i in range(len(consts_w)): + consts_w[i] = misc.intern_if_common_string( + self.space, consts_w[i]) else: consts_w = [] w_consts = self.space.newtuple(consts_w) diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -14,7 +14,7 @@ UserDelAction) from pypy.interpreter.error import OperationError, new_exception_class, oefmt from pypy.interpreter.argument import Arguments -from pypy.interpreter.miscutils import ThreadLocals +from pypy.interpreter.miscutils import ThreadLocals, make_weak_value_dictionary __all__ = ['ObjSpace', 'OperationError', 'W_Root'] @@ -384,7 +384,7 @@ self.builtin_modules = {} self.reloading_modules = {} - self.interned_strings = {} + self.interned_strings = make_weak_value_dictionary(self, str, W_Root) self.actionflag = ActionFlag() # changed by the signal module self.check_signal_action = None # changed by the signal module self.user_del_action = UserDelAction(self) @@ -522,11 +522,6 @@ if name not in modules: modules.append(name) - # a bit of custom logic: rctime take precedence over time - # XXX this could probably be done as a "requires" in the config - if 'rctime' in modules and 'time' in modules: - modules.remove('time') - self._builtinmodule_list = modules return self._builtinmodule_list @@ -782,25 +777,30 @@ return self.w_False def new_interned_w_str(self, w_s): + assert isinstance(w_s, W_Root) # and is not None s = self.str_w(w_s) if not we_are_translated(): assert type(s) is str - try: - return self.interned_strings[s] - except KeyError: - pass - self.interned_strings[s] = w_s - return w_s + w_s1 = self.interned_strings.get(s) + if w_s1 is None: + w_s1 = w_s + self.interned_strings.set(s, w_s1) + return w_s1 def new_interned_str(self, s): if not we_are_translated(): assert type(s) is str - try: - return self.interned_strings[s] - except KeyError: - pass - w_s = self.interned_strings[s] = self.wrap(s) - return w_s + w_s1 = self.interned_strings.get(s) + if w_s1 is None: + w_s1 = self.wrap(s) + self.interned_strings.set(s, w_s1) + return w_s1 + + def is_interned_str(self, s): + # interface for marshal_impl + if not we_are_translated(): + assert type(s) is str + return self.interned_strings.get(s) is not None def descr_self_interp_w(self, RequiredClass, w_obj): if not isinstance(w_obj, RequiredClass): diff --git a/pypy/interpreter/miscutils.py b/pypy/interpreter/miscutils.py --- a/pypy/interpreter/miscutils.py +++ b/pypy/interpreter/miscutils.py @@ -31,3 +31,19 @@ def getallvalues(self): return {0: self._value} + + +def make_weak_value_dictionary(space, keytype, valuetype): + "NOT_RPYTHON" + if space.config.translation.rweakref: + from rpython.rlib.rweakref import RWeakValueDictionary + return RWeakValueDictionary(keytype, valuetype) + else: + class FakeWeakValueDict(object): + def __init__(self): + self._dict = {} + def get(self, key): + return self._dict.get(key, None) + def set(self, key, value): + self._dict[key] = value + return FakeWeakValueDict() diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -131,7 +131,6 @@ # class bodies only have CO_NEWLOCALS. # CO_NEWLOCALS: make a locals dict unless optimized is also set # CO_OPTIMIZED: no locals dict needed at all - # NB: this method is overridden in nestedscope.py flags = code.co_flags if not (flags & pycode.CO_OPTIMIZED): if flags & pycode.CO_NEWLOCALS: diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py --- a/pypy/interpreter/test/test_compiler.py +++ b/pypy/interpreter/test/test_compiler.py @@ -970,7 +970,12 @@ sys.stdout = out output = s.getvalue() assert "CALL_METHOD" in output - + + def test_interned_strings(self): + source = """x = ('foo_bar42', 5); y = 'foo_bar42'; z = x[0]""" + exec source + assert y is z + class AppTestExceptions: def test_indentation_error(self): diff --git a/pypy/interpreter/test/test_objspace.py b/pypy/interpreter/test/test_objspace.py --- a/pypy/interpreter/test/test_objspace.py +++ b/pypy/interpreter/test/test_objspace.py @@ -378,3 +378,41 @@ assert space.str_w(space.getattr(space.sys, w_executable)) == 'foobar' space.startup() assert space.str_w(space.getattr(space.sys, w_executable)) == 'foobar' + + def test_interned_strings_are_weak(self): + import weakref, gc, random + space = self.space + assert space.config.translation.rweakref + w1 = space.new_interned_str("abcdef") + w2 = space.new_interned_str("abcdef") + assert w2 is w1 + # + # check that 'w1' goes away if we don't hold a reference to it + rw1 = weakref.ref(w1) + del w1, w2 + i = 10 + while rw1() is not None: + i -= 1 + assert i >= 0 + gc.collect() + # + s = "foobar%r" % random.random() + w0 = space.wrap(s) + w1 = space.new_interned_w_str(w0) + assert w1 is w0 + w2 = space.new_interned_w_str(w0) + assert w2 is w0 + w3 = space.wrap(s) + assert w3 is not w0 + w4 = space.new_interned_w_str(w3) + assert w4 is w0 + # + # check that 'w0' goes away if we don't hold a reference to it + # (even if we hold a reference to 'w3') + rw0 = weakref.ref(w0) + del w0, w1, w2, w4 + i = 10 + while rw0() is not None: + i -= 1 + assert i >= 0 + gc.collect() diff --git a/pypy/module/_cffi_backend/ctypeprim.py b/pypy/module/_cffi_backend/ctypeprim.py --- a/pypy/module/_cffi_backend/ctypeprim.py +++ b/pypy/module/_cffi_backend/ctypeprim.py @@ -158,21 +158,14 @@ class W_CTypePrimitiveSigned(W_CTypePrimitive): - _attrs_ = ['value_fits_long', 'vmin', 'vrangemax'] - _immutable_fields_ = ['value_fits_long', 'vmin', 'vrangemax'] + _attrs_ = ['value_fits_long', 'value_smaller_than_long'] + _immutable_fields_ = ['value_fits_long', 'value_smaller_than_long'] is_primitive_integer = True def __init__(self, *args): W_CTypePrimitive.__init__(self, *args) self.value_fits_long = self.size <= rffi.sizeof(lltype.Signed) - if self.size < rffi.sizeof(lltype.Signed): - assert self.value_fits_long - sh = self.size * 8 - self.vmin = r_uint(-1) << (sh - 1) - self.vrangemax = (r_uint(1) << sh) - 1 - else: - self.vmin = r_uint(0) - self.vrangemax = r_uint(-1) + self.value_smaller_than_long = self.size < rffi.sizeof(lltype.Signed) def cast_to_int(self, cdata): return self.convert_to_object(cdata) @@ -192,8 +185,17 @@ def convert_from_object(self, cdata, w_ob): if self.value_fits_long: value = misc.as_long(self.space, w_ob) - if self.size < rffi.sizeof(lltype.Signed): - if r_uint(value) - self.vmin > self.vrangemax: + if self.value_smaller_than_long: + size = self.size + if size == 1: + signextended = misc.signext(value, 1) + elif size == 2: + signextended = misc.signext(value, 2) + elif size == 4: + signextended = misc.signext(value, 4) + else: + raise AssertionError("unsupported size") + if value != signextended: self._overflow(w_ob) misc.write_raw_signed_data(cdata, value, self.size) else: @@ -221,7 +223,7 @@ length = w_cdata.get_array_length() populate_list_from_raw_array(res, buf, length) return res - elif self.value_fits_long: + elif self.value_smaller_than_long: res = [0] * w_cdata.get_array_length() misc.unpack_list_from_raw_array(res, w_cdata._cdata, self.size) return res @@ -235,8 +237,8 @@ cdata = rffi.cast(rffi.LONGP, cdata) copy_list_to_raw_array(int_list, cdata) else: - overflowed = misc.pack_list_to_raw_array_bounds( - int_list, cdata, self.size, self.vmin, self.vrangemax) + overflowed = misc.pack_list_to_raw_array_bounds_signed( + int_list, cdata, self.size) if overflowed != 0: self._overflow(self.space.wrap(overflowed)) return True @@ -314,8 +316,8 @@ def pack_list_of_items(self, cdata, w_ob): int_list = self.space.listview_int(w_ob) if int_list is not None: - overflowed = misc.pack_list_to_raw_array_bounds( - int_list, cdata, self.size, r_uint(0), self.vrangemax) + overflowed = misc.pack_list_to_raw_array_bounds_unsigned( + int_list, cdata, self.size, self.vrangemax) if overflowed != 0: self._overflow(self.space.wrap(overflowed)) return True diff --git a/pypy/module/_cffi_backend/misc.py b/pypy/module/_cffi_backend/misc.py --- a/pypy/module/_cffi_backend/misc.py +++ b/pypy/module/_cffi_backend/misc.py @@ -216,6 +216,19 @@ neg_msg = "can't convert negative number to unsigned" ovf_msg = "long too big to convert" + at specialize.arg(1) +def signext(value, size): + # 'value' is sign-extended from 'size' bytes to a full integer. + # 'size' should be a constant smaller than a full integer size. + if size == rffi.sizeof(rffi.SIGNEDCHAR): + return rffi.cast(lltype.Signed, rffi.cast(rffi.SIGNEDCHAR, value)) + elif size == rffi.sizeof(rffi.SHORT): + return rffi.cast(lltype.Signed, rffi.cast(rffi.SHORT, value)) + elif size == rffi.sizeof(rffi.INT): + return rffi.cast(lltype.Signed, rffi.cast(rffi.INT, value)) + else: + raise AssertionError("unsupported size") + # ____________________________________________________________ class _NotStandardObject(Exception): @@ -334,13 +347,26 @@ # ____________________________________________________________ -def pack_list_to_raw_array_bounds(int_list, target, size, vmin, vrangemax): +def pack_list_to_raw_array_bounds_signed(int_list, target, size): for TP, TPP in _prim_signed_types: if size == rffi.sizeof(TP): ptr = rffi.cast(TPP, target) for i in range(len(int_list)): x = int_list[i] - if r_uint(x) - vmin > vrangemax: + y = rffi.cast(TP, x) + if x != rffi.cast(lltype.Signed, y): + return x # overflow + ptr[i] = y + return 0 + raise NotImplementedError("bad integer size") + +def pack_list_to_raw_array_bounds_unsigned(int_list, target, size, vrangemax): + for TP, TPP in _prim_signed_types: + if size == rffi.sizeof(TP): + ptr = rffi.cast(TPP, target) + for i in range(len(int_list)): + x = int_list[i] + if r_uint(x) > vrangemax: return x # overflow ptr[i] = rffi.cast(TP, x) return 0 diff --git a/pypy/module/_file/test/test_file.py b/pypy/module/_file/test/test_file.py --- a/pypy/module/_file/test/test_file.py +++ b/pypy/module/_file/test/test_file.py @@ -304,7 +304,7 @@ py.test.skip("works with internals of _file impl on py.py") state = [0] def read(fd, n=None): - if fd != 42: + if fd != 424242: return cls.old_read(fd, n) if state[0] == 0: state[0] += 1 @@ -315,7 +315,7 @@ return '' os.read = read stdin = W_File(cls.space) - stdin.file_fdopen(42, 'rb', 1) + stdin.file_fdopen(424242, 'rb', 1) stdin.name = '' cls.w_stream = stdin diff --git a/pypy/module/_file/test/test_file_extra.py b/pypy/module/_file/test/test_file_extra.py --- a/pypy/module/_file/test/test_file_extra.py +++ b/pypy/module/_file/test/test_file_extra.py @@ -221,7 +221,7 @@ expected_filename = str(udir.join('sample')) expected_mode = 'rb' extra_args = () - spaceconfig = {'usemodules': ['binascii', 'rctime', 'struct']} + spaceconfig = {'usemodules': ['binascii', 'time', 'struct']} def setup_method(self, method): space = self.space @@ -281,7 +281,7 @@ expected_filename = '' expected_mode = 'rb' extra_args = () - spaceconfig = {'usemodules': ['binascii', 'rctime', 'struct']} + spaceconfig = {'usemodules': ['binascii', 'time', 'struct']} def setup_method(self, method): space = self.space @@ -359,7 +359,7 @@ # A few extra tests class AppTestAFewExtra: - spaceconfig = {'usemodules': ['_socket', 'array', 'binascii', 'rctime', + spaceconfig = {'usemodules': ['_socket', 'array', 'binascii', 'time', 'struct']} def setup_method(self, method): diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -1,6 +1,6 @@ class AppTestCProfile(object): spaceconfig = { - "usemodules": ['_lsprof', 'rctime'], + "usemodules": ['_lsprof', 'time'], } def setup_class(cls): diff --git a/pypy/module/_md5/test/test_md5.py b/pypy/module/_md5/test/test_md5.py --- a/pypy/module/_md5/test/test_md5.py +++ b/pypy/module/_md5/test/test_md5.py @@ -5,7 +5,7 @@ class AppTestMD5(object): spaceconfig = { - 'usemodules': ['_md5', 'binascii', 'rctime', 'struct'], + 'usemodules': ['_md5', 'binascii', 'time', 'struct'], } def setup_class(cls): diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py --- a/pypy/module/_multiprocessing/interp_semaphore.py +++ b/pypy/module/_multiprocessing/interp_semaphore.py @@ -254,7 +254,7 @@ start = _GetTickCount() while True: - from pypy.module.rctime.interp_time import State + from pypy.module.time.interp_time import State interrupt_event = space.fromcache(State).get_interrupt_event() handles = [self.handle, interrupt_event] diff --git a/pypy/module/_random/test/test_random.py b/pypy/module/_random/test/test_random.py --- a/pypy/module/_random/test/test_random.py +++ b/pypy/module/_random/test/test_random.py @@ -1,6 +1,6 @@ class AppTestRandom: spaceconfig = { - "usemodules": ['_random', 'rctime'], + "usemodules": ['_random', 'time'], } def test_dict(self): diff --git a/pypy/module/_sha/test/test_sha.py b/pypy/module/_sha/test/test_sha.py --- a/pypy/module/_sha/test/test_sha.py +++ b/pypy/module/_sha/test/test_sha.py @@ -5,7 +5,7 @@ class AppTestSHA(object): spaceconfig = { - 'usemodules': ['_sha', 'binascii', 'rctime', 'struct'], + 'usemodules': ['_sha', 'binascii', 'time', 'struct'], } def setup_class(cls): diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -52,7 +52,8 @@ if not OPENSSL_NO_SSL2: constants["PROTOCOL_SSLv2"] = PY_SSL_VERSION_SSL2 -constants["PROTOCOL_SSLv3"] = PY_SSL_VERSION_SSL3 +if not OPENSSL_NO_SSL3: + constants["PROTOCOL_SSLv3"] = PY_SSL_VERSION_SSL3 constants["PROTOCOL_SSLv23"] = PY_SSL_VERSION_SSL23 constants["PROTOCOL_TLSv1"] = PY_SSL_VERSION_TLS1 @@ -656,7 +657,7 @@ # set up context if protocol == PY_SSL_VERSION_TLS1: method = libssl_TLSv1_method() - elif protocol == PY_SSL_VERSION_SSL3: + elif protocol == PY_SSL_VERSION_SSL3 and not OPENSSL_NO_SSL3: method = libssl_SSLv3_method() elif protocol == PY_SSL_VERSION_SSL2 and not OPENSSL_NO_SSL2: method = libssl_SSLv2_method() diff --git a/pypy/module/_ssl/thread_lock.py b/pypy/module/_ssl/thread_lock.py --- a/pypy/module/_ssl/thread_lock.py +++ b/pypy/module/_ssl/thread_lock.py @@ -24,12 +24,19 @@ separate_module_source = """ #include +#ifndef _WIN32 +# include +#endif static unsigned int _ssl_locks_count = 0; static struct RPyOpaque_ThreadLock *_ssl_locks; static unsigned long _ssl_thread_id_function(void) { - return RPyThreadGetIdent(); +#ifdef _WIN32 + return (unsigned long)GetCurrentThreadId(); +#else + return (unsigned long)pthread_self(); +#endif } static void _ssl_thread_locking_function(int mode, int n, const char *file, diff --git a/pypy/module/bz2/test/test_bz2_file.py b/pypy/module/bz2/test/test_bz2_file.py --- a/pypy/module/bz2/test/test_bz2_file.py +++ b/pypy/module/bz2/test/test_bz2_file.py @@ -53,7 +53,7 @@ class AppTestBZ2File(CheckAllocation): spaceconfig = { - 'usemodules': ['bz2', 'binascii', 'rctime', 'struct'] + 'usemodules': ['bz2', 'binascii', 'time', 'struct'] } def setup_class(cls): diff --git a/pypy/module/cppyy/include/capi.h b/pypy/module/cppyy/include/capi.h --- a/pypy/module/cppyy/include/capi.h +++ b/pypy/module/cppyy/include/capi.h @@ -2,6 +2,7 @@ #define CPPYY_CAPI #include +#include "src/precommondefs.h" #ifdef __cplusplus extern "C" { @@ -15,102 +16,167 @@ typedef void* (*cppyy_methptrgetter_t)(cppyy_object_t); /* name to opaque C++ scope representation -------------------------------- */ + RPY_EXTERN int cppyy_num_scopes(cppyy_scope_t parent); + RPY_EXTERN char* cppyy_scope_name(cppyy_scope_t parent, int iscope); + RPY_EXTERN char* cppyy_resolve_name(const char* cppitem_name); + RPY_EXTERN cppyy_scope_t cppyy_get_scope(const char* scope_name); + RPY_EXTERN cppyy_type_t cppyy_get_template(const char* template_name); + RPY_EXTERN cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t obj); /* memory management ------------------------------------------------------ */ + RPY_EXTERN cppyy_object_t cppyy_allocate(cppyy_type_t type); + RPY_EXTERN void cppyy_deallocate(cppyy_type_t type, cppyy_object_t self); + RPY_EXTERN void cppyy_destruct(cppyy_type_t type, cppyy_object_t self); /* method/function dispatching -------------------------------------------- */ + RPY_EXTERN void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN void* cppyy_call_r(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args); + RPY_EXTERN cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t klass, int nargs, void* args); + RPY_EXTERN cppyy_object_t cppyy_call_o(cppyy_method_t method, cppyy_object_t self, int nargs, void* args, cppyy_type_t result_type); + RPY_EXTERN cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_scope_t scope, cppyy_index_t idx); /* handling of function argument buffer ----------------------------------- */ + RPY_EXTERN void* cppyy_allocate_function_args(int nargs); + RPY_EXTERN void cppyy_deallocate_function_args(void* args); + RPY_EXTERN size_t cppyy_function_arg_sizeof(); + RPY_EXTERN size_t cppyy_function_arg_typeoffset(); /* scope reflection information ------------------------------------------- */ + RPY_EXTERN int cppyy_is_namespace(cppyy_scope_t scope); + RPY_EXTERN int cppyy_is_enum(const char* type_name); /* class reflection information ------------------------------------------- */ + RPY_EXTERN char* cppyy_final_name(cppyy_type_t type); + RPY_EXTERN char* cppyy_scoped_final_name(cppyy_type_t type); + RPY_EXTERN int cppyy_has_complex_hierarchy(cppyy_type_t type); + RPY_EXTERN int cppyy_num_bases(cppyy_type_t type); + RPY_EXTERN char* cppyy_base_name(cppyy_type_t type, int base_index); + RPY_EXTERN int cppyy_is_subtype(cppyy_type_t derived, cppyy_type_t base); /* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */ + RPY_EXTERN ptrdiff_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction); /* method/function reflection information --------------------------------- */ + RPY_EXTERN int cppyy_num_methods(cppyy_scope_t scope); + RPY_EXTERN cppyy_index_t cppyy_method_index_at(cppyy_scope_t scope, int imeth); + RPY_EXTERN cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const char* name); + RPY_EXTERN char* cppyy_method_name(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN char* cppyy_method_result_type(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN int cppyy_method_num_args(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN int cppyy_method_req_args(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN char* cppyy_method_arg_type(cppyy_scope_t scope, cppyy_index_t idx, int arg_index); + RPY_EXTERN char* cppyy_method_arg_default(cppyy_scope_t scope, cppyy_index_t idx, int arg_index); + RPY_EXTERN char* cppyy_method_signature(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN int cppyy_method_num_template_args(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN char* cppyy_method_template_arg_name(cppyy_scope_t scope, cppyy_index_t idx, cppyy_index_t iarg); + RPY_EXTERN cppyy_method_t cppyy_get_method(cppyy_scope_t scope, cppyy_index_t idx); + RPY_EXTERN cppyy_index_t cppyy_get_global_operator( cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op); /* method properties ------------------------------------------------------ */ + RPY_EXTERN int cppyy_is_constructor(cppyy_type_t type, cppyy_index_t idx); + RPY_EXTERN int cppyy_is_staticmethod(cppyy_type_t type, cppyy_index_t idx); /* data member reflection information ------------------------------------- */ + RPY_EXTERN int cppyy_num_datamembers(cppyy_scope_t scope); + RPY_EXTERN char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index); + RPY_EXTERN char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index); + RPY_EXTERN ptrdiff_t cppyy_datamember_offset(cppyy_scope_t scope, int datamember_index); + RPY_EXTERN int cppyy_datamember_index(cppyy_scope_t scope, const char* name); /* data member properties ------------------------------------------------- */ + RPY_EXTERN int cppyy_is_publicdata(cppyy_type_t type, int datamember_index); + RPY_EXTERN int cppyy_is_staticdata(cppyy_type_t type, int datamember_index); /* misc helpers ----------------------------------------------------------- */ + RPY_EXTERN long long cppyy_strtoll(const char* str); + RPY_EXTERN unsigned long long cppyy_strtoull(const char* str); + RPY_EXTERN void cppyy_free(void* ptr); + RPY_EXTERN cppyy_object_t cppyy_charp2stdstring(const char* str); + RPY_EXTERN cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr); #ifdef __cplusplus diff --git a/pypy/module/cppyy/src/dummy_backend.cxx b/pypy/module/cppyy/src/dummy_backend.cxx --- a/pypy/module/cppyy/src/dummy_backend.cxx +++ b/pypy/module/cppyy/src/dummy_backend.cxx @@ -1,4 +1,3 @@ -#include "src/precommondefs.h" #include "cppyy.h" #include "capi.h" @@ -349,29 +348,24 @@ /* name to opaque C++ scope representation -------------------------------- */ -RPY_EXTERN int cppyy_num_scopes(cppyy_scope_t handle) { return 0; } -RPY_EXTERN char* cppyy_resolve_name(const char* cppitem_name) { return cppstring_to_cstring(cppitem_name); } -RPY_EXTERN cppyy_scope_t cppyy_get_scope(const char* scope_name) { return s_handles[scope_name]; // lookup failure will return 0 (== error) } -RPY_EXTERN cppyy_type_t cppyy_actual_class(cppyy_type_t klass, cppyy_object_t /* obj */) { return klass; } /* memory management ------------------------------------------------------ */ -RPY_EXTERN void cppyy_destruct(cppyy_type_t handle, cppyy_object_t self) { if (handle == s_handles["example01"]) delete (dummy::example01*)self; @@ -379,7 +373,6 @@ /* method/function dispatching -------------------------------------------- */ -RPY_EXTERN void cppyy_call_v(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { long idx = (long)method; if (idx == s_methods["static_example01::staticSetPayload_payload*_double"]) { @@ -469,7 +462,6 @@ } } -RPY_EXTERN unsigned char cppyy_call_b(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { unsigned char result = 0; const long idx = (long)method; @@ -482,7 +474,6 @@ return result; } -RPY_EXTERN char cppyy_call_c(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { char result = 0; const long idx = (long)method; @@ -498,7 +489,6 @@ return result; } -RPY_EXTERN short cppyy_call_h(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { short result = 0; const long idx = (long)method; @@ -514,7 +504,6 @@ return result; } -RPY_EXTERN int cppyy_call_i(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { int result = 0; const long idx = (long)method; @@ -547,7 +536,6 @@ return result; } -RPY_EXTERN long cppyy_call_l(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { long result = 0; const long idx = (long)method; @@ -689,7 +677,6 @@ return result; } -RPY_EXTERN long long cppyy_call_ll(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { long long result = 0; const long idx = (long)method; @@ -705,7 +692,6 @@ return result; } -RPY_EXTERN float cppyy_call_f(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { float result = 0; const long idx = (long)method; @@ -718,7 +704,6 @@ return result; } -RPY_EXTERN double cppyy_call_d(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { double result = 0.; const long idx = (long)method; @@ -740,7 +725,6 @@ return result; } -RPY_EXTERN char* cppyy_call_s(cppyy_method_t method, cppyy_object_t self, int nargs, void* args) { char* result = 0; const long idx = (long)method; @@ -753,7 +737,6 @@ return result; } -RPY_EXTERN cppyy_object_t cppyy_constructor(cppyy_method_t method, cppyy_type_t handle, int nargs, void* args) { void* result = 0; const long idx = (long)method; @@ -776,14 +759,12 @@ return (cppyy_object_t)result; } -RPY_EXTERN cppyy_methptrgetter_t cppyy_get_methptr_getter(cppyy_type_t /* handle */, cppyy_index_t /* method_index */) { return (cppyy_methptrgetter_t)0; } /* handling of function argument buffer ----------------------------------- */ -RPY_EXTERN void* cppyy_allocate_function_args(int nargs) { CPPYY_G__value* args = (CPPYY_G__value*)malloc(nargs*sizeof(CPPYY_G__value)); for (int i = 0; i < nargs; ++i) @@ -793,36 +774,30 @@ /* handling of function argument buffer ----------------------------------- */ -RPY_EXTERN void cppyy_deallocate_function_args(void* args) { free(args); } -RPY_EXTERN size_t cppyy_function_arg_sizeof() { return sizeof(CPPYY_G__value); } -RPY_EXTERN size_t cppyy_function_arg_typeoffset() { return offsetof(CPPYY_G__value, type); } /* scope reflection information ------------------------------------------- */ -RPY_EXTERN int cppyy_is_namespace(cppyy_scope_t /* handle */) { return 0; } -RPY_EXTERN int cppyy_is_enum(const char* /* type_name */) { return 0; } /* class reflection information ------------------------------------------- */ -RPY_EXTERN char* cppyy_final_name(cppyy_type_t handle) { for (Handles_t::iterator isp = s_handles.begin(); isp != s_handles.end(); ++isp) { if (isp->second == handle) @@ -831,75 +806,61 @@ return cppstring_to_cstring(""); } -RPY_EXTERN char* cppyy_scoped_final_name(cppyy_type_t handle) { return cppyy_final_name(handle); } -RPY_EXTERN int cppyy_has_complex_hierarchy(cppyy_type_t /* handle */) { return 0; } -RPY_EXTERN int cppyy_num_bases(cppyy_type_t /*handle*/) { return 0; } /* method/function reflection information --------------------------------- */ -RPY_EXTERN int cppyy_num_methods(cppyy_scope_t handle) { return s_scopes[handle].m_methods.size(); } -RPY_EXTERN cppyy_index_t cppyy_method_index_at(cppyy_scope_t /* scope */, int imeth) { return (cppyy_index_t)imeth; } -RPY_EXTERN char* cppyy_method_name(cppyy_scope_t handle, cppyy_index_t method_index) { return cppstring_to_cstring(s_scopes[handle].m_methods[(int)method_index].m_name); } -RPY_EXTERN char* cppyy_method_result_type(cppyy_scope_t handle, cppyy_index_t method_index) { return cppstring_to_cstring(s_scopes[handle].m_methods[method_index].m_returntype); } -RPY_EXTERN int cppyy_method_num_args(cppyy_scope_t handle, cppyy_index_t method_index) { return s_scopes[handle].m_methods[method_index].m_argtypes.size(); } -RPY_EXTERN int cppyy_method_req_args(cppyy_scope_t handle, cppyy_index_t method_index) { return cppyy_method_num_args(handle, method_index); } -RPY_EXTERN char* cppyy_method_arg_type(cppyy_scope_t handle, cppyy_index_t method_index, int arg_index) { return cppstring_to_cstring(s_scopes[handle].m_methods[method_index].m_argtypes[arg_index]); } -RPY_EXTERN char* cppyy_method_arg_default( cppyy_scope_t /* handle */, cppyy_index_t /* method_index */, int /* arg_index */) { return cppstring_to_cstring(""); } -RPY_EXTERN char* cppyy_method_signature(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */) { return cppstring_to_cstring(""); } -RPY_EXTERN int cppyy_method_is_template(cppyy_scope_t /* handle */, cppyy_index_t /* method_index */) { return 0; } -RPY_EXTERN cppyy_method_t cppyy_get_method(cppyy_scope_t handle, cppyy_index_t method_index) { if (s_scopes.find(handle) != s_scopes.end()) { long id = s_scopes[handle].m_method_offset + (long)method_index; @@ -911,7 +872,6 @@ /* method properties ----------------------------------------------------- */ -RPY_EXTERN int cppyy_is_constructor(cppyy_type_t handle, cppyy_index_t method_index) { if (s_scopes.find(handle) != s_scopes.end()) return s_scopes[handle].m_methods[method_index].m_type == kConstructor; @@ -919,7 +879,6 @@ return 0; } -RPY_EXTERN int cppyy_is_staticmethod(cppyy_type_t handle, cppyy_index_t method_index) { if (s_scopes.find(handle) != s_scopes.end()) return s_scopes[handle].m_methods[method_index].m_type == kStatic; @@ -929,34 +888,28 @@ /* data member reflection information ------------------------------------- */ -RPY_EXTERN int cppyy_num_datamembers(cppyy_scope_t handle) { return s_scopes[handle].m_datambrs.size(); } -RPY_EXTERN char* cppyy_datamember_name(cppyy_scope_t handle, int idatambr) { return cppstring_to_cstring(s_scopes[handle].m_datambrs[idatambr].m_name); } -RPY_EXTERN char* cppyy_datamember_type(cppyy_scope_t handle, int idatambr) { return cppstring_to_cstring(s_scopes[handle].m_datambrs[idatambr].m_type); } -RPY_EXTERN ptrdiff_t cppyy_datamember_offset(cppyy_scope_t handle, int idatambr) { return s_scopes[handle].m_datambrs[idatambr].m_offset; } /* data member properties ------------------------------------------------ */ -RPY_EXTERN int cppyy_is_publicdata(cppyy_scope_t handle, int idatambr) { return 1; } -RPY_EXTERN int cppyy_is_staticdata(cppyy_scope_t handle, int idatambr) { return s_scopes[handle].m_datambrs[idatambr].m_isstatic; } @@ -964,44 +917,37 @@ /* misc helpers ----------------------------------------------------------- */ #if defined(_MSC_VER) -RPY_EXTERN long long cppyy_strtoll(const char* str) { return _strtoi64(str, NULL, 0); } extern "C" { -RPY_EXTERN unsigned long long cppyy_strtoull(const char* str) { return _strtoui64(str, NULL, 0); } } #else -RPY_EXTERN long long cppyy_strtoll(const char* str) { return strtoll(str, NULL, 0); } extern "C" { -RPY_EXTERN unsigned long long cppyy_strtoull(const char* str) { return strtoull(str, NULL, 0); } } #endif -RPY_EXTERN void cppyy_free(void* ptr) { free(ptr); } -RPY_EXTERN cppyy_object_t cppyy_charp2stdstring(const char* str) { void* arena = new char[sizeof(std::string)]; new (arena) std::string(str); return (cppyy_object_t)arena; } -RPY_EXTERN cppyy_object_t cppyy_stdstring2stdstring(cppyy_object_t ptr) { void* arena = new char[sizeof(std::string)]; new (arena) std::string(*(std::string*)ptr); diff --git a/pypy/module/cpyext/src/pythread.c b/pypy/module/cpyext/src/pythread.c --- a/pypy/module/cpyext/src/pythread.c +++ b/pypy/module/cpyext/src/pythread.c @@ -1,11 +1,18 @@ #include +#ifndef _WIN32 +# include +#endif #include "pythread.h" #include "src/thread.h" long PyThread_get_thread_ident(void) { - return RPyThreadGetIdent(); +#ifdef _WIN32 + return (long)GetCurrentThreadId(); +#else + return (long)pthread_self(); +#endif } PyThread_type_lock diff --git a/pypy/module/cpyext/test/conftest.py b/pypy/module/cpyext/test/conftest.py --- a/pypy/module/cpyext/test/conftest.py +++ b/pypy/module/cpyext/test/conftest.py @@ -7,7 +7,7 @@ # it's necessary to run "import time" at least once before any # other cpyext test, otherwise the same statement will fail in # test_datetime.py. - space = gettestobjspace(usemodules=['rctime']) + space = gettestobjspace(usemodules=['time']) space.getbuiltinmodule("time") def pytest_ignore_collect(path, config): diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py --- a/pypy/module/cpyext/test/test_cpyext.py +++ b/pypy/module/cpyext/test/test_cpyext.py @@ -102,7 +102,7 @@ class LeakCheckingTest(object): """Base class for all cpyext tests.""" spaceconfig = dict(usemodules=['cpyext', 'thread', '_rawffi', 'array', - 'itertools', 'rctime', 'binascii', 'micronumpy']) + 'itertools', 'time', 'binascii', 'micronumpy']) spaceconfig['std.withmethodcache'] = True enable_leak_checking = True diff --git a/pypy/module/fcntl/test/test_fcntl.py b/pypy/module/fcntl/test/test_fcntl.py --- a/pypy/module/fcntl/test/test_fcntl.py +++ b/pypy/module/fcntl/test/test_fcntl.py @@ -12,7 +12,7 @@ class AppTestFcntl: spaceconfig = dict(usemodules=('fcntl', 'array', 'struct', 'termios', - 'select', 'rctime')) + 'select', 'time')) def setup_class(cls): tmpprefix = str(udir.ensure('test_fcntl', dir=1).join('tmp_')) diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py --- a/pypy/module/imp/test/test_app.py +++ b/pypy/module/imp/test/test_app.py @@ -4,7 +4,7 @@ class AppTestImpModule: spaceconfig = { - 'usemodules': ['binascii', 'imp', 'itertools', 'rctime', 'struct'], + 'usemodules': ['binascii', 'imp', 'itertools', 'time', 'struct'], } def setup_class(cls): diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py --- a/pypy/module/imp/test/test_import.py +++ b/pypy/module/imp/test/test_import.py @@ -149,7 +149,7 @@ class AppTestImport: spaceconfig = { - "usemodules": ['_md5', 'rctime'], + "usemodules": ['_md5', 'time'], } def setup_class(cls): @@ -1044,7 +1044,7 @@ class AppTestImportHooks(object): spaceconfig = { - "usemodules": ['struct', 'itertools', 'rctime'], + "usemodules": ['struct', 'itertools', 'time'], } def setup_class(cls): @@ -1304,7 +1304,7 @@ class AppTestMultithreadedImp(object): - spaceconfig = dict(usemodules=['thread', 'rctime']) + spaceconfig = dict(usemodules=['thread', 'time']) def setup_class(cls): #if not conftest.option.runappdirect: diff --git a/pypy/module/marshal/interp_marshal.py b/pypy/module/marshal/interp_marshal.py --- a/pypy/module/marshal/interp_marshal.py +++ b/pypy/module/marshal/interp_marshal.py @@ -144,7 +144,6 @@ atom_int(tc, int) puts code and int atom_int64(tc, int64) puts code and int64 atom_str(tc, str) puts code, len and string - atom_strlist(tc, strlist) puts code, len and list of strings building blocks for compound types: @@ -198,15 +197,6 @@ self.atom_int(typecode, len(x)) self.put(x) - def atom_strlist(self, typecode, tc2, x): - self.atom_int(typecode, len(x)) - atom_str = self.atom_str - for item in x: - # type(str) seems to be forbidden - #if type(item) is not str: - # self.raise_exc('object with wrong type in strlist') - atom_str(tc2, item) - def start(self, typecode): # type(char) not supported self.put(typecode) @@ -379,16 +369,6 @@ self.start(typecode) return self.get_lng() - def atom_strlist(self, typecode, tc2): - self.start(typecode) - lng = self.get_lng() - res = [None] * lng - idx = 0 - while idx < lng: - res[idx] = self.atom_str(tc2) - idx += 1 - return res - def start(self, typecode): tc = self.get1() if tc != typecode: @@ -436,7 +416,6 @@ def get_w_obj(self, allow_null=False): space = self.space - w_ret = space.w_None # something not None tc = self.get1() w_ret = self._dispatch[ord(tc)](space, self, tc) if w_ret is None and not allow_null: diff --git a/pypy/module/math/test/test_math.py b/pypy/module/math/test/test_math.py --- a/pypy/module/math/test/test_math.py +++ b/pypy/module/math/test/test_math.py @@ -7,7 +7,7 @@ class AppTestMath: spaceconfig = { - "usemodules": ['math', 'struct', 'itertools', 'rctime', 'binascii'], + "usemodules": ['math', 'struct', 'itertools', 'time', 'binascii'], } def setup_class(cls): diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py --- a/pypy/module/micronumpy/base.py +++ b/pypy/module/micronumpy/base.py @@ -1,7 +1,7 @@ from pypy.interpreter.baseobjspace import W_Root -from pypy.interpreter.error import OperationError +from pypy.interpreter.error import OperationError, oefmt from rpython.tool.pairtype import extendabletype - +from pypy.module.micronumpy import support def wrap_impl(space, w_cls, w_instance, impl): if w_cls is None or space.is_w(w_cls, space.gettypefor(W_NDimArray)): @@ -44,11 +44,32 @@ return W_NDimArray(impl) @staticmethod - def from_shape_and_storage(space, shape, storage, dtype, order='C', owning=False, - w_subtype=None, w_base=None, writable=True): + def from_shape_and_storage(space, shape, storage, dtype, storage_bytes=-1, + order='C', owning=False, w_subtype=None, + w_base=None, writable=True, strides=None): from pypy.module.micronumpy import concrete - from pypy.module.micronumpy.strides import calc_strides - strides, backstrides = calc_strides(shape, dtype, order) + from pypy.module.micronumpy.strides import (calc_strides, + calc_backstrides) + isize = dtype.elsize + if storage_bytes > 0 : + totalsize = support.product(shape) * isize + if totalsize > storage_bytes: + raise OperationError(space.w_TypeError, space.wrap( + "buffer is too small for requested array")) + else: + storage_bytes = support.product(shape) * isize + if strides is None: + strides, backstrides = calc_strides(shape, dtype, order) + else: + if len(strides) != len(shape): + raise oefmt(space.w_ValueError, + 'strides, if given, must be the same length as shape') + for i in range(len(strides)): + if strides[i] < 0 or strides[i]*shape[i] > storage_bytes: + raise oefmt(space.w_ValueError, + 'strides is incompatible with shape of requested ' + 'array and size of buffer') + backstrides = calc_backstrides(strides, shape) if w_base is not None: if owning: raise OperationError(space.w_ValueError, diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py --- a/pypy/module/micronumpy/boxes.py +++ b/pypy/module/micronumpy/boxes.py @@ -59,9 +59,9 @@ _mixin_ = True def reduce(self, space): - numpypy = space.getbuiltinmodule("_numpypy") - assert isinstance(numpypy, MixedModule) - multiarray = numpypy.get("multiarray") + _numpypy = space.getbuiltinmodule("_numpypy") + assert isinstance(_numpypy, MixedModule) + multiarray = _numpypy.get("multiarray") assert isinstance(multiarray, MixedModule) scalar = multiarray.get("scalar") @@ -167,7 +167,7 @@ if len(args_w) >= 1: for w_arg in args_w: try: - idx = support.index_w(space, w_arg) + support.index_w(space, w_arg) except OperationError: raise oefmt(space.w_TypeError, "an integer is required") raise oefmt(space.w_ValueError, "axes don't match array") diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py --- a/pypy/module/micronumpy/compile.py +++ b/pypy/module/micronumpy/compile.py @@ -34,8 +34,8 @@ SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any", - "unegative", "flat", "tostring","count_nonzero", - "argsort"] + "unegative", "flat", "tostring", "count_nonzero", + "argsort", "cumsum", "logical_xor_reduce"] TWO_ARG_FUNCTIONS = ["dot", 'take', 'searchsorted'] TWO_ARG_FUNCTIONS_OR_NONE = ['view', 'astype'] THREE_ARG_FUNCTIONS = ['where'] @@ -559,6 +559,11 @@ w_res = arr.descr_any(interp.space) elif self.name == "all": w_res = arr.descr_all(interp.space) + elif self.name == "cumsum": + w_res = arr.descr_cumsum(interp.space) + elif self.name == "logical_xor_reduce": + logical_xor = ufuncs.get(interp.space).logical_xor + w_res = logical_xor.reduce(interp.space, arr, None) elif self.name == "unegative": neg = ufuncs.get(interp.space).negative w_res = neg.call(interp.space, [arr]) diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py --- a/pypy/module/micronumpy/concrete.py +++ b/pypy/module/micronumpy/concrete.py @@ -11,7 +11,7 @@ from pypy.module.micronumpy.iterators import ArrayIter from pypy.module.micronumpy.strides import (Chunk, Chunks, NewAxisChunk, RecordChunk, calc_strides, calc_new_strides, shape_agreement, - calculate_broadcast_strides) + calculate_broadcast_strides, calc_backstrides) class BaseConcreteArray(object): @@ -47,6 +47,7 @@ def setitem(self, index, value): self.dtype.itemtype.store(self, index, 0, value) + @jit.unroll_safe def setslice(self, space, arr): From noreply at buildbot.pypy.org Tue Dec 9 17:29:56 2014 From: noreply at buildbot.pypy.org (ltratt) Date: Tue, 9 Dec 2014 17:29:56 +0100 (CET) Subject: [pypy-commit] pypy recursion_and_inlining: Close to-be-merged branch. Message-ID: <20141209162956.965E81C09B2@cobra.cs.uni-duesseldorf.de> Author: Laurence Tratt Branch: recursion_and_inlining Changeset: r74868:dcda54278f74 Date: 2014-12-09 16:26 +0000 http://bitbucket.org/pypy/pypy/changeset/dcda54278f74/ Log: Close to-be-merged branch. From noreply at buildbot.pypy.org Tue Dec 9 17:29:57 2014 From: noreply at buildbot.pypy.org (ltratt) Date: Tue, 9 Dec 2014 17:29:57 +0100 (CET) Subject: [pypy-commit] pypy default: Merge recursion_and_inlining. Message-ID: <20141209162957.D13DB1C09B2@cobra.cs.uni-duesseldorf.de> Author: Laurence Tratt Branch: Changeset: r74869:70d88f23b9bb Date: 2014-12-09 16:29 +0000 http://bitbucket.org/pypy/pypy/changeset/70d88f23b9bb/ Log: Merge recursion_and_inlining. This branch stops inlining in recursive function calls after N levels of (posiblly indirect) recursion in a function (where N is configurable; what the best possible value of N might be is still a little unclear, and ideally requires testing on a wider range of benchmarks). This stops us abusing abort as a way of stopping inlining in recursion, and improves performance. diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -964,9 +964,40 @@ assembler_call = False if warmrunnerstate.inlining: if warmrunnerstate.can_inline_callable(greenboxes): + # We've found a potentially inlinable function; now we need to + # see if it's already on the stack. In other words: are we about + # to enter recursion? If so, we don't want to inline the + # recursion, which would be equivalent to unrolling a while + # loop. portal_code = targetjitdriver_sd.mainjitcode - return self.metainterp.perform_call(portal_code, allboxes, - greenkey=greenboxes) + count = 0 + for f in self.metainterp.framestack: + if f.jitcode is not portal_code: + continue + gk = f.greenkey + if gk is None: + continue + assert len(gk) == len(greenboxes) + i = 0 + for i in range(len(gk)): + if not gk[i].same_constant(greenboxes[i]): + break + else: + count += 1 + memmgr = self.metainterp.staticdata.warmrunnerdesc.memory_manager + if count >= memmgr.max_unroll_recursion: + # This function is recursive and has exceeded the + # maximum number of unrollings we allow. We want to stop + # inlining it further and to make sure that, if it + # hasn't happened already, the function is traced + # separately as soon as possible. + if have_debug_prints(): + loc = targetjitdriver_sd.warmstate.get_location_str(greenboxes) + debug_print("recursive function (not inlined):", loc) + warmrunnerstate.dont_trace_here(greenboxes) + else: + return self.metainterp.perform_call(portal_code, allboxes, + greenkey=greenboxes) assembler_call = True # verify that we have all green args, needed to make sure # that assembler that we call is still correct diff --git a/rpython/jit/metainterp/test/test_recursive.py b/rpython/jit/metainterp/test/test_recursive.py --- a/rpython/jit/metainterp/test/test_recursive.py +++ b/rpython/jit/metainterp/test/test_recursive.py @@ -1112,6 +1112,37 @@ assert res == 2095 self.check_resops(call_assembler=12) + def test_inline_recursion_limit(self): + driver = JitDriver(greens = ["threshold", "loop"], reds=["i"]) + @dont_look_inside + def f(): + set_param(driver, "max_unroll_recursion", 10) + def portal(threshold, loop, i): + f() + if i > threshold: + return i + while True: + driver.jit_merge_point(threshold=threshold, loop=loop, i=i) + if loop: + portal(threshold, False, 0) + else: + portal(threshold, False, i + 1) + return i + if i > 10: + return 1 + i += 1 + driver.can_enter_jit(threshold=threshold, loop=loop, i=i) + + res1 = portal(10, True, 0) + res2 = self.meta_interp(portal, [10, True, 0], inline=True) + assert res1 == res2 + self.check_resops(call_assembler=2) + + res1 = portal(9, True, 0) + res2 = self.meta_interp(portal, [9, True, 0], inline=True) + assert res1 == res2 + self.check_resops(call_assembler=0) + def test_handle_jitexception_in_portal(self): # a test for _handle_jitexception_in_portal in blackhole.py driver = JitDriver(greens = ['codeno'], reds = ['i', 'str'], diff --git a/rpython/jit/metainterp/warmspot.py b/rpython/jit/metainterp/warmspot.py --- a/rpython/jit/metainterp/warmspot.py +++ b/rpython/jit/metainterp/warmspot.py @@ -69,7 +69,8 @@ backendopt=False, trace_limit=sys.maxint, inline=False, loop_longevity=0, retrace_limit=5, function_threshold=4, - enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15, **kwds): + enable_opts=ALL_OPTS_NAMES, max_retrace_guards=15, + max_unroll_recursion=7, **kwds): from rpython.config.config import ConfigError translator = interp.typer.annotator.translator try: @@ -91,6 +92,7 @@ jd.warmstate.set_param_retrace_limit(retrace_limit) jd.warmstate.set_param_max_retrace_guards(max_retrace_guards) jd.warmstate.set_param_enable_opts(enable_opts) + jd.warmstate.set_param_max_unroll_recursion(max_unroll_recursion) warmrunnerdesc.finish() if graph_and_interp_only: return interp, graph diff --git a/rpython/jit/metainterp/warmstate.py b/rpython/jit/metainterp/warmstate.py --- a/rpython/jit/metainterp/warmstate.py +++ b/rpython/jit/metainterp/warmstate.py @@ -291,6 +291,11 @@ if self.warmrunnerdesc.memory_manager: self.warmrunnerdesc.memory_manager.max_unroll_loops = value + def set_param_max_unroll_recursion(self, value): + if self.warmrunnerdesc: + if self.warmrunnerdesc.memory_manager: + self.warmrunnerdesc.memory_manager.max_unroll_recursion = value + def disable_noninlinable_function(self, greenkey): cell = self.JitCell.ensure_jit_cell_at_key(greenkey) cell.flags |= JC_DONT_TRACE_HERE @@ -567,19 +572,26 @@ jd = self.jitdriver_sd cpu = self.cpu - def can_inline_greenargs(*greenargs): + def can_inline_callable(greenkey): + greenargs = unwrap_greenkey(greenkey) if can_never_inline(*greenargs): return False cell = JitCell.get_jitcell(*greenargs) if cell is not None and (cell.flags & JC_DONT_TRACE_HERE) != 0: return False return True - def can_inline_callable(greenkey): - greenargs = unwrap_greenkey(greenkey) - return can_inline_greenargs(*greenargs) - self.can_inline_greenargs = can_inline_greenargs self.can_inline_callable = can_inline_callable + def dont_trace_here(greenkey): + # Set greenkey as somewhere that tracing should not occur into; + # notice that, as per the description of JC_DONT_TRACE_HERE earlier, + # if greenkey hasn't been traced separately, setting + # JC_DONT_TRACE_HERE will force tracing the next time the function + # is encountered. + cell = JitCell.ensure_jit_cell_at_key(greenkey) + cell.flags |= JC_DONT_TRACE_HERE + self.dont_trace_here = dont_trace_here + if jd._should_unroll_one_iteration_ptr is None: def should_unroll_one_iteration(greenkey): return False diff --git a/rpython/rlib/jit.py b/rpython/rlib/jit.py --- a/rpython/rlib/jit.py +++ b/rpython/rlib/jit.py @@ -463,6 +463,7 @@ 'max_unroll_loops': 'number of extra unrollings a loop can cause', 'enable_opts': 'INTERNAL USE ONLY (MAY NOT WORK OR LEAD TO CRASHES): ' 'optimizations to enable, or all = %s' % ENABLE_ALL_OPTS, + 'max_unroll_recursion': 'how many levels deep to unroll a recursive function' } PARAMETERS = {'threshold': 1039, # just above 1024, prime @@ -476,6 +477,7 @@ 'max_retrace_guards': 15, 'max_unroll_loops': 0, 'enable_opts': 'all', + 'max_unroll_recursion': 7, } unroll_parameters = unrolling_iterable(PARAMETERS.items()) From noreply at buildbot.pypy.org Tue Dec 9 17:30:58 2014 From: noreply at buildbot.pypy.org (vext01) Date: Tue, 9 Dec 2014 17:30:58 +0100 (CET) Subject: [pypy-commit] benchmarks min_5_secs: Ensure that all benchmarks run for at least 5 secs on a fast machine. Message-ID: <20141209163058.F38451C09B2@cobra.cs.uni-duesseldorf.de> Author: Edd Barrett Branch: min_5_secs Changeset: r285:507b827a733d Date: 2014-12-09 16:31 +0000 http://bitbucket.org/pypy/benchmarks/changeset/507b827a733d/ Log: Ensure that all benchmarks run for at least 5 secs on a fast machine. (I actually aimed for 5<=t<=6, but some are more) Note that some benchmarks (spitfire, twisted) do not report how long an iteration took, but rather how many of x happened in t seconds. So the output may not necessarily be >=5 secs. diff --git a/lib/pypy/rpython/translator/c/src/signals.o b/lib/pypy/rpython/translator/c/src/signals.o index 166016f96874014a34535131bd7cfed3aabe09eb..978377c7573fccb667802c8cb75d56c1a1ce01b9 GIT binary patch [cut] diff --git a/lib/pypy/rpython/translator/c/src/stacklet/stacklet.o b/lib/pypy/rpython/translator/c/src/stacklet/stacklet.o index e42497399f1f975b42e62fbf236498014c21f654..f9610bf7b82769ca1eeeac7f2eca92de8d120802 GIT binary patch [cut] diff --git a/lib/pypy/rpython/translator/c/src/thread.o b/lib/pypy/rpython/translator/c/src/thread.o index 9b7dcc7cb6e9c6eb94216acf121fbcd5b32297e5..a0f49075af33414be1dca504e743a537a7f175f6 GIT binary patch [cut] diff --git a/own/bm_chameleon.py b/own/bm_chameleon.py --- a/own/bm_chameleon.py +++ b/own/bm_chameleon.py @@ -13,15 +13,20 @@ """ +INNER_ITERS = 500 + def main(n): tmpl = PageTemplate(BIGTABLE_ZPT) options = {'table': [dict(a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8, i=9, j=10) for x in range(1000)]} import time l = [] - for k in range(n): + for k in xrange(n): t0 = time.time() - tmpl(options=options) + + for i in xrange(INNER_ITERS): + tmpl(options=options) + l.append(time.time() - t0) return l diff --git a/own/bm_dulwich_log.py b/own/bm_dulwich_log.py --- a/own/bm_dulwich_log.py +++ b/own/bm_dulwich_log.py @@ -4,13 +4,18 @@ import dulwich.repo +INNER_ITERS = 50 + def test_dulwich(n): l = [] r = dulwich.repo.Repo(os.path.join(os.path.dirname(__file__), 'git-demo')) import time - for i in range(20): + for i in xrange(n): t0 = time.time() - r.revision_history(r.head()) + + for j in xrange(INNER_ITERS): + r.revision_history(r.head()) + l.append(time.time() - t0) return l diff --git a/own/bm_genshi.py b/own/bm_genshi.py --- a/own/bm_genshi.py +++ b/own/bm_genshi.py @@ -22,21 +22,31 @@ """ - def main(n, bench): tmpl_cls, tmpl_str = { 'xml': (MarkupTemplate, BIGTABLE_XML), 'text': (NewTextTemplate, BIGTABLE_TEXT), }[bench] + + if bench == "text": + inner_iters = 620 + elif bench == "xml": + inner_iters = 220 + else: + assert(False) + tmpl = tmpl_cls(tmpl_str) context = {'table': [dict(a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8, i=9, j=10) for x in range(1000)]} l = [] - for k in range(n): + for k in xrange(n): t0 = time.time() - stream = tmpl.generate(**context) - stream.render() + + for i in xrange(inner_iters): + stream = tmpl.generate(**context) + stream.render() + l.append(time.time() - t0) return l diff --git a/own/bm_mako.py b/own/bm_mako.py --- a/own/bm_mako.py +++ b/own/bm_mako.py @@ -120,6 +120,7 @@ ${fun6()} """ +INNER_ITERS = 550 def test_mako(count): @@ -128,7 +129,7 @@ lookup.put_string('page.mako', PAGE_TEMPLATE) template = Template(CONTENT_TEMPLATE, lookup=lookup) - + table = [xrange(150) for i in xrange(150)] paragraphs = xrange(50) title = 'Hello world!' @@ -136,9 +137,11 @@ times = [] for i in range(count): t0 = time.time() - data = template.render(table=table, paragraphs=paragraphs, - lorem=LOREM_IPSUM, title=title, - img_count=50) + + for j in xrange(INNER_ITERS): + data = template.render(table=table, paragraphs=paragraphs, + lorem=LOREM_IPSUM, title=title, + img_count=50) t1 = time.time() times.append(t1-t0) return times diff --git a/own/bm_sympy.py b/own/bm_sympy.py --- a/own/bm_sympy.py +++ b/own/bm_sympy.py @@ -20,13 +20,25 @@ x, y, z = symbols('x y z') str(expand((x+2*y+3*z)**30)) +INNER_ITERS_D = { + 'expand' : 650000, + 'integrate' : 10, + 'str' : 500, + 'sum' : 500, +} + def main(n, bench): + + inner_iters = INNER_ITERS_D.get(bench, 1) func = globals()['bench_' + bench] l = [] for i in range(n): clear_cache() t0 = time.time() - func() + + for j in xrange(inner_iters): + func() + l.append(time.time() - t0) return l diff --git a/own/chaos.py b/own/chaos.py --- a/own/chaos.py +++ b/own/chaos.py @@ -13,6 +13,8 @@ import sys import time +INNER_ITERS = 5000 * 1300 + class GVector(object): def __init__(self, x = 0, y = 0, z = 0): self.x = x @@ -219,9 +221,9 @@ (self.maxy + self.miny) / 2, 0) colored = 0 times = [] - for _ in range(n): + for _ in xrange(n): t1 = time.time() - for i in xrange(5000): + for i in xrange(INNER_ITERS): point = self.transform_point(point) x = (point.x - self.minx) / self.width * w y = (point.y - self.miny) / self.height * h diff --git a/own/crypto_pyaes.py b/own/crypto_pyaes.py --- a/own/crypto_pyaes.py +++ b/own/crypto_pyaes.py @@ -22,13 +22,18 @@ assert plaintext == cleartext +INNER_ITERS = 197 + def main(arg): # XXX warmup times = [] for i in xrange(arg): t0 = time.time() - o = benchmark() + + for j in xrange(INNER_ITERS): + o = benchmark() + tk = time.time() times.append(tk - t0) return times diff --git a/own/deltablue.py b/own/deltablue.py --- a/own/deltablue.py +++ b/own/deltablue.py @@ -614,15 +614,19 @@ chain_test(100) projection_test(100) +INNER_ITERS = 17000 # Specific to the PyPy implementation, to run within the main harnass. def main(n): import time times = [] - for i in range(n): + for i in xrange(n): t1 = time.time() - delta_blue() + + for j in xrange(INNER_ITERS): + delta_blue() + t2 = time.time() times.append(t2 - t1) diff --git a/own/eparse.py b/own/eparse.py --- a/own/eparse.py +++ b/own/eparse.py @@ -4,13 +4,18 @@ ometa.FAST = True from monte.eparser import EParser +INNER_ITERS = 24 + def main(n): l = [] data = open(os.path.join(os.path.dirname(__file__), 'test.e')).read() for _ in range(n): t0 = time.time() - p = EParser(data) - v, e = p.apply('start') + + for i in xrange(INNER_ITERS): + p = EParser(data) + v, e = p.apply('start') + l.append(time.time() - t0) return l diff --git a/own/fannkuch.py b/own/fannkuch.py --- a/own/fannkuch.py +++ b/own/fannkuch.py @@ -52,15 +52,20 @@ DEFAULT_ARG = 9 +INNER_ITERS = 60 + def main(n): times = [] - for i in range(n): + for i in xrange(n): t0 = time.time() - fannkuch(DEFAULT_ARG) + + for j in xrange(INNER_ITERS): + fannkuch(DEFAULT_ARG) + tk = time.time() times.append(tk - t0) return times - + if __name__ == "__main__": parser = optparse.OptionParser( usage="%prog [options]", diff --git a/own/float.py b/own/float.py --- a/own/float.py +++ b/own/float.py @@ -47,17 +47,22 @@ POINTS = 100000 +INNER_ITERS = 240 + def main(arg): # XXX warmup - + times = [] for i in xrange(arg): t0 = time.time() - o = benchmark(POINTS) + + for j in xrange(INNER_ITERS): + o = benchmark(POINTS) + tk = time.time() times.append(tk - t0) return times - + if __name__ == "__main__": parser = optparse.OptionParser( usage="%prog [options]", diff --git a/own/go.py b/own/go.py --- a/own/go.py +++ b/own/go.py @@ -423,13 +423,18 @@ board = Board() pos = computer_move(board) +INNER_ITERS = 89 + def main(n): times = [] - for i in range(5): + for i in xrange(5): versus_cpu() # warmup - for i in range(n): + for i in xrange(n): t1 = time.time() - versus_cpu() + + for j in xrange(INNER_ITERS): + versus_cpu() + t2 = time.time() times.append(t2 - t1) return times diff --git a/own/json_bench.py b/own/json_bench.py --- a/own/json_bench.py +++ b/own/json_bench.py @@ -11,14 +11,20 @@ cases = ['EMPTY', 'SIMPLE', 'NESTED', 'HUGE'] +INNER_ITERS = 13 + def main(n): l = [] - for i in range(n): + for i in xrange(n): t0 = time.time() - for case in cases: - data, count = globals()[case] - for i in range(count): - json.dumps(data) + + for m in xrange(INNER_ITERS): + + for case in cases: + data, count = globals()[case] + for i in range(count): + json.dumps(data) + l.append(time.time() - t0) return l diff --git a/own/meteor-contest.py b/own/meteor-contest.py --- a/own/meteor-contest.py +++ b/own/meteor-contest.py @@ -135,21 +135,25 @@ SOLVE_ARG = 60 +INNER_ITERS = 92 + def main(n): times = [] - for i in range(n): + for i in xrange(n): + t0 = time.time() - free = frozenset(xrange(len(board))) - curr_board = [-1] * len(board) - pieces_left = range(len(pieces)) - solutions = [] - solve(SOLVE_ARG, 0, free, curr_board, pieces_left, solutions) - #print len(solutions), 'solutions found\n' - #for i in (0, -1): print_board(solutions[i]) - tk = time.time() + for j in xrange(INNER_ITERS): + free = frozenset(xrange(len(board))) + curr_board = [-1] * len(board) + pieces_left = range(len(pieces)) + solutions = [] + solve(SOLVE_ARG, 0, free, curr_board, pieces_left, solutions) + #print len(solutions), 'solutions found\n' + #for i in (0, -1): print_board(solutions[i]) + tk = time.time() times.append(tk - t0) return times - + if __name__ == "__main__": parser = optparse.OptionParser( usage="%prog [options]", diff --git a/own/nbody_modified.py b/own/nbody_modified.py --- a/own/nbody_modified.py +++ b/own/nbody_modified.py @@ -109,17 +109,22 @@ NUMBER_OF_ITERATIONS = 20000 +INNER_ITERATIONS = 290 + def main(n, ref='sun'): # XXX warmup - + times = [] - for i in range(n): + for i in xrange(n): t0 = time.time() - offset_momentum(BODIES[ref]) - report_energy() - advance(0.01, NUMBER_OF_ITERATIONS) - report_energy() - tk = time.time() + + for j in xrange(INNER_ITERATIONS): + offset_momentum(BODIES[ref]) + report_energy() + advance(0.01, NUMBER_OF_ITERATIONS) + report_energy() + tk = time.time() + times.append(tk - t0) return times diff --git a/own/pyflate-fast.py b/own/pyflate-fast.py --- a/own/pyflate-fast.py +++ b/own/pyflate-fast.py @@ -660,6 +660,8 @@ assert md5.md5(out).hexdigest() == "afa004a630fe072901b1d9628b960974" input.close() +INNER_ITERS = 26 + def main(n): import time times = [] @@ -667,7 +669,10 @@ _main() # warmup for i in range(n): t1 = time.time() - _main() + + for j in xrange(INNER_ITERS): + _main() + t2 = time.time() times.append(t2 - t1) return times diff --git a/own/raytrace-simple.py b/own/raytrace-simple.py --- a/own/raytrace-simple.py +++ b/own/raytrace-simple.py @@ -353,6 +353,8 @@ s.addObject(Halfspace(Point(0,0,0), Vector.UP), CheckerboardSurface()) s.render(c) +INNER_ITERS = 300 + def main(n): import time times = [] @@ -360,7 +362,10 @@ _main() # warmup for i in range(n): t1 = time.time() - _main() + + for j in xrange(INNER_ITERS): + _main() + t2 = time.time() times.append(t2 - t1) return times diff --git a/own/spectral-norm.py b/own/spectral-norm.py --- a/own/spectral-norm.py +++ b/own/spectral-norm.py @@ -42,25 +42,30 @@ DEFAULT_N = 130 +INNER_ITERS = 600 + def main(n): times = [] - for i in range(n): + for i in xrange(n): t0 = time.time() - u = [1] * DEFAULT_N - for dummy in xrange (10): - v = eval_AtA_times_u (u) - u = eval_AtA_times_u (v) + for j in xrange(INNER_ITERS): + u = [1] * DEFAULT_N - vBv = vv = 0 + for dummy in xrange (10): + v = eval_AtA_times_u (u) + u = eval_AtA_times_u (v) - for ue, ve in izip (u, v): - vBv += ue * ve - vv += ve * ve + vBv = vv = 0 + + for ue, ve in izip (u, v): + vBv += ue * ve + vv += ve * ve + tk = time.time() times.append(tk - t0) return times - + if __name__ == "__main__": parser = optparse.OptionParser( usage="%prog [options]", diff --git a/own/spitfire.py b/own/spitfire.py --- a/own/spitfire.py +++ b/own/spitfire.py @@ -21,11 +21,17 @@ # bummer, timeit module is stupid from bigtable import test_python_cstringio, test_spitfire_o4, test_spitfire +INNER_ITERS_D = { + "python_cstringio" : 12000, + "spitfire_o4" : 4000, +} + def runtest(n, benchmark): times = [] + inner_iters = INNER_ITERS_D.get(benchmark, 100) for i in range(n): sys.stdout = StringIO() - bigtable.run([benchmark], 100) + bigtable.run([benchmark], inner_iters) times.append(float(sys.stdout.getvalue().split(" ")[-2])) sys.stdout = sys.__stdout__ return times diff --git a/own/telco.py b/own/telco.py --- a/own/telco.py +++ b/own/telco.py @@ -75,11 +75,16 @@ end = time() return end - start +INNER_ITERS = 450 + def main(n): run() # warmup times = [] for i in range(n): - times.append(run()) + all_inner_runs = 0.0 + for j in xrange(INNER_ITERS): + all_inner_runs += run() + times.append(all_inner_runs) return times diff --git a/unladen_swallow/perf.py b/unladen_swallow/perf.py --- a/unladen_swallow/perf.py +++ b/unladen_swallow/perf.py @@ -809,7 +809,7 @@ if options.rigorous: trials = 100 elif options.fast: - trials = 5 + trials = 1 # XXX trials = max(1, int(trials * iteration_scaling)) RemovePycs() diff --git a/unladen_swallow/performance/bm_ai.py b/unladen_swallow/performance/bm_ai.py --- a/unladen_swallow/performance/bm_ai.py +++ b/unladen_swallow/performance/bm_ai.py @@ -69,6 +69,7 @@ yield vec +INNER_ITERS = 230 def test_n_queens(iterations): # Warm-up runs. list(n_queens(8)) @@ -77,7 +78,10 @@ times = [] for _ in xrange(iterations): t0 = time.time() - list(n_queens(8)) + + for i in xrange(INNER_ITERS): + list(n_queens(8)) + t1 = time.time() times.append(t1 - t0) return times diff --git a/unladen_swallow/performance/bm_django.py b/unladen_swallow/performance/bm_django.py --- a/unladen_swallow/performance/bm_django.py +++ b/unladen_swallow/performance/bm_django.py @@ -32,6 +32,7 @@ """) +INNER_ITERS = 300 def test_django(count): table = [xrange(150) for _ in xrange(150)] context = Context({"table": table}) @@ -43,7 +44,10 @@ times = [] for _ in xrange(count): t0 = time.time() - data = DJANGO_TMPL.render(context) + + for i in xrange(INNER_ITERS): + data = DJANGO_TMPL.render(context) + t1 = time.time() times.append(t1 - t0) return times diff --git a/unladen_swallow/performance/bm_html5lib.py b/unladen_swallow/performance/bm_html5lib.py --- a/unladen_swallow/performance/bm_html5lib.py +++ b/unladen_swallow/performance/bm_html5lib.py @@ -23,6 +23,8 @@ import html5lib +INNER_ITERS = 4 + def test_html5lib(count, spec_data): # No warm-up runs for this benchmark; in real life, the parser doesn't get # to warm up (this isn't a daemon process). @@ -31,7 +33,10 @@ for _ in xrange(count): spec_data.seek(0) t0 = time.time() - html5lib.parse(spec_data) + + for i in xrange(INNER_ITERS): + html5lib.parse(spec_data) + t1 = time.time() times.append(t1 - t0) return times diff --git a/unladen_swallow/performance/bm_richards.py b/unladen_swallow/performance/bm_richards.py --- a/unladen_swallow/performance/bm_richards.py +++ b/unladen_swallow/performance/bm_richards.py @@ -18,6 +18,8 @@ import util +INNER_ITERS = 2750 + def test_richards(iterations): # Warm-up r = richards.Richards() @@ -26,7 +28,7 @@ times = [] for _ in xrange(iterations): t0 = time.time() - r.run(iterations=1) + r.run(iterations=INNER_ITERS) t1 = time.time() times.append(t1 - t0) return times diff --git a/unladen_swallow/performance/bm_rietveld.py b/unladen_swallow/performance/bm_rietveld.py --- a/unladen_swallow/performance/bm_rietveld.py +++ b/unladen_swallow/performance/bm_rietveld.py @@ -86,6 +86,7 @@ tmpl = loader.get_template(templ_name) return tmpl, context +INNER_ITERS = 46 def test_rietveld(count, tmpl, context): # Warm up Django. @@ -95,37 +96,40 @@ times = [] for _ in xrange(count): t0 = time.time() - # 30 calls to render, so that we don't measure loop overhead. - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) + + for i in xrange(INNER_ITERS): + # 30 calls to render, so that we don't measure loop overhead. + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + tmpl.render(context) + t1 = time.time() times.append(t1 - t0) return times diff --git a/unladen_swallow/performance/bm_spambayes.py b/unladen_swallow/performance/bm_spambayes.py --- a/unladen_swallow/performance/bm_spambayes.py +++ b/unladen_swallow/performance/bm_spambayes.py @@ -20,6 +20,7 @@ # Local imports import util +INNER_ITERS = 150 def test_spambayes(iterations, messages, ham_classifier): # Prime the pump. This still leaves some hot functions uncompiled; these @@ -30,8 +31,9 @@ times = [] for _ in xrange(iterations): t0 = time.time() - for msg in messages: - ham_classifier.score(msg) + for i in xrange(INNER_ITERS): + for msg in messages: + ham_classifier.score(msg) t1 = time.time() times.append(t1 - t0) return times diff --git a/unladen_swallow/performance/bm_spitfire.py b/unladen_swallow/performance/bm_spitfire.py --- a/unladen_swallow/performance/bm_spitfire.py +++ b/unladen_swallow/performance/bm_spitfire.py @@ -40,6 +40,8 @@ """ +INNER_ITERS = 31 + def test_spitfire(count): # Activate the most aggressive Spitfire optimizations. While it might # conceivably be interesting to stress Spitfire's lower optimization @@ -60,7 +62,10 @@ times = [] for _ in xrange(count): t0 = time.time() - data = spitfire_tmpl_o4(search_list=[{"table": table}]).main() + + for i in xrange(INNER_ITERS): + data = spitfire_tmpl_o4(search_list=[{"table": table}]).main() + t1 = time.time() times.append(t1 - t0) return times From noreply at buildbot.pypy.org Tue Dec 9 17:40:25 2014 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 9 Dec 2014 17:40:25 +0100 (CET) Subject: [pypy-commit] benchmarks default: Uh, don't check in the .o files Message-ID: <20141209164025.DD2D41C0936@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r286:680e6f36aa42 Date: 2014-12-09 16:40 +0000 http://bitbucket.org/pypy/benchmarks/changeset/680e6f36aa42/ Log: Uh, don't check in the .o files diff --git a/lib/pypy/rpython/translator/c/src/signals.o b/lib/pypy/rpython/translator/c/src/signals.o deleted file mode 100644 Binary file lib/pypy/rpython/translator/c/src/signals.o has changed diff --git a/lib/pypy/rpython/translator/c/src/stacklet/stacklet.o b/lib/pypy/rpython/translator/c/src/stacklet/stacklet.o deleted file mode 100644 Binary file lib/pypy/rpython/translator/c/src/stacklet/stacklet.o has changed diff --git a/lib/pypy/rpython/translator/c/src/thread.o b/lib/pypy/rpython/translator/c/src/thread.o deleted file mode 100644 Binary file lib/pypy/rpython/translator/c/src/thread.o has changed From noreply at buildbot.pypy.org Tue Dec 9 17:40:27 2014 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 9 Dec 2014 17:40:27 +0100 (CET) Subject: [pypy-commit] benchmarks min_5_secs: don't check in the .o files Message-ID: <20141209164027.53E501C0936@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: min_5_secs Changeset: r287:4f82cc579716 Date: 2014-12-09 16:40 +0000 http://bitbucket.org/pypy/benchmarks/changeset/4f82cc579716/ Log: don't check in the .o files diff --git a/lib/pypy/rpython/translator/c/src/signals.o b/lib/pypy/rpython/translator/c/src/signals.o deleted file mode 100644 Binary file lib/pypy/rpython/translator/c/src/signals.o has changed diff --git a/lib/pypy/rpython/translator/c/src/stacklet/stacklet.o b/lib/pypy/rpython/translator/c/src/stacklet/stacklet.o deleted file mode 100644 Binary file lib/pypy/rpython/translator/c/src/stacklet/stacklet.o has changed diff --git a/lib/pypy/rpython/translator/c/src/thread.o b/lib/pypy/rpython/translator/c/src/thread.o deleted file mode 100644 Binary file lib/pypy/rpython/translator/c/src/thread.o has changed From noreply at buildbot.pypy.org Tue Dec 9 17:49:30 2014 From: noreply at buildbot.pypy.org (vext01) Date: Tue, 9 Dec 2014 17:49:30 +0100 (CET) Subject: [pypy-commit] benchmarks min_5_secs: Put back --fast to 5 iterations. Message-ID: <20141209164930.0E7511D22D0@cobra.cs.uni-duesseldorf.de> Author: Edd Barrett Branch: min_5_secs Changeset: r288:3926c2bd88df Date: 2014-12-09 16:47 +0000 http://bitbucket.org/pypy/benchmarks/changeset/3926c2bd88df/ Log: Put back --fast to 5 iterations. diff --git a/unladen_swallow/perf.py b/unladen_swallow/perf.py --- a/unladen_swallow/perf.py +++ b/unladen_swallow/perf.py @@ -809,7 +809,7 @@ if options.rigorous: trials = 100 elif options.fast: - trials = 1 # XXX + trials = 5 trials = max(1, int(trials * iteration_scaling)) RemovePycs() From noreply at buildbot.pypy.org Tue Dec 9 17:49:31 2014 From: noreply at buildbot.pypy.org (vext01) Date: Tue, 9 Dec 2014 17:49:31 +0100 (CET) Subject: [pypy-commit] benchmarks min_5_secs: merge Message-ID: <20141209164931.7026E1D22D0@cobra.cs.uni-duesseldorf.de> Author: Edd Barrett Branch: min_5_secs Changeset: r289:8c2f3584ae9a Date: 2014-12-09 16:49 +0000 http://bitbucket.org/pypy/benchmarks/changeset/8c2f3584ae9a/ Log: merge diff --git a/lib/pypy/rpython/translator/c/src/signals.o b/lib/pypy/rpython/translator/c/src/signals.o deleted file mode 100644 Binary file lib/pypy/rpython/translator/c/src/signals.o has changed diff --git a/lib/pypy/rpython/translator/c/src/stacklet/stacklet.o b/lib/pypy/rpython/translator/c/src/stacklet/stacklet.o deleted file mode 100644 Binary file lib/pypy/rpython/translator/c/src/stacklet/stacklet.o has changed diff --git a/lib/pypy/rpython/translator/c/src/thread.o b/lib/pypy/rpython/translator/c/src/thread.o deleted file mode 100644 Binary file lib/pypy/rpython/translator/c/src/thread.o has changed From noreply at buildbot.pypy.org Tue Dec 9 17:52:49 2014 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 9 Dec 2014 17:52:49 +0100 (CET) Subject: [pypy-commit] benchmarks min_5_secs: (cfbolz, arigo) Message-ID: <20141209165249.A62591C09B2@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: min_5_secs Changeset: r290:7acb20388ca1 Date: 2014-12-09 16:53 +0000 http://bitbucket.org/pypy/benchmarks/changeset/7acb20388ca1/ Log: (cfbolz, arigo) Un-unroll that loop diff --git a/unladen_swallow/performance/bm_rietveld.py b/unladen_swallow/performance/bm_rietveld.py --- a/unladen_swallow/performance/bm_rietveld.py +++ b/unladen_swallow/performance/bm_rietveld.py @@ -86,7 +86,7 @@ tmpl = loader.get_template(templ_name) return tmpl, context -INNER_ITERS = 46 +INNER_ITERS = 46 * 30 def test_rietveld(count, tmpl, context): # Warm up Django. @@ -98,36 +98,6 @@ t0 = time.time() for i in xrange(INNER_ITERS): - # 30 calls to render, so that we don't measure loop overhead. - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) - tmpl.render(context) tmpl.render(context) t1 = time.time() From noreply at buildbot.pypy.org Tue Dec 9 18:00:08 2014 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 9 Dec 2014 18:00:08 +0100 (CET) Subject: [pypy-commit] pypy default: (cfbolz, arigo) Message-ID: <20141209170008.4DE431D37CE@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r74870:d5298ea685c7 Date: 2014-12-09 16:59 +0000 http://bitbucket.org/pypy/pypy/changeset/d5298ea685c7/ Log: (cfbolz, arigo) Clarify what error we get from calling getattr() with 3 args in RPython diff --git a/rpython/flowspace/operation.py b/rpython/flowspace/operation.py --- a/rpython/flowspace/operation.py +++ b/rpython/flowspace/operation.py @@ -528,6 +528,10 @@ pyfunc = staticmethod(getattr) def constfold(self): + from rpython.flowspace.flowcontext import FlowingError + if len(self.args) == 3: + raise FlowingError( + "getattr() with three arguments not supported: %s" % (self,)) w_obj, w_name = self.args # handling special things like sys if (w_obj in NOT_REALLY_CONST and @@ -538,7 +542,6 @@ try: result = getattr(obj, name) except Exception as e: - from rpython.flowspace.flowcontext import FlowingError etype = e.__class__ msg = "getattr(%s, %s) always raises %s: %s" % ( obj, name, etype, e) From noreply at buildbot.pypy.org Tue Dec 9 18:59:55 2014 From: noreply at buildbot.pypy.org (cfbolz) Date: Tue, 9 Dec 2014 18:59:55 +0100 (CET) Subject: [pypy-commit] benchmarks default: (arigo, cfbolz) Message-ID: <20141209175955.6301A1D236C@cobra.cs.uni-duesseldorf.de> Author: Carl Friedrich Bolz Branch: Changeset: r291:ded8521a022d Date: 2014-12-09 18:00 +0000 http://bitbucket.org/pypy/benchmarks/changeset/ded8521a022d/ Log: (arigo, cfbolz) add a pypy_interp benchmark that runs a loop in the pypy interpreter diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -82,7 +82,7 @@ 'spectral-norm', 'chaos', 'telco', 'go', 'pyflate-fast', 'raytrace-simple', 'crypto_pyaes', 'bm_mako', 'bm_chameleon', 'json_bench', 'pidigits', 'hexiom2', 'eparse', 'deltablue', - 'bm_dulwich_log', 'bm_krakatau', 'bm_mdp']: + 'bm_dulwich_log', 'bm_krakatau', 'bm_mdp', 'pypy_interp']: _register_new_bm(name, name, globals(), **opts.get(name, {})) for name in ['names', 'iteration', 'tcp', 'pb', ]:#'web']:#, 'accepts']: diff --git a/own/pypy_interp.py b/own/pypy_interp.py new file mode 100644 --- /dev/null +++ b/own/pypy_interp.py @@ -0,0 +1,45 @@ +import sys, os, cStringIO +import time +import util, optparse + +pardir = os.path.dirname(os.path.abspath(os.path.dirname(__file__))) +pypypath = os.path.join(pardir, 'lib', 'pypy') +sys.path.insert(0, pypypath) + +from pypy.tool.pytest.objspace import gettestobjspace + +def bench(space): + w_l = space.appexec([], """(): + class A(object): + def __init__(self, x): + self.x = x + glob_a = A(1) + l = [] + a, b = 1, 1 + for i in range(100): + l.append((i, a, str(i), float(i), {i: a}, A(b), glob_a.x)) + a, b = b, a + b + return l + """) + +def main(n): + l = [] + space = gettestobjspace() + # warmup + bench(space) + bench(space) + for i in range(n): + t0 = time.time() + bench(space) + time_elapsed = time.time() - t0 + l.append(time_elapsed) + return l + +if __name__ == "__main__": + parser = optparse.OptionParser( + usage="%prog [options]", + description="Test the performance of the pypy-interp benchmark") + util.add_standard_options_to(parser) + options, args = parser.parse_args() + + util.run_benchmark(options, options.num_runs, main) From noreply at buildbot.pypy.org Tue Dec 9 19:35:02 2014 From: noreply at buildbot.pypy.org (arigo) Date: Tue, 9 Dec 2014 19:35:02 +0100 (CET) Subject: [pypy-commit] pypy default: Test get_errno() and get_last_error() here Message-ID: <20141209183502.3806D1C09B2@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r74871:05a286a4b5e0 Date: 2014-12-09 18:34 +0000 http://bitbucket.org/pypy/pypy/changeset/05a286a4b5e0/ Log: Test get_errno() and get_last_error() here diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py --- a/pypy/module/_rawffi/test/test__rawffi.py +++ b/pypy/module/_rawffi/test/test__rawffi.py @@ -16,6 +16,7 @@ #include "src/precommondefs.h" #include #include + #include struct x { @@ -204,6 +205,24 @@ return inp; } + RPY_EXPORTED + int check_errno(int incoming) + { + int old_errno = errno; + errno = incoming; + return old_errno; + } + + #ifdef _WIN32 + #include + RPY_EXPORTED + int check_last_error(int incoming) + { + int old_errno = GetLastError(); + SetLastError(incoming); + return old_errno; + } + #endif ''')) eci = ExternalCompilationInfo(include_dirs=[cdir]) return str(platform.compile([c_file], eci, 'x', standalone=False)) @@ -1150,6 +1169,37 @@ raises(OverflowError, "arg1[0] = 10**900") arg1.free() + def test_errno(self): + import _rawffi + lib = _rawffi.CDLL(self.lib_name) + A = _rawffi.Array('i') + f = lib.ptr('check_errno', ['i'], 'i') + _rawffi.set_errno(42) + arg = A(1) + arg[0] = 43 + res = f(arg) + assert res[0] == 42 + z = _rawffi.get_errno() + assert z == 43 + arg.free() + + def test_last_error(self): + import sys + if sys.platform != 'win32': + skip("Windows test") + import _rawffi + lib = _rawffi.CDLL(self.lib_name) + A = _rawffi.Array('i') + f = lib.ptr('check_last_error', ['i'], 'i') + _rawffi.set_last_error(42) + arg = A(1) + arg[0] = 43 + res = f(arg) + assert res[0] == 42 + z = _rawffi.get_last_error() + assert z == 43 + arg.free() + class AppTestAutoFree: spaceconfig = dict(usemodules=['_rawffi', 'struct']) From noreply at buildbot.pypy.org Wed Dec 10 00:01:24 2014 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 10 Dec 2014 00:01:24 +0100 (CET) Subject: [pypy-commit] pypy default: Attempt to fix issue #1944 Message-ID: <20141209230124.67F321D236C@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r74872:e4a49ff75f6d Date: 2014-12-09 23:01 +0000 http://bitbucket.org/pypy/pypy/changeset/e4a49ff75f6d/ Log: Attempt to fix issue #1944 diff --git a/pypy/module/_rawffi/alt/interp_funcptr.py b/pypy/module/_rawffi/alt/interp_funcptr.py --- a/pypy/module/_rawffi/alt/interp_funcptr.py +++ b/pypy/module/_rawffi/alt/interp_funcptr.py @@ -14,6 +14,7 @@ from rpython.rlib.objectmodel import we_are_translated from pypy.module._rawffi.alt.type_converter import FromAppLevelConverter, ToAppLevelConverter from pypy.module._rawffi.interp_rawffi import got_libffi_error, wrap_dlopenerror +from pypy.module._rawffi import lasterror import os if os.name == 'nt': @@ -201,11 +202,23 @@ self.func = func self.argchain = argchain + def before(self): + lasterror.restore_last_error(self.space) + + def after(self): + lasterror.save_last_error(self.space) + def get_longlong(self, w_ffitype): - return self.func.call(self.argchain, rffi.LONGLONG) + self.before() + x = self.func.call(self.argchain, rffi.LONGLONG) + self.after() + return x def get_ulonglong(self, w_ffitype): - return self.func.call(self.argchain, rffi.ULONGLONG) + self.before() + x = self.func.call(self.argchain, rffi.ULONGLONG) + self.after() + return x def get_signed(self, w_ffitype): # if the declared return type of the function is smaller than LONG, @@ -216,64 +229,94 @@ # to space.wrap in order to get a nice applevel . # restype = w_ffitype.get_ffitype() + self.before() call = self.func.call if restype is libffi.types.slong: - return call(self.argchain, rffi.LONG) + x = call(self.argchain, rffi.LONG) elif restype is libffi.types.sint: - return rffi.cast(rffi.LONG, call(self.argchain, rffi.INT)) + x = rffi.cast(rffi.LONG, call(self.argchain, rffi.INT)) elif restype is libffi.types.sshort: - return rffi.cast(rffi.LONG, call(self.argchain, rffi.SHORT)) + x = rffi.cast(rffi.LONG, call(self.argchain, rffi.SHORT)) elif restype is libffi.types.schar: - return rffi.cast(rffi.LONG, call(self.argchain, rffi.SIGNEDCHAR)) + x = rffi.cast(rffi.LONG, call(self.argchain, rffi.SIGNEDCHAR)) else: - self.error(w_ffitype) + raise self.error(w_ffitype) + self.after() + return x def get_unsigned(self, w_ffitype): - return self.func.call(self.argchain, rffi.ULONG) + self.before() + x = self.func.call(self.argchain, rffi.ULONG) + self.after() + return x def get_unsigned_which_fits_into_a_signed(self, w_ffitype): # the same comment as get_signed apply restype = w_ffitype.get_ffitype() + self.before() call = self.func.call if restype is libffi.types.uint: assert not libffi.IS_32_BIT # on 32bit machines, we should never get here, because it's a case # which has already been handled by get_unsigned above. - return rffi.cast(rffi.LONG, call(self.argchain, rffi.UINT)) + x = rffi.cast(rffi.LONG, call(self.argchain, rffi.UINT)) elif restype is libffi.types.ushort: - return rffi.cast(rffi.LONG, call(self.argchain, rffi.USHORT)) + x = rffi.cast(rffi.LONG, call(self.argchain, rffi.USHORT)) elif restype is libffi.types.uchar: - return rffi.cast(rffi.LONG, call(self.argchain, rffi.UCHAR)) + x = rffi.cast(rffi.LONG, call(self.argchain, rffi.UCHAR)) else: - self.error(w_ffitype) + raise self.error(w_ffitype) + self.after() + return x def get_pointer(self, w_ffitype): + self.before() ptrres = self.func.call(self.argchain, rffi.VOIDP) + self.after() return rffi.cast(rffi.ULONG, ptrres) def get_char(self, w_ffitype): - return self.func.call(self.argchain, rffi.UCHAR) + self.before() + x = self.func.call(self.argchain, rffi.UCHAR) + self.after() + return x def get_unichar(self, w_ffitype): - return self.func.call(self.argchain, rffi.WCHAR_T) + self.before() + x = self.func.call(self.argchain, rffi.WCHAR_T) + self.after() + return x def get_float(self, w_ffitype): - return self.func.call(self.argchain, rffi.DOUBLE) + self.before() + x = self.func.call(self.argchain, rffi.DOUBLE) + self.after() + return x def get_singlefloat(self, w_ffitype): - return self.func.call(self.argchain, rffi.FLOAT) + self.before() + x = self.func.call(self.argchain, rffi.FLOAT) + self.after() + return x def get_struct(self, w_ffitype, w_structdescr): + self.before() addr = self.func.call(self.argchain, rffi.LONG, is_struct=True) + self.after() return w_structdescr.fromaddress(self.space, addr) def get_struct_rawffi(self, w_ffitype, w_structdescr): + self.before() uintval = self.func.call(self.argchain, rffi.ULONG, is_struct=True) + self.after() return w_structdescr.fromaddress(self.space, uintval) def get_void(self, w_ffitype): - return self.func.call(self.argchain, lltype.Void) + self.before() + x = self.func.call(self.argchain, lltype.Void) + self.after() + return x def unpack_argtypes(space, w_argtypes, w_restype): diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -18,6 +18,7 @@ from rpython.rlib.rarithmetic import intmask, r_uint from pypy.module._rawffi.buffer import RawFFIBuffer from pypy.module._rawffi.tracker import tracker +from pypy.module._rawffi import lasterror TYPEMAP = { # XXX A mess with unsigned/signed/normal chars :-/ @@ -495,10 +496,14 @@ try: if self.resshape is not None: result = self.resshape.allocate(space, 1, autofree=True) + lasterror.restore_last_error(space) self.ptr.call(args_ll, result.ll_buffer) + lasterror.save_last_error(space) return space.wrap(result) else: + lasterror.restore_last_error(space) self.ptr.call(args_ll, lltype.nullptr(rffi.VOIDP.TO)) + lasterror.save_last_error(space) return space.w_None except StackCheckError, e: raise OperationError(space.w_ValueError, space.wrap(e.message)) From noreply at buildbot.pypy.org Wed Dec 10 00:02:46 2014 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 10 Dec 2014 00:02:46 +0100 (CET) Subject: [pypy-commit] pypy default: add missing file Message-ID: <20141209230246.9B3B51D28EE@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r74873:33de11afa62a Date: 2014-12-09 23:02 +0000 http://bitbucket.org/pypy/pypy/changeset/33de11afa62a/ Log: add missing file diff --git a/pypy/module/_rawffi/lasterror.py b/pypy/module/_rawffi/lasterror.py new file mode 100644 --- /dev/null +++ b/pypy/module/_rawffi/lasterror.py @@ -0,0 +1,32 @@ +# For Windows only. +# https://bitbucket.org/pypy/pypy/issue/1944/ctypes-on-windows-getlasterror + +import os + +_MS_WINDOWS = os.name == "nt" + + +if _MS_WINDOWS: + from rpython.rlib import rwin32 + from pypy.interpreter.executioncontext import Executioncontext + + + ExecutionContext._rawffi_last_error = 0 + + def restore_last_error(space): + ec = space.getexecutioncontext() + lasterror = ec._rawffi_last_error + rwin32.SetLastError(lasterror) + + def save_last_error(space): + lasterror = rwin32.GetLastError() + ec = space.getexecutioncontext() + ec._rawffi_last_error = lasterror + +else: + + def restore_last_error(space): + pass + + def save_last_error(space): + pass From noreply at buildbot.pypy.org Wed Dec 10 00:17:31 2014 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 10 Dec 2014 00:17:31 +0100 (CET) Subject: [pypy-commit] pypy default: fixes Message-ID: <20141209231731.251F21C09B2@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r74874:99234fd4cade Date: 2014-12-09 23:17 +0000 http://bitbucket.org/pypy/pypy/changeset/99234fd4cade/ Log: fixes diff --git a/pypy/module/_rawffi/interp_rawffi.py b/pypy/module/_rawffi/interp_rawffi.py --- a/pypy/module/_rawffi/interp_rawffi.py +++ b/pypy/module/_rawffi/interp_rawffi.py @@ -620,12 +620,10 @@ if sys.platform == 'win32': def get_last_error(space): - from rpython.rlib.rwin32 import GetLastError - return space.wrap(GetLastError()) + return space.wrap(lasterror.fetch_last_error(space)) @unwrap_spec(error=int) def set_last_error(space, error): - from rpython.rlib.rwin32 import SetLastError - SetLastError(error) + lasterror.store_last_error(space, error) else: # always have at least a dummy version of these functions # (https://bugs.pypy.org/issue1242) diff --git a/pypy/module/_rawffi/lasterror.py b/pypy/module/_rawffi/lasterror.py --- a/pypy/module/_rawffi/lasterror.py +++ b/pypy/module/_rawffi/lasterror.py @@ -8,11 +8,19 @@ if _MS_WINDOWS: from rpython.rlib import rwin32 - from pypy.interpreter.executioncontext import Executioncontext + from pypy.interpreter.executioncontext import ExecutionContext ExecutionContext._rawffi_last_error = 0 + def fetch_last_error(space): + ec = space.getexecutioncontext() + return ec._rawffi_last_error + + def store_last_error(space, last_error): + ec = space.getexecutioncontext() + ec._rawffi_last_error = last_error + def restore_last_error(space): ec = space.getexecutioncontext() lasterror = ec._rawffi_last_error From noreply at buildbot.pypy.org Wed Dec 10 01:16:49 2014 From: noreply at buildbot.pypy.org (antocuni) Date: Wed, 10 Dec 2014 01:16:49 +0100 (CET) Subject: [pypy-commit] pypy vmprof: make sure that the overridden PyFrame.execute_frame is seen before we start translation Message-ID: <20141210001649.087F51C09B2@cobra.cs.uni-duesseldorf.de> Author: Antonio Cuni Branch: vmprof Changeset: r74875:794e9137937b Date: 2014-12-10 00:16 +0000 http://bitbucket.org/pypy/pypy/changeset/794e9137937b/ Log: make sure that the overridden PyFrame.execute_frame is seen before we start translation diff --git a/pypy/module/_vmprof/__init__.py b/pypy/module/_vmprof/__init__.py --- a/pypy/module/_vmprof/__init__.py +++ b/pypy/module/_vmprof/__init__.py @@ -12,3 +12,7 @@ 'enable': 'interp_vmprof.enable', 'disable': 'interp_vmprof.disable', } + + def setup_after_space_initialization(self): + # force the __extend__ hacks to occur early + import pypy.module._vmprof.interp_vmprof From noreply at buildbot.pypy.org Wed Dec 10 10:26:58 2014 From: noreply at buildbot.pypy.org (arigo) Date: Wed, 10 Dec 2014 10:26:58 +0100 (CET) Subject: [pypy-commit] benchmarks default: Add ICBD as a benchmark. This comes from Kevin Modzelewski on pypy-dev. Message-ID: <20141210092658.58C541D3816@cobra.cs.uni-duesseldorf.de> Author: Armin Rigo Branch: Changeset: r292:67706c915134 Date: 2014-12-10 09:15 +0000 http://bitbucket.org/pypy/benchmarks/changeset/67706c915134/ Log: Add ICBD as a benchmark. This comes from Kevin Modzelewski on pypy- dev. diff too long, truncating to 2000 out of 90238 lines diff --git a/benchmarks.py b/benchmarks.py --- a/benchmarks.py +++ b/benchmarks.py @@ -82,7 +82,8 @@ 'spectral-norm', 'chaos', 'telco', 'go', 'pyflate-fast', 'raytrace-simple', 'crypto_pyaes', 'bm_mako', 'bm_chameleon', 'json_bench', 'pidigits', 'hexiom2', 'eparse', 'deltablue', - 'bm_dulwich_log', 'bm_krakatau', 'bm_mdp', 'pypy_interp']: + 'bm_dulwich_log', 'bm_krakatau', 'bm_mdp', 'pypy_interp', + 'bm_icbd']: _register_new_bm(name, name, globals(), **opts.get(name, {})) for name in ['names', 'iteration', 'tcp', 'pb', ]:#'web']:#, 'accepts']: diff --git a/own/bm_icbd.py b/own/bm_icbd.py new file mode 100644 --- /dev/null +++ b/own/bm_icbd.py @@ -0,0 +1,35 @@ +import sys, os, subprocess, time +this_dir = os.path.abspath(os.path.dirname(__file__)) + +def main(n): + # HAAAAAACK with subprocess because I can't get the thing + # to run in-process :-( As a result, it doesn't make + # sense to run it more than once. + + d = os.environ.copy() + d['PYTHONPATH'] = 'icbd' + t0 = time.time() + popen = subprocess.Popen( + [sys.executable, + '-m', 'icbd.type_analyzer.analyze_all', + '-I', 'stdlib/python2.5_tiny', + '-I', '.', + '-E', 'icbd/type_analyzer/tests', + '-E', 'icbd/compiler/benchmarks', + '-E', 'icbd/compiler/tests', + '-I', 'stdlib/type_mocks', + '-n', + 'icbd'], cwd=this_dir, env=d, stdout=subprocess.PIPE) + popen.communicate() + time_elapsed = time.time() - t0 + return [time_elapsed] * n + +if __name__ == "__main__": + import util, optparse + parser = optparse.OptionParser( + usage="%prog [options]", + description="Test the performance of the ICBD benchmark") + util.add_standard_options_to(parser) + options, args = parser.parse_args() + + util.run_benchmark(options, options.num_runs, main) diff --git a/own/icbd/.gitignore b/own/icbd/.gitignore new file mode 100644 --- /dev/null +++ b/own/icbd/.gitignore @@ -0,0 +1,24 @@ +*.pyc +*.d +*.sw? +*.out +*.out[0-9] +*.o +*.s +*.s[0-9] +*.gen.bc +*.gen.c +*.comb.ll +*.gen.ll +*opt.ll +*.so +icbd/compiler/tests/[0-9] +icbd/compiler/tests/[0-9][0-9] +icbd/compiler/tests/*.hpp +icbd/compiler/tests/*[0-9].cpp +icbd/compiler/tests/Makefile +*.shed +*.ppm +icbd/compiler/dist +*.pyicbd +*.pyd diff --git a/own/icbd/LICENSE b/own/icbd/LICENSE new file mode 100644 --- /dev/null +++ b/own/icbd/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014, Kevin Modzelewski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/own/icbd/README.md b/own/icbd/README.md new file mode 100644 --- /dev/null +++ b/own/icbd/README.md @@ -0,0 +1,109 @@ +# icbd + +> ICBD is a defunct project, but I'm releasing the source code in case any one is interested. + +ICBD is a static type analyzer and static compiler for Python. It originated +from the desire at Dropbox to have additional type information for our growing +codebases, without requiring programmers to add type annotations. There are +other static type analyzers for Python out there; the goal of ICBD was to +produce one that would work well on the Dropbox codebase, which meant +concretely: + +- Handling untypable code as gracefully as possible +- "Acceptable" running times for multi-100k LOC codebases +- A plugin system for handling code that is inherently not statically analyzable + +These goals were somewhat met, perhaps to the limits of using whole-program type +inference; the running time for the Dropbox codebase was about 15 minutes, which +I believe is better than alternatives but is not good enough for easy use. + +The plugin system was able to get anecdotally get ICBD to successfully analyze a +sufficient fraction of the Dropbox codebase, though when typing failed, it was +difficult to tell why. + +### Testing it out + +You need to install pygments and simplejson to run ICBD; once you do, run + +``` +bash icbd/type_analyzer/run.sh icbd +``` + +to have ICBD analyze its own codebase (it doesn't do particularly well since +there are no plugins for its getattr usage). You can see the output at +file:///tmp/icbd_icbd/icbd/type_analyzer/type_checker.html + +### Technical approach + +ICBD treats every Python expression as a constraint on the allowable types of +the program: `a = o.x` encodes the constraint that "a will have the type of o's +x attribute", `f(x)` encodes the constaint that "f accepts a type argument of +type type(x)", etc. At a high level, ICBD then does a graph fixed-point +analysis to determine a set of types that satisfy the constraints, and emits +errors when types could not be found (ex: `a, b, c = 1, 2`). + +The guessed types start at the BOTTOM type, and ICBD iteratively finds +unsatisfied constraints and raises the involved types to attempt to satisfy the +constraints. In theory, if ICBD always raises types monotonically and to the +minimum satisfying type, this process will converge on a deterministic set of +lowest (or in some sense, most descriptive) types. + +In practice, this is somewhat harder because the type constraints are dependent +on other types -- for example, attribute lookup dependencies can change based on +learning that an attribute may actually be a instance attribute. This doesn't +seem to be that big a deal, though. + +### Comparison to Python type analyzers + +ICBD only analyzes a single version of each function, and assumes that any +combination of seen argument types could occur together. For example, in this +snippet: + +```python +def add_int_or_str(a, b): + return a + b + +add_int_or_str(1, 2) +add_int_or_str("hello ", "world") +``` + +ICBD will report an error, saying that an int cannot be added to a string. +Other analyzers will notice that add_int_or_str does not actually receive an +(int, str) combination of arguments and handle this correctly, but at an +exponentially-large cost. + +This means that ICBD does not handle polymorphic functions very gracefully, +but in practice this seems to net be a common thing for applications code, and +the plugin system makes it possible to handle on a one-off basis. + +#### Quick note about HM + +People often ask "why don't you just apply HM (Hindley-Milner) which computes +the types ideally". Yes, it's true that HM has some nice ideality properties, +but it only applies to a fairly-restrictive type system. I'm not a type +theorist, but my understanding is that to properly represent the Python type +system you need + +- Dependent types to represent attributes, and +- Rank-n polymorphism to represent global variables + +both of which I believe make the inference problem undecidable. (Is there +really any Haskell program that uses 0 type annotations?) + +Of course in theory it's possible to translate Python code into, for example, +Haskell, but I don't see any reason to believe this can be done in an automated +way such that the generated Haskell has any meaningful relation to the original +Python. For example, one could build an X86 emulator in Haskell, and use that +to run the Python interpreter, but the types on the Haskell program have no +usefulness to the original Python programmer. + +# Compiler + +ICBD also includes a static compiler, in icbd/compiler. Assuming that the type +analyzer can come up with a complete set of types for your program (a big +assumption), in theory it should be possible to compile the Python as if it were +a more traditionally-typed static language. + +In practice I doubt that real code can really be 100% typed; the ICBD compiler +served as the starting point for the [Pyston](https://github.com/dropbox/pyston) +project, which replaces it. diff --git a/own/icbd/demos/demo.py b/own/icbd/demos/demo.py new file mode 100644 --- /dev/null +++ b/own/icbd/demos/demo.py @@ -0,0 +1,291 @@ +if 0: + "" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + # Basic type analysis: + a = 2 + b = '3' + d = {a:b} + ch = ord(b[2].lower()[0]) + print ch + + + + + + + + + + + + + + + + + + + + # Name errors: + ch *= e + + + + + + + + + + + + + + + + + + + + # Nested-type manipulation: + d = {1:[1], 3:[4]} + d[1].append(2) + + l = [range(i) for i in xrange(5)] + l.append([-1]) + l2 = [k[0] for k in l] + l2.append(1) + + + + + + + + + + + + + + + + + + + + + + + # Function type inference: + def func(x, y): + return b * (x + y) + r = func(3, 4) + + + + + + + + + + + + + + + + + # Higher-level types: + def f(x): + def g(): + return x + return g + + inner = f(2) + print f(1)() + inner() + + + + + + + + + + + + + + + + + # Control-flow analysis: + if inner(): + x = 3 + else: + x = [0] + print l2[x] + + def fib(x): + if x <= 1: + return x + return fib(x-1) + fib(x-2) + fib(2) + + + + + + + + + + + + + + def foo(): + return foo() + if 0: + x = 0 + else: + x = foo() + print x + + + + + + + + + + + + + + + + + # Classes: + class C(object): + def __init__(self, x): + self.x = x + def bar(self, z): + return self.x * z + def baz(self, k): + return k**2 + + c = C(2) + c.baz(3) + + + + + + + + + + + # attributes + print c.x + z = c.bar(3) + c.y = 3 + z = c.x * c.y + z *= c.z + + + + + + + + + + + + + + + + + + # Complex type analysis: + def f1(x): + def g(y): + return x * y + return g + + a = f1('') + b = a(2) + + def f2(x): + def g(y): + return x * y + return g + + a = f2(1) + b = a(2) + + + + + + + "" diff --git a/own/icbd/demos/demo_compact.py b/own/icbd/demos/demo_compact.py new file mode 100644 --- /dev/null +++ b/own/icbd/demos/demo_compact.py @@ -0,0 +1,105 @@ +# Basic type analysis: +a = 2 +b = '3' +d = {a:b} +c = ord(b[2].lower()[0]) +print c + + +# Name errors: +c *= e + +# Nested-type manipulation: +d = {1:[1], 3:[4]} +d[1].append(2) + +l = [range(i) for i in xrange(5)] +l.append([-1]) +l2 = [k[0] for k in l] +l2.append(1) + + +# Argument-type checking, based on inferred types +l2.append('') + + + +# Function type inference: +def f(x, y): + return b * (x + y) +r = f(3, 4) + + + +# Higher-level types: +def f(x): + def g(): + return x + return g + +f1 = f(2) +print f(1)() + f1() + + + + +# Control-flow analysis: +if f1(): + x = 3 +else: + x = [0] +print l2[x] + +def fib(x): + if x <= 1: + return x + return fib(x-1) + fib(x-2) +fib(2) + + +def foo(): + return foo() +if 0: + x = 0 +else: + x = foo() +print x + + +# Classes: +class Foo(object): + def __init__(self, x): + self.x = x + def bar(self, z): + return self.x * z + def baz(self, k): + return k**2 + +f = Foo(2) +f.baz(3) + +# attributes +print f.x +z = f.bar(3) +f.y = 3 +z = f.x * f.y +z *= f.z + + +# Complex type analysis: +def f1(x): + def g(y): + return x * y + return g + +a = f1('') +b = a(2) + +def f2(x): + def g(y): + return x * y + return g + +a = f2(1) +b = a(2) + diff --git a/own/icbd/demos/ray.html b/own/icbd/demos/ray.html new file mode 100644 --- /dev/null +++ b/own/icbd/demos/ray.html @@ -0,0 +1,15385 @@ + + + + + + Emscripten-Generated Code + + + +
+
Downloading...
+ +
+
+
+ +
+ +