Author: Richard Plangger <planri...@gmail.com>
Branch: vecopt-merge
Changeset: r80229:04ab6b2dc6ff
Date: 2015-10-15 09:33 +0200
http://bitbucket.org/pypy/pypy/changeset/04ab6b2dc6ff/

Log:    merged default

diff too long, truncating to 2000 out of 2228 lines

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
@@ -75,7 +75,13 @@
 remain valid as long as the target exists (unlike the previous
 version, where handles become invalid *before* the __del__ is called).
 
+.. branch: ufunc-casting
+
+allow automatic casting in ufuncs (and frompypyfunc) to cast the
+arguments to the allowed function type declarations, fixes various
+failures in linalg cffi functions
+
 .. branch: vecopt
 .. branch: vecopt-merge
 
-A new optimization pass to use SIMD instructions for trace loop that allow this
+A new optimization pass to use emit vectorized loops
diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -66,6 +66,7 @@
 import pypy.module.cpyext.codecs
 import pypy.module.cpyext.pyfile
 import pypy.module.cpyext.pystrtod
+import pypy.module.cpyext.pytraceback
 
 # now that all rffi_platform.Struct types are registered, configure them
 api.configure_types()
diff --git a/pypy/module/cpyext/include/Python.h 
b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -126,6 +126,7 @@
 #include "fileobject.h"
 #include "pysignals.h"
 #include "pythread.h"
+#include "traceback.h"
 
 /* Missing definitions */
 #include "missing.h"
diff --git a/pypy/module/cpyext/include/frameobject.h 
b/pypy/module/cpyext/include/frameobject.h
--- a/pypy/module/cpyext/include/frameobject.h
+++ b/pypy/module/cpyext/include/frameobject.h
@@ -4,7 +4,7 @@
 extern "C" {
 #endif
 
-typedef struct {
+typedef struct _frame {
     PyObject_HEAD
     PyCodeObject *f_code;
     PyObject *f_globals;
diff --git a/pypy/module/cpyext/include/traceback.h 
b/pypy/module/cpyext/include/traceback.h
--- a/pypy/module/cpyext/include/traceback.h
+++ b/pypy/module/cpyext/include/traceback.h
@@ -4,7 +4,15 @@
 extern "C" {
 #endif
 
-typedef PyObject PyTracebackObject;
+struct _frame;
+
+typedef struct _traceback {
+        PyObject_HEAD
+        struct _traceback *tb_next;
+        struct _frame *tb_frame;
+        int tb_lasti;
+        int tb_lineno;
+} PyTracebackObject;
 
 #ifdef __cplusplus
 }
diff --git a/pypy/module/cpyext/pytraceback.py 
b/pypy/module/cpyext/pytraceback.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/pytraceback.py
@@ -0,0 +1,50 @@
+from rpython.rtyper.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import (
+    PyObjectFields, generic_cpy_call, CONST_STRING, CANNOT_FAIL, Py_ssize_t,
+    cpython_api, bootstrap_function, cpython_struct, build_type_checkers)
+from pypy.module.cpyext.pyobject import (
+    PyObject, make_ref, from_ref, Py_DecRef, make_typedescr, borrow_from)
+from pypy.module.cpyext.frameobject import PyFrameObject
+from rpython.rlib.unroll import unrolling_iterable
+from pypy.interpreter.error import OperationError
+from pypy.interpreter.pytraceback import PyTraceback
+from pypy.interpreter import pycode
+
+
+PyTracebackObjectStruct = lltype.ForwardReference()
+PyTracebackObject = lltype.Ptr(PyTracebackObjectStruct)
+PyTracebackObjectFields = PyObjectFields + (
+    ("tb_next", PyTracebackObject),
+    ("tb_frame", PyFrameObject),
+    ("tb_lasti", rffi.INT),
+    ("tb_lineno", rffi.INT),
+)
+cpython_struct("PyTracebackObject", PyTracebackObjectFields, 
PyTracebackObjectStruct)
+
+@bootstrap_function
+def init_traceback(space):
+    make_typedescr(PyTraceback.typedef,
+                   basestruct=PyTracebackObject.TO,
+                   attach=traceback_attach,
+                   dealloc=traceback_dealloc)
+
+
+def traceback_attach(space, py_obj, w_obj):
+    py_traceback = rffi.cast(PyTracebackObject, py_obj)
+    traceback = space.interp_w(PyTraceback, w_obj)
+    if traceback.next is None:
+        w_next_traceback = None
+    else:
+        w_next_traceback = space.wrap(traceback.next)
+    py_traceback.c_tb_next = rffi.cast(PyTracebackObject, make_ref(space, 
w_next_traceback))
+    py_traceback.c_tb_frame = rffi.cast(PyFrameObject, make_ref(space, 
space.wrap(traceback.frame)))
+    rffi.setintfield(py_traceback, 'c_tb_lasti', traceback.lasti)
+    rffi.setintfield(py_traceback, 'c_tb_lineno',traceback.get_lineno())
+
+@cpython_api([PyObject], lltype.Void, external=False)
+def traceback_dealloc(space, py_obj):
+    py_traceback = rffi.cast(PyTracebackObject, py_obj)
+    Py_DecRef(space, rffi.cast(PyObject, py_traceback.c_tb_next))
+    Py_DecRef(space, rffi.cast(PyObject, py_traceback.c_tb_frame))
+    from pypy.module.cpyext.object import PyObject_dealloc
+    PyObject_dealloc(space, py_obj)
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -61,6 +61,30 @@
     args_w = space.fixedview(w_args)
     return generic_cpy_call(space, func_binary, w_self, args_w[0])
 
+def wrap_binaryfunc_l(space, w_self, w_args, func):
+    func_binary = rffi.cast(binaryfunc, func)
+    check_num_args(space, w_args, 1)
+    args_w = space.fixedview(w_args)
+
+    if not space.is_true(space.issubtype(space.type(args_w[0]),
+                                         space.type(w_self))):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            "NotImplemented"))
+ 
+    return generic_cpy_call(space, func_binary, w_self, args_w[0])
+
+def wrap_binaryfunc_r(space, w_self, w_args, func):
+    func_binary = rffi.cast(binaryfunc, func)
+    check_num_args(space, w_args, 1)
+    args_w = space.fixedview(w_args)
+
+    if not space.is_true(space.issubtype(space.type(args_w[0]),
+                                         space.type(w_self))):
+        raise OperationError(space.w_NotImplementedError, space.wrap(
+            "NotImplemented"))
+
+    return generic_cpy_call(space, func_binary, args_w[0], w_self)
+
 def wrap_inquirypred(space, w_self, w_args, func):
     func_inquiry = rffi.cast(inquiry, func)
     check_num_args(space, w_args, 0)
diff --git a/pypy/module/cpyext/test/test_traceback.py 
b/pypy/module/cpyext/test/test_traceback.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_traceback.py
@@ -0,0 +1,40 @@
+from rpython.rtyper.lltypesystem import lltype, rffi
+from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref
+from pypy.module.cpyext.pytraceback import PyTracebackObject
+from pypy.interpreter.pytraceback import PyTraceback
+from pypy.interpreter.pyframe import PyFrame
+
+class TestPyTracebackObject(BaseApiTest):
+    def test_traceback(self, space, api):
+        w_traceback = space.appexec([], """():
+            import sys
+            try:
+                1/0
+            except:
+                return sys.exc_info()[2]
+        """)
+        py_obj = make_ref(space, w_traceback)
+        py_traceback = rffi.cast(PyTracebackObject, py_obj)
+        assert (from_ref(space, rffi.cast(PyObject, py_traceback.c_ob_type)) is
+                space.gettypeobject(PyTraceback.typedef))
+
+        traceback = space.interp_w(PyTraceback, w_traceback)
+        assert traceback.lasti == py_traceback.c_tb_lasti
+        assert traceback.get_lineno() == py_traceback.c_tb_lineno
+        assert space.eq_w(space.getattr(w_traceback, space.wrap("tb_lasti")),
+                          space.wrap(py_traceback.c_tb_lasti))
+        assert space.is_w(space.getattr(w_traceback, space.wrap("tb_frame")),
+                          from_ref(space, rffi.cast(PyObject,
+                                                    py_traceback.c_tb_frame)))
+
+        while not space.is_w(w_traceback, space.w_None):
+            assert space.is_w(
+                w_traceback,
+                from_ref(space, rffi.cast(PyObject, py_traceback)))
+            w_traceback = space.getattr(w_traceback, space.wrap("tb_next"))
+            py_traceback = py_traceback.c_tb_next
+
+        assert lltype.normalizeptr(py_traceback) is None
+
+        api.Py_DecRef(py_obj)
diff --git a/pypy/module/cpyext/test/test_typeobject.py 
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -589,6 +589,48 @@
         assert bool(module.newInt(-1))
         raises(ValueError, bool, module.newInt(-42))
 
+    def test_binaryfunc(self):
+        module = self.import_extension('foo', [
+            ("new_obj", "METH_NOARGS",
+             """
+                FooObject *fooObj;
+
+                Foo_Type.tp_as_number = &foo_as_number;
+                foo_as_number.nb_add = foo_nb_add_call;
+                if (PyType_Ready(&Foo_Type) < 0) return NULL;
+                fooObj = PyObject_New(FooObject, &Foo_Type);
+                if (!fooObj) {
+                    return NULL;
+                }
+
+                return (PyObject *)fooObj;
+             """)],
+            """
+            typedef struct
+            {
+                PyObject_HEAD
+            } FooObject;
+
+            static PyObject * 
+            foo_nb_add_call(PyObject *self, PyObject *other)
+            {
+                return PyInt_FromLong(42); 
+            }
+
+            PyTypeObject Foo_Type = {
+                PyObject_HEAD_INIT(0)
+                /*ob_size*/             0,
+                /*tp_name*/             "Foo",
+                /*tp_basicsize*/        sizeof(FooObject),
+            };
+            static PyNumberMethods foo_as_number;
+            """)
+        a = module.new_obj()
+        b = module.new_obj() 
+        c = 3
+        assert (a + b) == 42 
+        raises(NotImplementedError, "b + c")
+
     def test_tp_new_in_subclass_of_type(self):
         skip("BROKEN")
         module = self.import_module(name='foo3')
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
@@ -70,7 +70,10 @@
 
     @jit.unroll_safe
     def setslice(self, space, arr):
-        if len(arr.get_shape()) >  len(self.get_shape()):
+        if arr.get_size() == 1:
+            # we can always set self[:] = scalar
+            pass
+        elif len(arr.get_shape()) >  len(self.get_shape()):
             # record arrays get one extra dimension
             if not self.dtype.is_record() or \
                     len(arr.get_shape()) > len(self.get_shape()) + 1:
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
@@ -161,10 +161,10 @@
 
 call_many_to_one_driver = jit.JitDriver(
     name='numpy_call_many_to_one',
-    greens=['shapelen', 'nin', 'func', 'res_dtype'],
+    greens=['shapelen', 'nin', 'func', 'in_dtypes', 'res_dtype'],
     reds='auto')
 
-def call_many_to_one(space, shape, func, res_dtype, in_args, out):
+def call_many_to_one(space, shape, func, in_dtypes, res_dtype, in_args, out):
     # out must hav been built. func needs no calc_type, is usually an
     # external ufunc
     nin = len(in_args)
@@ -182,9 +182,9 @@
     vals = [None] * nin
     while not out_iter.done(out_state):
         call_many_to_one_driver.jit_merge_point(shapelen=shapelen, func=func,
-                                     res_dtype=res_dtype, nin=nin)
+                        in_dtypes=in_dtypes, res_dtype=res_dtype, nin=nin)
         for i in range(nin):
-            vals[i] = in_iters[i].getitem(in_states[i])
+            vals[i] = in_dtypes[i].coerce(space, 
in_iters[i].getitem(in_states[i]))
         w_arglist = space.newlist(vals)
         w_out_val = space.call_args(func, Arguments.frompacked(space, 
w_arglist))
         out_iter.setitem(out_state, res_dtype.coerce(space, w_out_val))
@@ -195,10 +195,10 @@
 
 call_many_to_many_driver = jit.JitDriver(
     name='numpy_call_many_to_many',
-    greens=['shapelen', 'nin', 'nout', 'func', 'res_dtype'],
+    greens=['shapelen', 'nin', 'nout', 'func', 'in_dtypes', 'out_dtypes'],
     reds='auto')
 
-def call_many_to_many(space, shape, func, res_dtype, in_args, out_args):
+def call_many_to_many(space, shape, func, in_dtypes, out_dtypes, in_args, 
out_args):
     # out must hav been built. func needs no calc_type, is usually an
     # external ufunc
     nin = len(in_args)
@@ -221,24 +221,29 @@
         out_states[i] = out_state
     shapelen = len(shape)
     vals = [None] * nin
-    while not out_iters[0].done(out_states[0]):
+    test_iter, test_state = in_iters[-1], in_states[-1]
+    if nout > 0:
+        test_iter, test_state = out_iters[0], out_states[0]
+    while not test_iter.done(test_state):
         call_many_to_many_driver.jit_merge_point(shapelen=shapelen, func=func,
-                                     res_dtype=res_dtype, nin=nin, nout=nout)
+                             in_dtypes=in_dtypes, out_dtypes=out_dtypes,
+                             nin=nin, nout=nout)
         for i in range(nin):
-            vals[i] = in_iters[i].getitem(in_states[i])
+            vals[i] = in_dtypes[i].coerce(space, 
in_iters[i].getitem(in_states[i]))
         w_arglist = space.newlist(vals)
         w_outvals = space.call_args(func, Arguments.frompacked(space, 
w_arglist))
         # w_outvals should be a tuple, but func can return a single value as 
well 
         if space.isinstance_w(w_outvals, space.w_tuple):
             batch = space.listview(w_outvals)
             for i in range(len(batch)):
-                out_iters[i].setitem(out_states[i], res_dtype.coerce(space, 
batch[i]))
+                out_iters[i].setitem(out_states[i], 
out_dtypes[i].coerce(space, batch[i]))
                 out_states[i] = out_iters[i].next(out_states[i])
-        else:
-            out_iters[0].setitem(out_states[0], res_dtype.coerce(space, 
w_outvals))
+        elif nout > 0:
+            out_iters[0].setitem(out_states[0], out_dtypes[0].coerce(space, 
w_outvals))
             out_states[0] = out_iters[0].next(out_states[0])
         for i in range(nin):
             in_states[i] = in_iters[i].next(in_states[i])
+        test_state = test_iter.next(test_state)
     return space.newtuple([convert_to_array(space, o) for o in out_args])
 
 setslice_driver = jit.JitDriver(name='numpy_setslice',
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
@@ -159,8 +159,7 @@
         af2 = ufunc(af)
         assert all(af2 == af * 2)
         ac = arange(10, dtype=complex)
-        skip('casting not implemented yet')
-        ac1 = ufunc(ac)
+        raises(TypeError, ufunc, ac)
 
     def test_frompyfunc_2d_sig(self):
         import sys
@@ -199,6 +198,10 @@
         ai2 = ufunc(aiV)
         assert (ai2 == aiV * 2).all()
 
+        ai = arange(0).reshape(0, 1, 1)
+        ao = ufunc(ai)
+        assert ao.shape == (0, 1, 1)
+
     def test_frompyfunc_needs_nditer(self):
         import sys
         from numpy import frompyfunc, dtype, arange
@@ -268,6 +271,76 @@
         assert out0.shape == in0.shape
         assert (out0 == in0 * 2).all()
 
+    def test_frompyfunc_casting(self):
+        import sys
+        import numpy as np
+        if '__pypy__' not in sys.builtin_module_names:
+            skip('PyPy only frompyfunc extension')
+
+        def times2_int(in0, out0):
+            assert in0.dtype == int
+            assert out0.dtype == int
+            # hack to assing to a 0-dim array
+            out0.real = in0 * 2
+
+        def times2_complex(in0, out0):
+            assert in0.dtype == complex
+            assert out0.dtype == complex
+            out0.real = in0.real * 2
+            out0.imag = in0.imag
+
+        def times2_complex0(in0):
+            assert in0.dtype == complex
+            return in0 * 2
+
+        def times2_int0(in0):
+            assert in0.dtype == int
+            return in0 * 2
+
+        times2stacked = np.frompyfunc([times2_int, times2_complex], 1, 1,
+                            dtypes=[np.dtype(int), np.dtype(int),
+                                np.dtype(complex), np.dtype(complex)],
+                            stack_inputs=True, signature='()->()',
+                          )
+        times2 = np.frompyfunc([times2_int0, times2_complex0], 1, 1,
+                            dtypes=[np.dtype(int), np.dtype(int),
+                                np.dtype(complex), np.dtype(complex)],
+                            stack_inputs=False,
+                          )
+        for d in [np.dtype(float), np.dtype('uint8'), np.dtype('complex64')]:
+            in0 = np.arange(4, dtype=d)
+            out0 = times2stacked(in0)
+            assert out0.shape == in0.shape
+            assert out0.dtype in (int, complex) 
+            assert (out0 == in0 * 2).all()
+
+            out0 = times2(in0)
+            assert out0.shape == in0.shape
+            assert out0.dtype in (int, complex) 
+            assert (out0 == in0 * 2).all()
+
+    def test_frompyfunc_scalar(self):
+        import sys
+        import numpy as np
+        if '__pypy__' not in sys.builtin_module_names:
+            skip('PyPy only frompyfunc extension')
+
+        def summer(in0):
+            out = np.empty(1, in0.dtype)
+            out[0] = in0.sum()
+            return out
+
+        pysummer = np.frompyfunc([summer, summer], 1, 1,
+                            dtypes=[np.dtype(int), np.dtype(int),
+                                np.dtype(complex), np.dtype(complex)],
+                            stack_inputs=False, signature='(m,m)->()',
+                          )
+        for d in [np.dtype(float), np.dtype('uint8'), np.dtype('complex64')]:
+            in0 = np.arange(4, dtype=d).reshape(1, 2, 2)
+            out0 = pysummer(in0)
+            assert out0 == in0.sum()
+            assert out0.dtype in (int, complex)
+
     def test_ufunc_kwargs(self):
         from numpy import ufunc, frompyfunc, arange, dtype
         def adder(a, b):
@@ -1393,7 +1466,7 @@
     def test_add_doc(self):
         import sys
         if '__pypy__' not in sys.builtin_module_names:
-            skip('')
+            skip('cpython sets docstrings differently')
         try:
             from numpy import set_docstring
         except ImportError:
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
@@ -709,6 +709,32 @@
             raise oefmt(space.w_TypeError,
                 "ufunc '%s' not supported for the input types", self.name)
 
+def _match_dtypes(space, indtypes, targetdtypes, i_target, casting):
+    allok = True
+    for i in range(len(indtypes)):
+        origin = indtypes[i]
+        target = targetdtypes[i + i_target]
+        if origin is None:
+            continue
+        if target is None:
+            continue
+        if not can_cast_type(space, origin, target, casting):
+            allok = False
+            break
+    return allok
+
+def _raise_err_msg(self, space, dtypes0, dtypes1):
+    dtypesstr = ''
+    for d in dtypes0:
+        if d is None:
+            dtypesstr += 'None,'
+        else:
+            dtypesstr += '%s%s%s,' % (d.byteorder, d.kind, d.elsize)
+    _dtypesstr = ','.join(['%s%s%s' % (d.byteorder, d.kind, d.elsize) \
+                    for d in dtypes1])
+    raise oefmt(space.w_TypeError,
+         "input dtype [%s] did not match any known dtypes [%s] ",
+         dtypesstr,_dtypesstr)
 
 
 class W_UfuncGeneric(W_Ufunc):
@@ -799,29 +825,36 @@
             outargs0 = outargs[0]
             assert isinstance(inargs0, W_NDimArray)
             assert isinstance(outargs0, W_NDimArray)
+            nin = self.nin
+            assert nin >= 0
             res_dtype = outargs0.get_dtype()
             new_shape = inargs0.get_shape()
             # XXX use _find_array_wrap and wrap outargs using __array_wrap__
+            if self.stack_inputs:
+                loop.call_many_to_many(space, new_shape, func,
+                                         dtypes, [], inargs + outargs, [])
+                if len(outargs) < 2:
+                    return outargs[0]
+                return space.newtuple(outargs)
             if len(outargs) < 2:
                 return loop.call_many_to_one(space, new_shape, func,
-                                             res_dtype, inargs, outargs[0])
+                         dtypes[:nin], dtypes[-1], inargs, outargs[0])
             return loop.call_many_to_many(space, new_shape, func,
-                                             res_dtype, inargs, outargs)
+                         dtypes[:nin], dtypes[nin:], inargs, outargs)
+        w_casting = space.w_None
+        w_op_dtypes = space.w_None
         for tf in need_to_cast:
             if tf:
-                raise oefmt(space.w_NotImplementedError, "casting not 
supported yet")
+                w_casting = space.wrap('safe')
+                w_op_dtypes = space.newtuple([space.wrap(d) for d in dtypes])
+                
         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_ro = space.newtuple([space.wrap('readonly'), space.wrap('copy')])
+        w_rw = space.newtuple([space.wrap('readwrite'), 
space.wrap('updateifcopy')])
+        
+        w_op_flags = space.newtuple([w_ro] * len(inargs) + [w_rw] * 
len(outargs))
         w_op_axes = space.w_None
 
-        #print '\nsignature', sig
-        #print [(d, getattr(self,d)) for d in dir(self) if 'core' in d or 
'broad' in d]
-        #print [(d, locals()[d]) for d in locals() if 'core' in d or 'broad' 
in d]
-        #print 'shapes',[d.get_shape() for d in inargs + outargs]
-        #print 'steps',[d.implementation.strides for d in inargs + outargs]
         if isinstance(func, W_GenericUFuncCaller):
             # Use GeneralizeUfunc interface with signature
             # Unlike numpy, we will not broadcast dims before
@@ -934,19 +967,32 @@
         # 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
-        nop = len(inargs) + len(outargs)
+
+        # XXX why does the next line not pass translation?
+        # dtypes = [i.get_dtype() for i in inargs]
         dtypes = []
+        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)
         if isinstance(type_tup, str) and len(type_tup) > 0:
             try:
                 if len(type_tup) == 1:
-                    dtypes = [get_dtype_cache(space).dtypes_by_name[type_tup]] 
* self.nargs
+                    s_dtypes = 
[get_dtype_cache(space).dtypes_by_name[type_tup]] * self.nargs
                 elif len(type_tup) == self.nargs + 2:
+                    s_dtypes = []
                     for i in range(self.nin):
-                        
dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[i]])
+                        
s_dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[i]])
                     #skip the '->' in the signature
                     for i in range(self.nout):
                         j = i + self.nin + 2
-                        
dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[j]])
+                        
s_dtypes.append(get_dtype_cache(space).dtypes_by_name[type_tup[j]])
                 else:
                     raise oefmt(space.w_TypeError, "a type-string for %s " \
                         "requires 1 typecode or %d typecode(s) before and %d" \
@@ -955,42 +1001,29 @@
             except KeyError:
                 raise oefmt(space.w_ValueError, "unknown typecode in" \
                         " call to %s with type-string '%s'", self.name, 
type_tup)
-        else:
-            # 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):
-                    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)
+            # Make sure args can be cast to dtypes
+            if not _match_dtypes(space, dtypes, s_dtypes, 0, "safe"):
+                _raise_err_msg(self, space, dtypes, s_dtypes)
+            dtypes = s_dtypes    
         #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] != _dtypes[i+j]:
-                    allok = False
+            allok = _match_dtypes(space, dtypes, _dtypes, i, "no")
             if allok:
                 break
         else:
-            if len(self.funcs) > 1:
-
-                dtypesstr = ''
-                for d in dtypes:
-                    if d is None:
-                        dtypesstr += 'None,'
-                    else:
-                        dtypesstr += '%s%s%s,' % (d.byteorder, d.kind, 
d.elsize)
-                _dtypesstr = ','.join(['%s%s%s' % (d.byteorder, d.kind, 
d.elsize) \
-                                for d in _dtypes])
-                raise oefmt(space.w_TypeError,
-                     "input dtype [%s] did not match any known dtypes [%s] ",
-                     dtypesstr,_dtypesstr)
-            i = 0
+            # No exact matches, can we cast?
+            for i in range(0, len(_dtypes), self.nargs):
+                allok = _match_dtypes(space, dtypes, _dtypes, i, "safe")
+                if allok:
+                    end = i + self.nargs
+                    assert i >= 0
+                    assert end >=0
+                    dtypes = _dtypes[i:end]
+                    break
+            else:
+                if len(self.funcs) > 1:
+                    _raise_err_msg(self, space, dtypes, _dtypes)
+                i = 0
         # Fill in empty dtypes
         for j in range(self.nargs):
             if dtypes[j] is None:
@@ -1086,7 +1119,7 @@
             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:
+                if y != 0 and x != 0 and ((x > y and x % y) or y %x):
                     raise oefmt(space.w_ValueError, "%s: %s operand %d has a "
                         "mismatch in its broadcast dimension %d "
                         "(size %d is different from %d)",
@@ -1123,7 +1156,7 @@
         # the current op (signalling it can handle ndarray's).
 
         # TODO parse and handle subok
-        # TODO handle flags, op_flags
+        # TODO handle more flags, op_flags
         #print 
'iter_shape',iter_shape,'arg_shapes',arg_shapes,'matched_dims',matched_dims
         return iter_shape, arg_shapes, matched_dims
 
diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py
--- a/rpython/annotator/bookkeeper.py
+++ b/rpython/annotator/bookkeeper.py
@@ -8,12 +8,12 @@
 from contextlib import contextmanager
 
 from rpython.flowspace.model import Constant
-from rpython.annotator.model import (SomeOrderedDict,
-    SomeString, SomeChar, SomeFloat, unionof, SomeInstance, SomeDict,
-    SomeBuiltin, SomePBC, SomeInteger, TLS, SomeUnicodeCodePoint,
+from rpython.annotator.model import (
+    SomeOrderedDict, SomeString, SomeChar, SomeFloat, unionof, SomeInstance,
+    SomeDict, SomeBuiltin, SomePBC, SomeInteger, TLS, SomeUnicodeCodePoint,
     s_None, s_ImpossibleValue, SomeBool, SomeTuple,
     SomeImpossibleValue, SomeUnicodeString, SomeList, HarmlesslyBlocked,
-    SomeWeakRef, SomeByteArray, SomeConstantType, SomeProperty)
+    SomeWeakRef, SomeByteArray, SomeConstantType, SomeProperty, AnnotatorError)
 from rpython.annotator.classdef import InstanceSource, ClassDef
 from rpython.annotator.listdef import ListDef, ListItem
 from rpython.annotator.dictdef import DictDef
@@ -225,7 +225,8 @@
                 x = int(x)
                 result = SomeInteger(nonneg = x>=0)
             else:
-                raise Exception("seeing a prebuilt long (value %s)" % hex(x))
+                # XXX: better error reporting?
+                raise ValueError("seeing a prebuilt long (value %s)" % hex(x))
         elif issubclass(tp, str): # py.lib uses annotated str subclasses
             no_nul = not '\x00' in x
             if len(x) == 1:
diff --git a/rpython/annotator/classdef.py b/rpython/annotator/classdef.py
--- a/rpython/annotator/classdef.py
+++ b/rpython/annotator/classdef.py
@@ -112,14 +112,10 @@
                         for desc in s_newvalue.descriptions:
                             if desc.selfclassdef is None:
                                 if homedef.classdesc.settled:
-                                    raise Exception("demoting method %s "
-                                                    "to settled class %s not "
-                                                    "allowed" %
-                                                    (self.name, homedef)
-                                                    )
-                                #self.bookkeeper.warning("demoting method %s "
-                                #                        "to base class %s" %
-                                #                        (self.name, homedef))
+                                    raise AnnotatorError(
+                                        "demoting method %s to settled class "
+                                        "%s not allowed" % (self.name, homedef)
+                                    )
                                 break
 
         # check for attributes forbidden by slots or _attrs_
diff --git a/rpython/annotator/description.py b/rpython/annotator/description.py
--- a/rpython/annotator/description.py
+++ b/rpython/annotator/description.py
@@ -801,8 +801,9 @@
             s_init = basedesc.s_read_attribute('__init__')
             parent_has_init = isinstance(s_init, SomePBC)
             if has_init and not parent_has_init:
-                raise Exception("some subclasses among %r declare __init__(),"
-                                " but not the common parent class" % (descs,))
+                raise AnnotatorError(
+                    "some subclasses among %r declare __init__(),"
+                    " but not the common parent class" % (descs,))
         # make a PBC of MethodDescs, one for the __init__ of each class
         initdescs = []
         for desc, classdef in zip(descs, classdefs):
diff --git a/rpython/annotator/test/test_annrpython.py 
b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -4,10 +4,12 @@
 from rpython.conftest import option
 
 from rpython.annotator import model as annmodel
+from rpython.annotator.model import AnnotatorError, UnionError
 from rpython.annotator.annrpython import RPythonAnnotator as _RPythonAnnotator
+from rpython.annotator.classdef import NoSuchAttrError
 from rpython.translator.translator import graphof as tgraphof
 from rpython.annotator.policy import AnnotatorPolicy
-from rpython.annotator.signature import Sig
+from rpython.annotator.signature import Sig, SignatureError
 from rpython.annotator.listdef import ListDef, ListChangeUnallowed
 from rpython.annotator.dictdef import DictDef
 from rpython.flowspace.model import *
@@ -213,7 +215,7 @@
         def f():
             return X().meth()
         a = self.RPythonAnnotator()
-        py.test.raises(annmodel.AnnotatorError, a.build_types, f,  [])
+        py.test.raises(AnnotatorError, a.build_types, f,  [])
 
     def test_methodcall1(self):
         a = self.RPythonAnnotator()
@@ -360,7 +362,7 @@
         def f(l):
             return g(*l)
         a = self.RPythonAnnotator()
-        with py.test.raises(annmodel.AnnotatorError):
+        with py.test.raises(AnnotatorError):
             a.build_types(f, [[int]])
 
     def test_star_unpack_and_keywords(self):
@@ -769,7 +771,8 @@
         def f():
             return x
         a = self.RPythonAnnotator(policy=AnnotatorPolicy())
-        py.test.raises(Exception, a.build_types, f, [])
+        with py.test.raises(Exception):
+            a.build_types(f, [])
 
     def test_exception_deduction_with_raise1(self):
         a = self.RPythonAnnotator()
@@ -959,14 +962,16 @@
         def f():
             return large_constant
         a = self.RPythonAnnotator()
-        py.test.raises(Exception, a.build_types, f, [])
+        with py.test.raises(ValueError):
+            a.build_types(f, [])
         # if you want to get a r_uint, you have to be explicit about it
 
     def test_add_different_ints(self):
         def f(a, b):
             return a + b
         a = self.RPythonAnnotator()
-        py.test.raises(Exception, a.build_types, f, [r_uint, int])
+        with py.test.raises(UnionError):
+            a.build_types(f, [r_uint, int])
 
     def test_merge_different_ints(self):
         def f(a, b):
@@ -976,7 +981,8 @@
                 c = b
             return c
         a = self.RPythonAnnotator()
-        py.test.raises(Exception, a.build_types, f, [r_uint, int])
+        with py.test.raises(UnionError):
+            a.build_types(f, [r_uint, int])
 
     def test_merge_ruint_zero(self):
         def f(a):
@@ -2612,14 +2618,14 @@
         def f():
             return A()
         a = self.RPythonAnnotator()
-        py.test.raises(annmodel.AnnotatorError, a.build_types, f, [])
+        py.test.raises(AnnotatorError, a.build_types, f, [])
         #
         class B(object):
             pass
         x = B()
         def g():
             return isinstance(x, A)
-        py.test.raises(annmodel.AnnotatorError, a.build_types, g, [])
+        py.test.raises(AnnotatorError, a.build_types, g, [])
 
     def test_import_from_mixin(self):
         class M(object):
@@ -2694,7 +2700,8 @@
             return a.x   # should explode here
 
         a = self.RPythonAnnotator()
-        e = py.test.raises(Exception, a.build_types, f, [int])
+        with py.test.raises(NoSuchAttrError) as excinfo:
+            a.build_types(f, [int])
         # this should explode on reading the attribute 'a.x', but it can
         # sometimes explode on 'self.x = x', which does not make much sense.
         # But it looks hard to fix in general: we don't know yet during 'a.x'
@@ -2928,7 +2935,8 @@
         s = a.build_types(fun, [s_nonneg, s_nonneg])
         assert isinstance(s, annmodel.SomeInteger)
         assert not s.nonneg
-        py.test.raises(Exception, a.build_types, fun, [int, int])
+        with py.test.raises(SignatureError):
+            a.build_types(fun, [int, int])
 
     def test_sig_simpler(self):
         def fun(x, y):
@@ -2940,7 +2948,8 @@
         s = a.build_types(fun, [s_nonneg, s_nonneg])
         assert isinstance(s, annmodel.SomeInteger)
         assert not s.nonneg
-        py.test.raises(Exception, a.build_types, fun, [int, int])
+        with py.test.raises(SignatureError):
+            a.build_types(fun, [int, int])
 
     def test_sig_lambda(self):
         def fun(x, y):
@@ -2954,7 +2963,8 @@
         s = a.build_types(fun, [int, s_nonneg])
         assert isinstance(s, annmodel.SomeInteger)
         assert not s.nonneg
-        py.test.raises(Exception, a.build_types, fun, [s_nonneg, int])
+        with py.test.raises(SignatureError):
+            a.build_types(fun, [s_nonneg, int])
 
     def test_sig_bug(self):
         def g(x, y=5):
@@ -3004,8 +3014,8 @@
             if works:
                 a.build_types(fun, [int])
             else:
-                from rpython.annotator.classdef import NoSuchAttrError
-                py.test.raises(NoSuchAttrError, a.build_types, fun, [int])
+                with py.test.raises(NoSuchAttrError):
+                    a.build_types(fun, [int])
 
     def test_slots_enforce_attrs(self):
         class Superbase(object):
@@ -3138,7 +3148,8 @@
             return a.n()
 
         a = self.RPythonAnnotator()
-        py.test.raises(Exception, a.build_types, fun, [bool])
+        with py.test.raises(AnnotatorError):
+            a.build_types(fun, [bool])
 
     def test_float_cmp(self):
         def fun(x, y):
@@ -3227,6 +3238,7 @@
         assert isinstance(s.items[2], annmodel.SomeInstance)
         assert s.items[2].flags == {}
 
+    @py.test.mark.xfail
     def test_no_access_directly_on_heap(self):
         from rpython.rlib.jit import hint
 
@@ -3243,7 +3255,8 @@
             i.x = x
 
         a = self.RPythonAnnotator()
-        py.test.raises(Exception, a.build_types, f, [])
+        with py.test.raises(AnnotatorError):
+            a.build_types(f, [])
 
 
         class M:
@@ -3267,7 +3280,7 @@
             c.m.l.append(x)
 
         a = self.RPythonAnnotator()
-        py.test.raises(AssertionError, a.build_types, f, [])
+        py.test.raises(AnnotatorError, a.build_types, f, [])
 
         def f():
             x = A()
@@ -3275,7 +3288,7 @@
             c.m.d[None] = x
 
         a = self.RPythonAnnotator()
-        py.test.raises(AssertionError, a.build_types, f, [])
+        py.test.raises(AnnotatorError, a.build_types, f, [])
 
         def f():
             x = A()
@@ -3283,7 +3296,7 @@
             c.m.d[x] = None
 
         a = self.RPythonAnnotator()
-        py.test.raises(AssertionError, a.build_types, f, [])
+        py.test.raises(AnnotatorError, a.build_types, f, [])
 
     def test_ctr_location(self):
         class A:
@@ -3342,7 +3355,8 @@
             if g(x, y):
                 g(x, r_uint(y))
         a = self.RPythonAnnotator()
-        py.test.raises(Exception, a.build_types, f, [int, int])
+        with py.test.raises(UnionError):
+            a.build_types(f, [int, int])
 
     def test_compare_with_zero(self):
         def g():
@@ -3464,22 +3478,22 @@
             return '%s' % unichr(x)
 
         a = self.RPythonAnnotator()
-        py.test.raises(annmodel.AnnotatorError, a.build_types, f, [int])
+        py.test.raises(AnnotatorError, a.build_types, f, [int])
         def f(x):
             return '%s' % (unichr(x) * 3)
 
         a = self.RPythonAnnotator()
-        py.test.raises(annmodel.AnnotatorError, a.build_types, f, [int])
+        py.test.raises(AnnotatorError, a.build_types, f, [int])
         def f(x):
             return '%s%s' % (1, unichr(x))
 
         a = self.RPythonAnnotator()
-        py.test.raises(annmodel.AnnotatorError, a.build_types, f, [int])
+        py.test.raises(AnnotatorError, a.build_types, f, [int])
         def f(x):
             return '%s%s' % (1, unichr(x) * 15)
 
         a = self.RPythonAnnotator()
-        py.test.raises(annmodel.AnnotatorError, a.build_types, f, [int])
+        py.test.raises(AnnotatorError, a.build_types, f, [int])
 
 
     def test_strformatting_tuple(self):
@@ -3517,7 +3531,7 @@
             return [1, 2, 3][s:e]
 
         a = self.RPythonAnnotator()
-        py.test.raises(annmodel.AnnotatorError, "a.build_types(f, [int, int])")
+        py.test.raises(AnnotatorError, "a.build_types(f, [int, int])")
         a.build_types(f, [annmodel.SomeInteger(nonneg=True),
                           annmodel.SomeInteger(nonneg=True)])
         def f(x):
@@ -3530,20 +3544,20 @@
             return "xyz".find("x", s, e)
 
         a = self.RPythonAnnotator()
-        py.test.raises(annmodel.AnnotatorError, "a.build_types(f, [int, int])")
+        py.test.raises(AnnotatorError, "a.build_types(f, [int, int])")
         a.build_types(f, [annmodel.SomeInteger(nonneg=True),
                           annmodel.SomeInteger(nonneg=True)])
         def f(s, e):
             return "xyz".rfind("x", s, e)
 
-        py.test.raises(annmodel.AnnotatorError, "a.build_types(f, [int, int])")
+        py.test.raises(AnnotatorError, "a.build_types(f, [int, int])")
         a.build_types(f, [annmodel.SomeInteger(nonneg=True),
                           annmodel.SomeInteger(nonneg=True)])
 
         def f(s, e):
             return "xyz".count("x", s, e)
 
-        py.test.raises(annmodel.AnnotatorError, "a.build_types(f, [int, int])")
+        py.test.raises(AnnotatorError, "a.build_types(f, [int, int])")
         a.build_types(f, [annmodel.SomeInteger(nonneg=True),
                           annmodel.SomeInteger(nonneg=True)])
 
@@ -3717,7 +3731,8 @@
             raise Exception(lle)
             # ^^^ instead, must cast back from a base ptr to an instance
         a = self.RPythonAnnotator()
-        py.test.raises(AssertionError, a.build_types, f, [])
+        with py.test.raises(AssertionError):
+            a.build_types(f, [])
 
     def test_enumerate(self):
         def f():
@@ -4102,7 +4117,8 @@
                 e = cls()
                 e.foo = "bar"
             a = self.RPythonAnnotator()
-            py.test.raises(Exception, a.build_types, fn, [])
+            with py.test.raises(NoSuchAttrError):
+                a.build_types(fn, [])
 
     def test_lower_char(self):
         def fn(c):
@@ -4214,7 +4230,7 @@
                 return "bbb"
         a = self.RPythonAnnotator()
 
-        with py.test.raises(annmodel.UnionError) as exc:
+        with py.test.raises(UnionError) as exc:
             a.build_types(f, [int])
 
         the_exc = exc.value
@@ -4230,7 +4246,7 @@
                 return (1, 2)
         a = self.RPythonAnnotator()
 
-        with py.test.raises(annmodel.UnionError) as exc:
+        with py.test.raises(UnionError) as exc:
             a.build_types(f, [int])
 
         assert "RPython cannot unify tuples of different length: 2 versus 1" 
in exc.value.msg
@@ -4243,7 +4259,7 @@
                 return -1
         a = self.RPythonAnnotator()
 
-        with py.test.raises(annmodel.UnionError) as exc:
+        with py.test.raises(UnionError) as exc:
             a.build_types(f, [int])
 
         assert ("RPython cannot prove that these integers are of the "
@@ -4260,7 +4276,7 @@
                 return B()
         a = self.RPythonAnnotator()
 
-        with py.test.raises(annmodel.UnionError) as exc:
+        with py.test.raises(UnionError) as exc:
             a.build_types(f, [int])
 
         assert ("RPython cannot unify instances with no common base class"
@@ -4276,7 +4292,7 @@
                 return d.itervalues()
         a = self.RPythonAnnotator()
 
-        with py.test.raises(annmodel.UnionError) as exc:
+        with py.test.raises(UnionError) as exc:
             a.build_types(f, [int])
 
         assert ("RPython cannot unify incompatible iterator variants" in
@@ -4288,7 +4304,7 @@
             a = A()
             return getattr(a, y)
         a = self.RPythonAnnotator()
-        with py.test.raises(annmodel.AnnotatorError) as exc:
+        with py.test.raises(AnnotatorError) as exc:
             a.build_types(f, [str])
         assert ("variable argument to getattr" in exc.value.msg)
 
@@ -4296,7 +4312,7 @@
         def f(x):
             return x()
         a = self.RPythonAnnotator()
-        with py.test.raises(annmodel.AnnotatorError) as exc:
+        with py.test.raises(AnnotatorError) as exc:
             a.build_types(f, [str])
         assert ("Cannot prove that the object is callable" in exc.value.msg)
 
@@ -4305,7 +4321,7 @@
         def f(x):
             l.append(x)
         a = self.RPythonAnnotator()
-        with py.test.raises(annmodel.UnionError) as excinfo:
+        with py.test.raises(UnionError) as excinfo:
             a.build_types(f, [int])
         assert 'Happened at file' in excinfo.value.source
         assert 'Known variable annotations:' in excinfo.value.source
@@ -4314,7 +4330,7 @@
         def f(s, x):
             return s.format(x)
         a = self.RPythonAnnotator()
-        with py.test.raises(annmodel.AnnotatorError) as exc:
+        with py.test.raises(AnnotatorError) as exc:
             a.build_types(f, [str, str])
         assert ("format() is not RPython" in exc.value.msg)
 
@@ -4350,7 +4366,7 @@
         def f(x):
             a, b = x
         a = self.RPythonAnnotator()
-        py.test.raises(annmodel.AnnotatorError,
+        py.test.raises(AnnotatorError,
                        a.build_types, f, [annmodel.s_None])
 
     def test_class___name__(self):
@@ -4464,10 +4480,10 @@
             o = O2(n)
             o.x = 20
         a = self.RPythonAnnotator()
-        with py.test.raises(annmodel.UnionError) as exc:
+        with py.test.raises(UnionError) as exc:
             a.build_types(f1, [int])
         a = self.RPythonAnnotator()
-        with py.test.raises(annmodel.UnionError) as exc:
+        with py.test.raises(UnionError) as exc:
             a.build_types(f2, [int])
 
     def test_property_union_2(self):
@@ -4496,7 +4512,7 @@
         a = self.RPythonAnnotator()
         # Ideally, this should translate to something sensible,
         # but for now, AnnotatorError is better than silently mistranslating.
-        with py.test.raises(annmodel.AnnotatorError):
+        with py.test.raises(AnnotatorError):
             a.build_types(f, [int])
 
     def test_property_union_3(self):
@@ -4516,7 +4532,7 @@
                 obj = B()
             return obj.x
         a = self.RPythonAnnotator()
-        with py.test.raises(annmodel.AnnotatorError):
+        with py.test.raises(AnnotatorError):
             a.build_types(f, [int])
 
     def test_dict_can_be_none_ordering_issue(self):
diff --git a/rpython/annotator/test/test_annsimplifyrpython.py 
b/rpython/annotator/test/test_annsimplifyrpython.py
--- a/rpython/annotator/test/test_annsimplifyrpython.py
+++ b/rpython/annotator/test/test_annsimplifyrpython.py
@@ -3,6 +3,7 @@
 
 from rpython.annotator.test.test_annrpython import graphof
 from rpython.annotator.test.test_annrpython import TestAnnotateTestCase as 
parent
+from rpython.annotator.model import AnnotatorError
 
 
 class TestAnnotateAndSimplifyTestCase(parent):
@@ -132,5 +133,5 @@
                 cls = C
             return cls().foo
         a = self.RPythonAnnotator()
-        with py.test.raises(Exception):
+        with py.test.raises(AnnotatorError):
             a.build_types(f, [int])
diff --git a/rpython/rlib/rdynload.py b/rpython/rlib/rdynload.py
--- a/rpython/rlib/rdynload.py
+++ b/rpython/rlib/rdynload.py
@@ -2,13 +2,13 @@
 """
 
 from rpython.rtyper.tool import rffi_platform
-from rpython.rtyper.lltypesystem import rffi
+from rpython.rtyper.lltypesystem import rffi, lltype
 from rpython.rlib.objectmodel import we_are_translated
 from rpython.rlib.rarithmetic import r_uint
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
 from rpython.translator.platform import platform
 
-import sys
+import sys, os, string
 
 # maaaybe isinstance here would be better. Think
 _MSVC = platform.name == "msvc"
@@ -103,6 +103,48 @@
             return ("opening %r with ctypes.CDLL() works, "
                     "but not with c_dlopen()??" % (name,))
 
+    def _retry_as_ldscript(err, mode):
+        """ ld scripts are fairly straightforward to parse (the library we want
+        is in a form like 'GROUP ( <actual-filepath.so>'. A simple state 
machine
+        can parse that out (avoids regexes)."""
+
+        parts = err.split(":")
+        if len(parts) != 2:
+            return lltype.nullptr(rffi.VOIDP.TO)
+        fullpath = parts[0]
+        actual = ""
+        last_five = "     "
+        state = 0
+        ldscript = os.open(fullpath, os.O_RDONLY, 0777)
+        c = os.read(ldscript, 1)
+        while c != "":
+            if state == 0:
+                last_five += c
+                last_five = last_five[1:6]
+                if last_five == "GROUP":
+                    state = 1
+            elif state == 1:
+                if c == "(":
+                    state = 2
+            elif state == 2:
+                if c not in string.whitespace:
+                    actual += c
+                    state = 3
+            elif state == 3:
+                if c in string.whitespace or c == ")":
+                    break
+                else:
+                    actual += c
+            c = os.read(ldscript, 1)
+        os.close(ldscript)
+        if actual != "":
+            a = rffi.str2charp(actual)
+            lib = c_dlopen(a, rffi.cast(rffi.INT, mode))
+            rffi.free_charp(a)
+            return lib
+        else:
+            return lltype.nullptr(rffi.VOIDP.TO)
+
     def dlopen(name, mode=-1):
         """ Wrapper around C-level dlopen
         """
@@ -119,7 +161,17 @@
                 err = _dlerror_on_dlopen_untranslated(name)
             else:
                 err = dlerror()
-            raise DLOpenError(err)
+            if platform.name == "linux" and 'invalid ELF header' in err:
+                # some linux distros put ld linker scripts in .so files
+                # to load libraries more dynamically. The error contains the
+                # full path to something that is probably a script to load
+                # the library we want.
+                res = _retry_as_ldscript(err, mode)
+                if not res:
+                    raise DLOpenError(err)
+                return res
+            else:
+                raise DLOpenError(err)
         return res
 
     dlclose = c_dlclose
diff --git a/rpython/rlib/rstrategies/rstrategies.py 
b/rpython/rlib/rstrategies/rstrategies.py
--- a/rpython/rlib/rstrategies/rstrategies.py
+++ b/rpython/rlib/rstrategies/rstrategies.py
@@ -41,7 +41,7 @@
         attrs['get_storage'] = get_storage
         attrs['set_storage'] = set_storage
         return type.__new__(self, name, bases, attrs)
-    
+
 def strategy(generalize=None, singleton=True):
     """
     Strategy classes must be decorated with this.
@@ -71,19 +71,19 @@
 class StrategyFactory(object):
     _immutable_fields_ = ["strategies[*]", "logger", 
"strategy_singleton_field"]
     factory_instance_counter = 0
-    
+
     def __init__(self, root_class, all_strategy_classes=None):
         if all_strategy_classes is None:
             all_strategy_classes = self._collect_subclasses(root_class)
         self.strategies = []
         self.logger = logger.Logger()
-        
+
         # This is to avoid confusion between multiple factories existing 
simultaneously (e.g. in tests)
         self.strategy_singleton_field = "__singleton_%i" % 
StrategyFactory.factory_instance_counter
         StrategyFactory.factory_instance_counter += 1
-        
+
         self._create_strategy_instances(root_class, all_strategy_classes)
-    
+
     def _create_strategy_instances(self, root_class, all_strategy_classes):
         for strategy_class in all_strategy_classes:
             if strategy_class._is_strategy:
@@ -91,11 +91,11 @@
                 self.strategies.append(strategy_class)
             self._patch_strategy_class(strategy_class, root_class)
         self._order_strategies()
-    
+
     # =============================
     # API methods
     # =============================
-    
+
     def switch_strategy(self, w_self, new_strategy_type, new_element=None):
         """
         Switch the strategy of w_self to the new type.
@@ -113,7 +113,7 @@
         new_strategy.strategy_switched(w_self)
         self.log(w_self, new_strategy, old_strategy, new_element)
         return new_strategy
-    
+
     def set_initial_strategy(self, w_self, strategy_type, size, elements=None):
         """
         Initialize the strategy and storage fields of w_self.
@@ -135,7 +135,7 @@
         strategy.strategy_switched(w_self)
         self.log(w_self, strategy, None, element)
         return strategy
-    
+
     @jit.unroll_safe
     def strategy_type_for(self, objects):
         """
@@ -153,8 +153,8 @@
         for i, strategy_type in enumerate(self.strategies):
             if can_handle[i]:
                 return strategy_type
-        raise Exception("Could not find strategy to handle: %s" % objects)
-    
+        raise ValueError("Could not find strategy to handle: %s" % objects)
+
     def decorate_strategies(self, transitions):
         """
         As an alternative to decorating all strategies with @strategy,
@@ -165,11 +165,11 @@
         "NOT_RPYTHON"
         for strategy_class, generalized in transitions.items():
             strategy(generalized)(strategy_class)
-    
+
     # =============================
     # The following methods can be overwritten to customize certain aspects of 
the factory.
     # =============================
-    
+
     def instantiate_strategy(self, strategy_type, w_self=None, initial_size=0):
         """
         Return a functional instance of strategy_type.
@@ -177,7 +177,7 @@
         The two additional parameters should be ignored for 
singleton-strategies.
         """
         return strategy_type()
-    
+
     def log(self, w_self, new_strategy, old_strategy=None, new_element=None):
         """
         This can be overwritten into a more appropriate call to self.logger.log
@@ -190,7 +190,7 @@
         typename = ""
         cause = "Switched" if old_strategy else "Created"
         self.logger.log(new_strategy_str, size, cause, old_strategy_str, 
typename, element_typename)
-    
+
     @specialize.call_location()
     def log_string_for_object(self, obj):
         """
@@ -198,8 +198,8 @@
         Keep the specialize-annotation in order to handle different kinds of 
objects here.
         """
         return obj.__class__.__name__ if obj else ""
-    
-    # These storage accessors are specialized because the storage field is 
+
+    # These storage accessors are specialized because the storage field is
     # populated by erased-objects which seem to be incompatible sometimes.
     @specialize.call_location()
     def get_storage(self, obj):
@@ -207,16 +207,16 @@
     @specialize.call_location()
     def set_storage(self, obj, val):
         return obj._set_storage(val)
-    
+
     def get_strategy(self, obj):
         return obj._get_strategy()
     def set_strategy(self, obj, val):
         return obj._set_strategy(val)
-    
+
     # =============================
     # Internal methods
     # =============================
-    
+
     def _patch_strategy_class(self, strategy_class, root_class):
         "NOT_RPYTHON"
         # Patch root class: Add default handler for visitor
@@ -225,12 +225,12 @@
         funcname = "_convert_storage_from_" + strategy_class.__name__
         _convert_storage_from_OTHER.func_name = funcname
         setattr(root_class, funcname, _convert_storage_from_OTHER)
-        
+
         # Patch strategy class: Add polymorphic visitor function
         def _convert_storage_to(self, w_self, new_strategy):
             getattr(new_strategy, funcname)(w_self, self)
         strategy_class._convert_storage_to = _convert_storage_to
-    
+
     def _collect_subclasses(self, cls):
         "NOT_RPYTHON"
         subclasses = []
@@ -238,7 +238,7 @@
             subclasses.append(subcls)
             subclasses.extend(self._collect_subclasses(subcls))
         return subclasses
-    
+
     def _order_strategies(self):
         "NOT_RPYTHON"
         def get_generalization_depth(strategy, visited=None):
@@ -256,11 +256,11 @@
             else:
                 return 0
         self.strategies.sort(key=get_generalization_depth, reverse=True)
-    
+
     @jit.elidable
     def strategy_singleton_instance(self, strategy_class):
         return getattr(strategy_class, self.strategy_singleton_field)
-    
+
     def _freeze_(self):
         # Instance will be frozen at compile time, making accesses constant.
         # The constructor does meta stuff which is not possible after 
translation.
@@ -271,65 +271,65 @@
     == Required:
     strategy_factory(self) - Access to StorageFactory
     """
-    
+
     def strategy_switched(self, w_self):
         # Overwrite this method for a hook whenever the strategy
         # of w_self was switched to self.
         pass
-    
+
     # Main Fixedsize API
-    
+
     def store(self, w_self, index0, value):
         raise NotImplementedError("Abstract method")
-    
+
     def fetch(self, w_self, index0):
         raise NotImplementedError("Abstract method")
-    
+
     def size(self, w_self):
         raise NotImplementedError("Abstract method")
-    
+
     # Fixedsize utility methods
-    
+
     def slice(self, w_self, start, end):
         return [ self.fetch(w_self, i) for i in range(start, end)]
-    
+
     def fetch_all(self, w_self):
         return self.slice(w_self, 0, self.size(w_self))
-    
+
     def store_all(self, w_self, elements):
         for i, e in enumerate(elements):
             self.store(w_self, i, e)
-    
+
     # Main Varsize API
-    
+
     def insert(self, w_self, index0, list_w):
         raise NotImplementedError("Abstract method")
-    
+
     def delete(self, w_self, start, end):
         raise NotImplementedError("Abstract method")
-    
+
     # Varsize utility methods
-    
+
     def append(self, w_self, list_w):
-        self.insert(w_self, self.size(w_self), list_w)        
-    
+        self.insert(w_self, self.size(w_self), list_w)
+
     def pop(self, w_self, index0):
         e = self.fetch(w_self, index0)
         self.delete(w_self, index0, index0+1)
         return e
 
     # Internal methods
-    
+
     def _initialize_storage(self, w_self, initial_size):
         raise NotImplementedError("Abstract method")
-    
+
     def _check_can_handle(self, value):
         raise NotImplementedError("Abstract method")
-    
+
     def _convert_storage_to(self, w_self, new_strategy):
         # This will be overwritten in _patch_strategy_class
         new_strategy._convert_storage_from(w_self, self)
-    
+
     @jit.unroll_safe
     def _convert_storage_from(self, w_self, previous_strategy):
         # This is a very unefficient (but most generic) way to do this.
@@ -338,16 +338,16 @@
         self._initialize_storage(w_self, previous_strategy.size(w_self))
         for i, field in enumerate(storage):
             self.store(w_self, i, field)
-    
+
     def _generalize_for_value(self, w_self, value):
         strategy_type = self.generalized_strategy_for(value)
         new_instance = self.strategy_factory().switch_strategy(w_self, 
strategy_type, new_element=value)
         return new_instance
-        
+
     def _cannot_handle_store(self, w_self, index0, value):
         new_instance = self._generalize_for_value(w_self, value)
         new_instance.store(w_self, index0, value)
-        
+
     def _cannot_handle_insert(self, w_self, index0, list_w):
         # TODO - optimize. Prevent multiple generalizations and slicing done 
by callers.
         new_strategy = self._generalize_for_value(w_self, list_w[0])
@@ -358,7 +358,7 @@
 class EmptyStrategy(AbstractStrategy):
     # == Required:
     # See AbstractStrategy
-    
+
     def _initialize_storage(self, w_self, initial_size):
         assert initial_size == 0
         self.set_storage(w_self, None)
@@ -366,7 +366,7 @@
         self.set_storage(w_self, None)
     def _check_can_handle(self, value):
         return False
-    
+
     def fetch(self, w_self, index0):
         raise IndexError
     def store(self, w_self, index0, value):
@@ -389,7 +389,7 @@
     # See AbstractStrategy
     # check_index_*(...) - use mixin SafeIndexingMixin or UnsafeIndexingMixin
     # value(self) - the single value contained in this strategy. Should be 
constant.
-    
+
     def _initialize_storage(self, w_self, initial_size):
         storage_obj = SingleValueStrategyStorage(initial_size)
         self.set_storage(w_self, storage_obj)
@@ -397,7 +397,7 @@
         self._initialize_storage(w_self, previous_strategy.size(w_self))
     def _check_can_handle(self, value):
         return value is self.value()
-    
+
     def fetch(self, w_self, index0):
         self.check_index_fetch(w_self, index0)
         return self.value()
@@ -411,7 +411,7 @@
         self.get_storage(w_self).size -= (end - start)
     def size(self, w_self):
         return self.get_storage(w_self).size
-    
+
     @jit.unroll_safe
     def insert(self, w_self, index0, list_w):
         storage_obj = self.get_storage(w_self)
@@ -429,18 +429,18 @@
     # See AbstractStrategy
     # check_index_*(...) - use mixin SafeIndexingMixin or UnsafeIndexingMixin
     # default_value(self) - The value to be initially contained in this 
strategy
-    
+
     def _initialize_storage(self, w_self, initial_size):
         default = self._unwrap(self.default_value())
         self.set_storage(w_self, [default] * initial_size)
-    
+
     @jit.unroll_safe
     def _convert_storage_from(self, w_self, previous_strategy):
         size = previous_strategy.size(w_self)
         new_storage = [ self._unwrap(previous_strategy.fetch(w_self, i))
                         for i in range(size) ]
         self.set_storage(w_self, new_storage)
-    
+
     def store(self, w_self, index0, wrapped_value):
         self.check_index_store(w_self, index0)
         if self._check_can_handle(wrapped_value):
@@ -448,21 +448,21 @@
             self.get_storage(w_self)[index0] = unwrapped
         else:
             self._cannot_handle_store(w_self, index0, wrapped_value)
-    
+
     def fetch(self, w_self, index0):
         self.check_index_fetch(w_self, index0)
         unwrapped = self.get_storage(w_self)[index0]
         return self._wrap(unwrapped)
-    
+
     def _wrap(self, value):
         raise NotImplementedError("Abstract method")
-    
+
     def _unwrap(self, value):
         raise NotImplementedError("Abstract method")
-    
+
     def size(self, w_self):
         return len(self.get_storage(w_self))
-    
+
     @jit.unroll_safe
     def insert(self, w_self, start, list_w):
         # This is following Python's behaviour - insert automatically
@@ -475,27 +475,27 @@
             else:
                 self._cannot_handle_insert(w_self, start + i, list_w[i:])
                 return
-    
+
     def delete(self, w_self, start, end):
         self.check_index_range(w_self, start, end)
         assert start >= 0 and end >= 0
         del self.get_storage(w_self)[start : end]
-        
+
 class GenericStrategy(StrategyWithStorage):
     # == Required:
     # See StrategyWithStorage
-    
+
     def _wrap(self, value):
         return value
     def _unwrap(self, value):
         return value
     def _check_can_handle(self, wrapped_value):
         return True
-    
+
 class WeakGenericStrategy(StrategyWithStorage):
     # == Required:
     # See StrategyWithStorage
-    
+
     def _wrap(self, value):
         return value() or self.default_value()
     def _unwrap(self, value):
@@ -503,7 +503,7 @@
         return weakref.ref(value)
     def _check_can_handle(self, wrapped_value):
         return True
-    
+
 # ============== Mixins for index checking operations ==============
 
 class SafeIndexingMixin(object):
@@ -535,37 +535,37 @@
     # See StrategyWithStorage
     # wrap(self, value) - Return a boxed object for the primitive value
     # unwrap(self, value) - Return the unboxed primitive value of value
-    
+
     def _unwrap(self, value):
         return self.unwrap(value)
     def _wrap(self, value):
         return self.wrap(value)
-    
+
 class SingleTypeStrategy(SpecializedStrategy):
     # == Required Functions:
     # See SpecializedStrategy
     # contained_type - The wrapped type that can be stored in this strategy
-    
+
     def _check_can_handle(self, value):
         return isinstance(value, self.contained_type)
-    
+
 class TaggingStrategy(SingleTypeStrategy):
     """This strategy uses a special tag value to represent a single additional 
object."""
     # == Required:
     # See SingleTypeStrategy
     # wrapped_tagged_value(self) - The tagged object
     # unwrapped_tagged_value(self) - The unwrapped tag value representing the 
tagged object
-    
+
     def _check_can_handle(self, value):
         return value is self.wrapped_tagged_value() or \
                 (isinstance(value, self.contained_type) and \
                 self.unwrap(value) != self.unwrapped_tagged_value())
-    
+
     def _unwrap(self, value):
         if value is self.wrapped_tagged_value():
             return self.unwrapped_tagged_value()
         return self.unwrap(value)
-    
+
     def _wrap(self, value):
         if value == self.unwrapped_tagged_value():
             return self.wrapped_tagged_value()
diff --git a/rpython/rlib/rstrategies/test/test_rstrategies.py 
b/rpython/rlib/rstrategies/test/test_rstrategies.py
--- a/rpython/rlib/rstrategies/test/test_rstrategies.py
+++ b/rpython/rlib/rstrategies/test/test_rstrategies.py
@@ -69,7 +69,7 @@
 
 class Factory(rs.StrategyFactory):
     switching_log = []
-    
+
     def __init__(self, root_class):
         self.decorate_strategies({
             EmptyStrategy: [NilStrategy, IntegerStrategy, 
IntegerOrNilStrategy, GenericStrategy],
@@ -79,15 +79,15 @@
             IntegerOrNilStrategy: [GenericStrategy],
         })
         rs.StrategyFactory.__init__(self, root_class)
-    
+
     def instantiate_strategy(self, strategy_type, w_self=None, size=0):
         return strategy_type(self, w_self, size)
-    
-    def set_strategy(self, w_list, strategy): 
+
+    def set_strategy(self, w_list, strategy):
         old_strategy = self.get_strategy(w_list)
         self.switching_log.append((old_strategy, strategy))
         super(Factory, self).set_strategy(w_list, strategy)
-    
+
     def clear_log(self):
         del self.switching_log[:]
 
@@ -107,7 +107,7 @@
 class WeakGenericStrategy(AbstractStrategy):
     import_from_mixin(rs.WeakGenericStrategy)
     def default_value(self): return w_nil
-    
+
 class IntegerStrategy(AbstractStrategy):
     import_from_mixin(rs.SingleTypeStrategy)
     contained_type = W_Integer
@@ -123,7 +123,7 @@
     def default_value(self): return w_nil
     def wrapped_tagged_value(self): return w_nil
     def unwrapped_tagged_value(self): import sys; return sys.maxint
-    
+
 @rs.strategy(generalize=[], singleton=False)
 class NonSingletonStrategy(GenericStrategy):
     def __init__(self, factory, w_list=None, size=0):
@@ -214,22 +214,22 @@
     py.test.raises(IndexError, s.fetch, l, 10)
     py.test.raises(IndexError, s.delete, l, 0, 1)
     py.test.raises(AssertionError, W_List, EmptyStrategy, 2) # Only size 0 
possible.
-    
+
 def test_init_Nil():
     do_test_initialization(NilStrategy)
 
 def test_init_Generic():
     do_test_initialization(GenericStrategy, is_safe=False)
-    
+
 def test_init_WeakGeneric():
     do_test_initialization(WeakGenericStrategy)
-    
+
 def test_init_Integer():
     do_test_initialization(IntegerStrategy, default_value=W_Integer(0))
-    
+
 def test_init_IntegerOrNil():
     do_test_initialization(IntegerOrNilStrategy)
-    
+
 # === Test Simple store
 
 def do_test_store(cls, stored_value=W_Object(), is_safe=True, 
is_varsize=False):
@@ -256,13 +256,13 @@
 
 def test_store_Generic():
     do_test_store(GenericStrategy, is_safe=False)
-    
+
 def test_store_WeakGeneric():
     do_test_store(WeakGenericStrategy, stored_value=w_nil)
-    
+
 def test_store_Integer():
     do_test_store(IntegerStrategy, stored_value=W_Integer(100))
-    
+
 def test_store_IntegerOrNil():
     do_test_store(IntegerOrNilStrategy, stored_value=W_Integer(100))
     do_test_store(IntegerOrNilStrategy, stored_value=w_nil)
@@ -289,17 +289,17 @@
 
 def test_insert_Generic():
     do_test_insert(GenericStrategy, [W_Object() for _ in range(6)])
-    
+
 def test_insert_WeakGeneric():
     do_test_insert(WeakGenericStrategy, [W_Object() for _ in range(6)])
-    
+
 def test_insert_Integer():
     do_test_insert(IntegerStrategy, [W_Integer(x) for x in range(6)])
-    
+
 def test_insert_IntegerOrNil():
     do_test_insert(IntegerOrNilStrategy, [w_nil]+[W_Integer(x) for x in 
range(4)]+[w_nil])
     do_test_insert(IntegerOrNilStrategy, [w_nil]*6)
-    
+
 # === Test Delete
 
 def do_test_delete(cls, values, indexing_unsafe=False):
@@ -319,13 +319,13 @@
 
 def test_delete_Generic():
     do_test_delete(GenericStrategy, [W_Object() for _ in range(6)], 
indexing_unsafe=True)
-    
+
 def test_delete_WeakGeneric():
     do_test_delete(WeakGenericStrategy, [W_Object() for _ in range(6)])
-    
+
 def test_delete_Integer():
     do_test_delete(IntegerStrategy, [W_Integer(x) for x in range(6)])
-    
+
 def test_delete_IntegerOrNil():
     do_test_delete(IntegerOrNilStrategy, [w_nil]+[W_Integer(x) for x in 
range(4)]+[w_nil])
     do_test_delete(IntegerOrNilStrategy, [w_nil]*6)
@@ -342,7 +342,7 @@
     obj = W_Object()
     i = W_Integer(0)
     nil = w_nil
-    
+
     assert_handles(EmptyStrategy, [], [nil, obj, i])
     assert_handles(NilStrategy, [nil], [obj, i])
     assert_handles(GenericStrategy, [nil, obj, i], [])
@@ -392,7 +392,7 @@
     o = W_Object()
     l = do_test_insert(NilStrategy, [w_nil, w_nil, o, o, w_nil, w_nil])
     assert isinstance(l.strategy, GenericStrategy)
-    
+
 def test_transition_to_nonSingleton():
     l = W_List(NilStrategy, 5)
     factory.switch_strategy(l, NonSingletonStrategy)
@@ -467,12 +467,12 @@
     v3 = [W_Object() for _ in range(l.size()) ]
     assert v2 != v
     assert v3 != v
-    
+
     l.store_all(v2)
     assert l.fetch_all() == v2+v[4:]
     l.store_all(v3)
     assert l.fetch_all() == v3
-    
+
     py.test.raises(IndexError, l.store_all, [W_Object() for _ in range(8) ])
 
 # === Test Weak Strategy
@@ -488,7 +488,7 @@
         assert False, "The default convert_storage_from() should not be 
called!"
     def convert_storage_from_special(self, w_self, other):
         s.copied += 1
-    
+
     monkeypatch.setattr(AbstractStrategy, "_convert_storage_from_NilStrategy", 
convert_storage_from_special)
     monkeypatch.setattr(AbstractStrategy, "_convert_storage_from", 
convert_storage_from_default)
     try:
@@ -507,7 +507,8 @@
     assert factory.strategy_type_for([]) == EmptyStrategy
     monkeypatch.setattr(GenericStrategy, '_check_can_handle', lambda self, o: 
False)
     try:
-        py.test.raises(Exception, factory.strategy_type_for, [W_Object(), 
W_Object()])
+        with py.test.raises(ValueError):
+            factory.strategy_type_for([W_Object(), W_Object()])
     finally:
         monkeypatch.undo()
 
@@ -549,4 +550,3 @@
         'Created (EmptyStrategy) size 0 objects 1',
         'Created (IntegerStrategy) size 3 objects 1',
         'Switched (IntegerStrategy -> IntegerOrNilStrategy) size 3 objects 1 
elements: W_Object']
-    
\ No newline at end of file
diff --git a/rpython/rlib/rweakref.py b/rpython/rlib/rweakref.py
--- a/rpython/rlib/rweakref.py
+++ b/rpython/rlib/rweakref.py
@@ -2,10 +2,10 @@
 Weakref support in RPython.  Basic regular weakrefs without callbacks
 are supported.  This file contains the following additions:
 a form of WeakKeyDictionary, and a limited version of WeakValueDictionary.
-LLType only for now!
 """
 
 import weakref
+from rpython.annotator.model import UnionError
 
 ref = weakref.ref    # basic regular weakrefs are supported in RPython
 
@@ -191,9 +191,9 @@
 class __extend__(pairtype(SomeWeakKeyDict, SomeWeakKeyDict)):
     def union((s_wkd1, s_wkd2)):
         if s_wkd1.keyclassdef is not s_wkd2.keyclassdef:
-            raise UnionError(w_wkd1, s_wkd2, "not the same key class!")
+            raise UnionError(s_wkd1, s_wkd2, "not the same key class!")
         if s_wkd1.valueclassdef is not s_wkd2.valueclassdef:
-            raise UnionError(w_wkd1, s_wkd2, "not the same value class!")
+            raise UnionError(s_wkd1, s_wkd2, "not the same value class!")
         return SomeWeakKeyDict(s_wkd1.keyclassdef, s_wkd1.valueclassdef)
 
 class Entry(extregistry.ExtRegistryEntry):
diff --git a/rpython/rlib/test/ldscript_broken1.so 
b/rpython/rlib/test/ldscript_broken1.so
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/test/ldscript_broken1.so
@@ -0,0 +1,4 @@
+/* GNU ld script
+*/
+OUTPUT_FORMAT(elf64-x86-64)
+GROUP libc.so.6 )
diff --git a/rpython/rlib/test/ldscript_broken2.so 
b/rpython/rlib/test/ldscript_broken2.so
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/test/ldscript_broken2.so
@@ -0,0 +1,4 @@
+/* GNU ld script
+*/
+OUTPUT_FORMAT(elf64-x86-64)
+libc.so.6
diff --git a/rpython/rlib/test/ldscript_working1.so 
b/rpython/rlib/test/ldscript_working1.so
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/test/ldscript_working1.so
@@ -0,0 +1,4 @@
+/* GNU ld script
+*/
+OUTPUT_FORMAT(elf64-x86-64)
+GROUP ( libc.so.6 )
diff --git a/rpython/rlib/test/ldscript_working2.so 
b/rpython/rlib/test/ldscript_working2.so
new file mode 100644
--- /dev/null
+++ b/rpython/rlib/test/ldscript_working2.so
@@ -0,0 +1,4 @@
+/* GNU ld script
+*/
+OUTPUT_FORMAT(elf64-x86-64)
+GROUP(libc.so.6)
diff --git a/rpython/rlib/test/test_rdynload.py 
b/rpython/rlib/test/test_rdynload.py
--- a/rpython/rlib/test/test_rdynload.py
+++ b/rpython/rlib/test/test_rdynload.py
@@ -1,6 +1,7 @@
 from rpython.rlib.rdynload import *
 from rpython.rlib.clibffi import get_libc_name
 from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.translator.platform import platform
 import py
 
 class TestDLOperations:
@@ -21,3 +22,28 @@
                            lltype.Signed)), dlsym(lib, 'abs'))
         assert 1 == handle(1)
         assert 1 == handle(-1)
+
+    def test_ldscripts(self):
+        # this test only makes sense on linux
+        if platform.name != "linux":
+            return
+
+        fname = os.path.join(os.path.dirname(__file__), "ldscript_working1.so")
+        s = rffi.str2charp(fname)
+        assert "C object" in str(dlopen(s))
+        rffi.free_charp(s)
+
+        fname = os.path.join(os.path.dirname(__file__), "ldscript_working2.so")
+        s = rffi.str2charp(fname)
+        assert "C object" in str(dlopen(s))
+        rffi.free_charp(s)
+
+        fname = os.path.join(os.path.dirname(__file__), "ldscript_broken1.so")
+        s = rffi.str2charp(fname)
+        py.test.raises(DLOpenError, 'dlopen(s)')
+        rffi.free_charp(s)
+
+        fname = os.path.join(os.path.dirname(__file__), "ldscript_broken2.so")
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to