[pypy-commit] pypy numpy-pickle: Merge default

rguillebert noreply at buildbot.pypy.org
Thu May 23 18:38:27 CEST 2013


Author: Romain Guillebert <romain.py at gmail.com>
Branch: numpy-pickle
Changeset: r64514:75782b4f223f
Date: 2013-05-23 17:29 +0200
http://bitbucket.org/pypy/pypy/changeset/75782b4f223f/

Log:	Merge default

diff too long, truncating to 2000 out of 12012 lines

diff --git a/lib-python/2.7/distutils/sysconfig.py b/lib-python/2.7/distutils/sysconfig.py
--- a/lib-python/2.7/distutils/sysconfig.py
+++ b/lib-python/2.7/distutils/sysconfig.py
@@ -1,30 +1,16 @@
-"""Provide access to Python's configuration information.  The specific
-configuration variables available depend heavily on the platform and
-configuration.  The values may be retrieved using
-get_config_var(name), and the list of variables is available via
-get_config_vars().keys().  Additional convenience functions are also
-available.
-
-Written by:   Fred L. Drake, Jr.
-Email:        <fdrake at acm.org>
-"""
-
-__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $"
-
-import sys
-
 
 # The content of this file is redirected from
 # sysconfig_cpython or sysconfig_pypy.
+# All underscore names are imported too, because
+# people like to use undocumented sysconfig._xxx
+# directly.
 
+import sys
 if '__pypy__' in sys.builtin_module_names:
-    from distutils.sysconfig_pypy import *
-    from distutils.sysconfig_pypy import _config_vars # needed by setuptools
-    from distutils.sysconfig_pypy import _variable_rx # read_setup_file()
+    from distutils import sysconfig_pypy as _sysconfig_module
 else:
-    from distutils.sysconfig_cpython import *
-    from distutils.sysconfig_cpython import _config_vars # needed by setuptools
-    from distutils.sysconfig_cpython import _variable_rx # read_setup_file()
+    from distutils import sysconfig_cpython as _sysconfig_module
+globals().update(_sysconfig_module.__dict__)
 
 _USE_CLANG = None
 
diff --git a/lib-python/2.7/distutils/sysconfig_cpython.py b/lib-python/2.7/distutils/sysconfig_cpython.py
--- a/lib-python/2.7/distutils/sysconfig_cpython.py
+++ b/lib-python/2.7/distutils/sysconfig_cpython.py
@@ -9,7 +9,7 @@
 Email:        <fdrake at acm.org>
 """
 
-__revision__ = "$Id$"
+__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $"
 
 import os
 import re
diff --git a/lib-python/2.7/distutils/sysconfig_pypy.py b/lib-python/2.7/distutils/sysconfig_pypy.py
--- a/lib-python/2.7/distutils/sysconfig_pypy.py
+++ b/lib-python/2.7/distutils/sysconfig_pypy.py
@@ -1,6 +1,15 @@
-"""PyPy's minimal configuration information.
+"""Provide access to Python's configuration information.
+This is actually PyPy's minimal configuration information.
+
+The specific configuration variables available depend heavily on the
+platform and configuration.  The values may be retrieved using
+get_config_var(name), and the list of variables is available via
+get_config_vars().keys().  Additional convenience functions are also
+available.
 """
 
+__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $"
+
 import sys
 import os
 import imp
diff --git a/lib-python/2.7/socket.py b/lib-python/2.7/socket.py
--- a/lib-python/2.7/socket.py
+++ b/lib-python/2.7/socket.py
@@ -324,7 +324,12 @@
                 if self._close:
                     self._sock.close()
                 else:
-                    self._sock._decref_socketios()
+                    try:
+                        self._sock._decref_socketios()
+                    except AttributeError:
+                        pass  # bah, someone built a _fileobject manually
+                              # with some unexpected replacement of the
+                              # _socketobject class
             self._sock = None
 
     def __del__(self):
diff --git a/lib-python/2.7/test/test_codecs.py b/lib-python/2.7/test/test_codecs.py
--- a/lib-python/2.7/test/test_codecs.py
+++ b/lib-python/2.7/test/test_codecs.py
@@ -2,7 +2,11 @@
 import unittest
 import codecs
 import locale
-import sys, StringIO, _testcapi
+import sys, StringIO
+try:
+    import _testcapi
+except ImportError:
+    _testcapi = None
 
 class Queue(object):
     """
@@ -1387,7 +1391,7 @@
                     decodedresult += reader.read()
                 self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding))
 
-            if encoding not in broken_incremental_coders:
+            if encoding not in broken_incremental_coders and _testcapi:
                 # check incremental decoder/encoder (fetched via the Python
                 # and C API) and iterencode()/iterdecode()
                 try:
diff --git a/lib-python/2.7/test/test_sysconfig.py b/lib-python/2.7/test/test_sysconfig.py
--- a/lib-python/2.7/test/test_sysconfig.py
+++ b/lib-python/2.7/test/test_sysconfig.py
@@ -7,7 +7,8 @@
 import subprocess
 from copy import copy, deepcopy
 
-from test.test_support import run_unittest, TESTFN, unlink, get_attribute
+from test.test_support import (run_unittest, TESTFN, unlink, get_attribute,
+                               import_module)
 
 import sysconfig
 from sysconfig import (get_paths, get_platform, get_config_vars,
@@ -236,7 +237,10 @@
 
     def test_get_config_h_filename(self):
         config_h = sysconfig.get_config_h_filename()
-        self.assertTrue(os.path.isfile(config_h), config_h)
+        # import_module skips the test when the CPython C Extension API
+        # appears to not be supported
+        self.assertTrue(os.path.isfile(config_h) or
+                        not import_module('_testcapi'), config_h)
 
     def test_get_scheme_names(self):
         wanted = ('nt', 'nt_user', 'os2', 'os2_home', 'osx_framework_user',
diff --git a/lib-python/2.7/test/test_traceback.py b/lib-python/2.7/test/test_traceback.py
--- a/lib-python/2.7/test/test_traceback.py
+++ b/lib-python/2.7/test/test_traceback.py
@@ -1,6 +1,9 @@
 """Test cases for traceback module"""
 
-from _testcapi import traceback_print
+try:
+    from _testcapi import traceback_print
+except ImportError:
+    traceback_print = None
 from StringIO import StringIO
 import sys
 import unittest
@@ -176,6 +179,8 @@
 class TracebackFormatTests(unittest.TestCase):
 
     def test_traceback_format(self):
+        if traceback_print is None:
+            raise unittest.SkipTest('Requires _testcapi')
         try:
             raise KeyError('blah')
         except KeyError:
diff --git a/lib-python/2.7/test/test_unicode.py b/lib-python/2.7/test/test_unicode.py
--- a/lib-python/2.7/test/test_unicode.py
+++ b/lib-python/2.7/test/test_unicode.py
@@ -1609,7 +1609,10 @@
         self.assertEqual("{}".format(u), '__unicode__ overridden')
 
     def test_encode_decimal(self):
-        from _testcapi import unicode_encodedecimal
+        try:
+            from _testcapi import unicode_encodedecimal
+        except ImportError:
+            raise unittest.SkipTest('Requires _testcapi')
         self.assertEqual(unicode_encodedecimal(u'123'),
                          b'123')
         self.assertEqual(unicode_encodedecimal(u'\u0663.\u0661\u0664'),
diff --git a/lib-python/conftest.py b/lib-python/conftest.py
--- a/lib-python/conftest.py
+++ b/lib-python/conftest.py
@@ -130,7 +130,7 @@
     RegrTest('test_bz2.py', usemodules='bz2'),
     RegrTest('test_calendar.py'),
     RegrTest('test_call.py', core=True),
-    RegrTest('test_capi.py'),
+    RegrTest('test_capi.py', usemodules='cpyext'),
     RegrTest('test_cd.py'),
     RegrTest('test_cfgparser.py'),
     RegrTest('test_cgi.py'),
@@ -177,7 +177,7 @@
     RegrTest('test_cprofile.py'),
     RegrTest('test_crypt.py', usemodules='crypt'),
     RegrTest('test_csv.py', usemodules='_csv'),
-    RegrTest('test_ctypes.py', usemodules="_rawffi thread"),
+    RegrTest('test_ctypes.py', usemodules="_rawffi thread cpyext"),
     RegrTest('test_curses.py'),
     RegrTest('test_datetime.py', usemodules='binascii struct'),
     RegrTest('test_dbm.py'),
diff --git a/lib_pypy/_testcapi.py b/lib_pypy/_testcapi.py
--- a/lib_pypy/_testcapi.py
+++ b/lib_pypy/_testcapi.py
@@ -54,4 +54,9 @@
     fp, filename, description = imp.find_module('_testcapi', path=[output_dir])
     imp.load_module('_testcapi', fp, filename, description)
 
-compile_shared()
+try:
+    import cpyext
+except ImportError:
+    raise ImportError("No module named '_testcapi'")
+else:
+    compile_shared()
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -121,12 +121,10 @@
                     __import__(name)
             except (ImportError, CompilationError, py.test.skip.Exception), e:
                 errcls = e.__class__.__name__
-                config.add_warning(
+                raise Exception(
                     "The module %r is disabled\n" % (modname,) +
                     "because importing %s raised %s\n" % (name, errcls) +
                     str(e))
-                raise ConflictConfigError("--withmod-%s: %s" % (modname,
-                                                                errcls))
         return validator
     else:
         return None
@@ -217,10 +215,6 @@
                    "(the empty string and potentially single-char strings)",
                    default=False),
 
-        BoolOption("withsmalltuple",
-                   "use small tuples",
-                   default=False),
-
         BoolOption("withspecialisedtuple",
                    "use specialised tuples",
                    default=False),
@@ -365,6 +359,7 @@
     # ignore names from 'essential_modules', notably 'exceptions', which
     # may not be present in config.objspace.usemodules at all
     modules = [name for name in modules if name not in essential_modules]
+
     config.objspace.usemodules.suggest(**dict.fromkeys(modules, True))
 
 def enable_translationmodules(config):
diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst
--- a/pypy/doc/coding-guide.rst
+++ b/pypy/doc/coding-guide.rst
@@ -339,8 +339,9 @@
 
 + methods and other class attributes do not change after startup
 + single inheritance is fully supported
-+ simple mixins work too, but the mixed in class needs a ``_mixin_ = True``
-  class attribute
++ simple mixins somewhat work too, but the mixed in class needs a
+  ``_mixin_ = True`` class attribute. isinstance checks against the
+  mixin type will fail when translated.
 
 + classes are first-class objects too
 
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -47,7 +47,7 @@
 # The short X.Y version.
 version = '2.0'
 # The full version, including alpha/beta/rc tags.
-release = '2.0.0'
+release = '2.0.2'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/pypy/doc/how-to-contribute.rst b/pypy/doc/how-to-contribute.rst
--- a/pypy/doc/how-to-contribute.rst
+++ b/pypy/doc/how-to-contribute.rst
@@ -28,7 +28,8 @@
 Layers
 ------
 
-PyPy has layers. Those layers help us keep the respective parts separated enough
+PyPy has layers. Just like Ogres or onions.
+Those layers help us keep the respective parts separated enough
 to be worked on independently and make the complexity manageable. This is,
 again, just a sanity requirement for such a complex project. For example writing
 a new optimization for the JIT usually does **not** involve touching a Python
diff --git a/pypy/doc/how-to-release.rst b/pypy/doc/how-to-release.rst
--- a/pypy/doc/how-to-release.rst
+++ b/pypy/doc/how-to-release.rst
@@ -22,7 +22,8 @@
   will capture the revision number of this change for the release;
   some of the next updates may be done before or after branching; make
   sure things are ported back to the trunk and to the branch as
-  necessary
+  necessary; also update the version number in pypy/doc/conf.py,
+  and in pypy/doc/index.rst
 * update pypy/doc/contributor.rst (and possibly LICENSE)
 * rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst
   and create a fresh whatsnew_head.rst after the release
diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst
--- a/pypy/doc/index.rst
+++ b/pypy/doc/index.rst
@@ -40,7 +40,7 @@
 
 * `FAQ`_: some frequently asked questions.
 
-* `Release 2.0`_: the latest official release
+* `Release 2.0.2`_: the latest official release
 
 * `PyPy Blog`_: news and status info about PyPy 
 
@@ -110,7 +110,7 @@
 .. _`Getting Started`: getting-started.html
 .. _`Papers`: extradoc.html
 .. _`Videos`: video-index.html
-.. _`Release 2.0`: http://pypy.org/download.html
+.. _`Release 2.0.2`: http://pypy.org/download.html
 .. _`speed.pypy.org`: http://speed.pypy.org
 .. _`RPython toolchain`: translation.html
 .. _`potential project ideas`: project-ideas.html
diff --git a/pypy/doc/release-2.0.1.rst b/pypy/doc/release-2.0.1.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-2.0.1.rst
@@ -0,0 +1,46 @@
+==============================
+PyPy 2.0.1 - Bohr Smørrebrød
+==============================
+
+We're pleased to announce PyPy 2.0.1.  This is a stable bugfix release
+over `2.0`_.  You can download it here:
+  
+    http://pypy.org/download.html
+
+The fixes are mainly about fatal errors or crashes in our stdlib.  See
+below for more details.
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 64 or
+Windows 32.  Support for ARM is progressing but not bug-free yet.
+
+.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org
+
+Highlights
+==========
+
+- fix an occasional crash in the JIT that ends in `RPython Fatal error:
+  NotImplementedError`__.
+
+- `id(x)` is now always a positive number (except on int/float/long/complex).
+  This fixes an issue in ``_sqlite.py`` (mostly for 32-bit Linux).
+
+- fix crashes of callback-from-C-functions (with cffi) when used together
+  with Stackless features, on asmgcc (i.e. Linux only).  Now `gevent should
+  work better`__.
+
+- work around an eventlet issue with `socket._decref_socketios()`__.
+
+.. __: https://bugs.pypy.org/issue1482
+.. __: http://mail.python.org/pipermail/pypy-dev/2013-May/011362.html
+.. __: https://bugs.pypy.org/issue1468
+.. _2.0: release-2.0.0.html
+
+Cheers,
+arigo et. al. for the PyPy team
diff --git a/pypy/doc/release-2.0.2.rst b/pypy/doc/release-2.0.2.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-2.0.2.rst
@@ -0,0 +1,46 @@
+=========================
+PyPy 2.0.2 - Fermi Panini
+=========================
+
+We're pleased to announce PyPy 2.0.2.  This is a stable bugfix release
+over `2.0`_ and `2.0.1`_.  You can download it here:
+
+    http://pypy.org/download.html
+
+It fixes a crash in the JIT when calling external C functions (with
+ctypes/cffi) in a multithreaded context.
+
+.. _2.0: release-2.0.0.html
+.. _2.0.1: release-2.0.1.html
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 64 or
+Windows 32.  Support for ARM is progressing but not bug-free yet.
+
+.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org
+
+Highlights
+==========
+
+This release contains only the fix described above.  A crash (or wrong
+results) used to occur if all these conditions were true:
+
+- your program is multithreaded;
+
+- it runs on a single-core machine or a heavily-loaded multi-core one;
+
+- it uses ctypes or cffi to issue external calls to C functions.
+
+This was fixed in the branch `emit-call-x86`__ (see the example file
+``bug1.py``).
+
+.. __: https://bitbucket.org/pypy/pypy/commits/7c80121abbf4
+
+Cheers,
+arigo et. al. for the PyPy team
diff --git a/pypy/doc/test/test_whatsnew.py b/pypy/doc/test/test_whatsnew.py
--- a/pypy/doc/test/test_whatsnew.py
+++ b/pypy/doc/test/test_whatsnew.py
@@ -19,23 +19,28 @@
     branches.discard('default')
     return startrev, branches
 
-def get_merged_branches(path, startrev, endrev):
-    if getstatusoutput('hg root')[0]:
+def get_merged_branches(path, startrev, endrev, current_branch=None):
+    errcode, wc_branch = getstatusoutput('hg branch')
+    if errcode != 0:
         py.test.skip('no Mercurial repo')
+    if current_branch is None:
+        current_branch = wc_branch
 
     # X = take all the merges which are descendants of startrev and are on default
     # revset = all the parents of X which are not on default
     # ===>
     # revset contains all the branches which have been merged to default since
     # startrev
-    revset = 'parents(%s::%s and \
+    revset = "parents(%s::%s and \
                       merge() and \
-                      branch(default)) and \
-              not branch(default)' % (startrev, endrev)
+                      branch('%s')) and \
+              not branch('%s')" % (startrev, endrev,
+                                   current_branch, current_branch)
     cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset)
     out = getoutput(cmd)
     branches = set(map(str.strip, out.splitlines()))
-    return branches
+    branches.discard("default")
+    return branches, current_branch
 
 
 def test_parse_doc():
@@ -65,7 +70,8 @@
     assert branches == set(['foobar', 'hello'])
 
 def test_get_merged_branches():
-    branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93')
+    branches, _ = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93',
+                                      'default')
     assert branches == set(['numpy-indexing-by-arrays-bool',
                             'better-jit-hooks-2',
                             'numpypy-ufuncs'])
@@ -76,7 +82,9 @@
     whatsnew_list.sort()
     last_whatsnew = whatsnew_list[-1].read()
     startrev, documented = parse_doc(last_whatsnew)
-    merged = get_merged_branches(ROOT, startrev, '')
+    merged, branch = get_merged_branches(ROOT, startrev, '')
+    merged.discard('default')
+    merged.discard('')
     not_documented = merged.difference(documented)
     not_merged = documented.difference(merged)
     print 'Branches merged but not documented:'
@@ -85,4 +93,6 @@
     print 'Branches documented but not merged:'
     print '\n'.join(not_merged)
     print
-    assert not not_documented and not not_merged
+    assert not not_documented
+    if branch == 'default':
+        assert not not_merged
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
@@ -8,5 +8,29 @@
 .. branch: numpy-pickle
 Pickling of numpy arrays and dtypes (including record dtypes)
 
+.. branch: remove-array-smm
+Remove multimethods in the arraymodule
+
+.. branch: callback-stacklet
+Fixed bug when switching stacklets from a C callback
+
+.. branch: remove-set-smm
+Remove multi-methods on sets
+
 .. branch: numpy-subarrays
-It is now possible to create arrays and dtypes that use subarrays
+Implement subarrays for numpy
+
+.. branch: remove-dict-smm
+Remove multi-methods on dict
+
+.. branch: remove-list-smm-2
+Remove remaining multi-methods on list
+
+.. branch: arm-stacklet
+Stacklet support for ARM, enables _continuation support
+
+.. branch: remove-tuple-smm
+Remove multi-methods on tuple
+
+.. branch: remove-iter-smm
+Remove multi-methods on iterators
diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -10,6 +10,8 @@
 from rpython.config.config import ConflictConfigError
 from pypy.tool.option import make_objspace
 from pypy.conftest import pypydir
+from rpython.rlib import rthread
+from pypy.module.thread import os_thread
 
 thisdir = py.path.local(__file__).dirpath()
 
@@ -120,6 +122,17 @@
         source = rffi.charp2str(ll_source)
         return _pypy_execute_source(source)
 
+    @entrypoint('main', [], c_name='pypy_init_threads')
+    def pypy_init_threads():
+        if space.config.objspace.usemodules.thread:
+            os_thread.setup_threads(space)
+            rffi.aroundstate.before()
+
+    @entrypoint('main', [], c_name='pypy_thread_attach')
+    def pypy_thread_attach():
+        if space.config.objspace.usemodules.thread:
+            rthread.gc_thread_start()
+
     w_globals = space.newdict()
     space.setitem(w_globals, space.wrap('__builtins__'),
                   space.builtin_modules['__builtin__'])
@@ -137,6 +150,8 @@
         return 0
 
     return entry_point, {'pypy_execute_source': pypy_execute_source,
+                         'pypy_init_threads': pypy_init_threads,
+                         'pypy_thread_attach': pypy_thread_attach,
                          'pypy_setup_home': pypy_setup_home}
 
 def call_finish(space):
diff --git a/pypy/interpreter/astcompiler/codegen.py b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -853,9 +853,10 @@
             self.emit_jump(ops.JUMP_IF_FALSE_OR_POP, cleanup, True)
             if i < (ops_count - 1):
                 comp.comparators[i].walkabout(self)
-        comp.comparators[-1].walkabout(self)
-        last_kind = compare_operations(comp.ops[-1])
-        self.emit_op_arg(ops.COMPARE_OP, last_kind)
+        last_op, last_comparator = comp.ops[-1], comp.comparators[-1]
+        if not self._optimize_comparator(last_op, last_comparator):
+            last_comparator.walkabout(self)
+        self.emit_op_arg(ops.COMPARE_OP, compare_operations(last_op))
         if ops_count > 1:
             end = self.new_block()
             self.emit_jump(ops.JUMP_FORWARD, end)
@@ -864,6 +865,37 @@
             self.emit_op(ops.POP_TOP)
             self.use_next_block(end)
 
+    def _optimize_comparator(self, op, node):
+        """Fold lists/sets of constants in the context of "in"/"not in".
+
+        lists are folded into tuples, sets into frozensets, otherwise
+        returns False
+        """
+        if op in (ast.In, ast.NotIn):
+            is_list = isinstance(node, ast.List)
+            if is_list or isinstance(node, ast.Set):
+                w_const = self._tuple_of_consts(node.elts)
+                if w_const is not None:
+                    if not is_list:
+                        from pypy.objspace.std.setobject import (
+                            W_FrozensetObject)
+                        w_const = W_FrozensetObject(self.space, w_const)
+                    self.load_const(w_const)
+                    return True
+        return False
+
+    def _tuple_of_consts(self, elts):
+        """Return a tuple of consts from elts if possible, or None"""
+        count = len(elts) if elts is not None else 0
+        consts_w = [None] * count
+        for i in range(count):
+            w_value = elts[i].as_constant()
+            if w_value is None:
+                # Not all constants
+                return None
+            consts_w[i] = w_value
+        return self.space.newtuple(consts_w)
+
     def visit_IfExp(self, ifexp):
         self.update_position(ifexp.lineno)
         end = self.new_block()
diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py
--- a/pypy/interpreter/astcompiler/test/test_compiler.py
+++ b/pypy/interpreter/astcompiler/test/test_compiler.py
@@ -973,3 +973,30 @@
         counts = self.count_instructions(source3)
         assert counts[ops.BUILD_LIST] == 1
         assert ops.BUILD_LIST_FROM_ARG not in counts
+
+    def test_folding_of_list_constants(self):
+        for source in (
+            # in/not in constants with BUILD_LIST should be folded to a tuple:
+            'a in [1,2,3]',
+            'a not in ["a","b","c"]',
+            'a in [None, 1, None]',
+            'a not in [(1, 2), 3, 4]',
+            ):
+            source = 'def f(): %s' % source
+            counts = self.count_instructions(source)
+            assert ops.BUILD_LIST not in counts
+            assert ops.LOAD_CONST in counts
+
+    def test_folding_of_set_constants(self):
+        for source in (
+            # in/not in constants with BUILD_SET should be folded to a frozenset:
+            'a in {1,2,3}',
+            'a not in {"a","b","c"}',
+            'a in {None, 1, None}',
+            'a not in {(1, 2), 3, 4}',
+            'a in {1, 2, 3, 3, 2, 1}',
+            ):
+            source = 'def f(): %s' % source
+            counts = self.count_instructions(source)
+            assert ops.BUILD_SET not in counts
+            assert ops.LOAD_CONST in counts
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -242,6 +242,11 @@
     def __spacebind__(self, space):
         return self
 
+    def unwrap(self, space):
+        """NOT_RPYTHON"""
+        # _____ this code is here to support testing only _____
+        return self
+
 
 class W_InterpIterable(W_Root):
     def __init__(self, space, w_iterable):
diff --git a/pypy/interpreter/test/test_app_main.py b/pypy/interpreter/test/test_app_main.py
--- a/pypy/interpreter/test/test_app_main.py
+++ b/pypy/interpreter/test/test_app_main.py
@@ -903,22 +903,33 @@
         expected_path = [str(prefix.join(subdir).ensure(dir=1))
                          for subdir in ('lib_pypy',
                                         'lib-python/%s' % cpy_ver)]
+        # an empty directory from where we can't find the stdlib
+        tmp_dir = str(udir.join('tmp').ensure(dir=1))
 
         self.w_goal_dir = self.space.wrap(goal_dir)
         self.w_fake_exe = self.space.wrap(str(fake_exe))
         self.w_expected_path = self.space.wrap(expected_path)
         self.w_trunkdir = self.space.wrap(os.path.dirname(pypydir))
 
+        self.w_tmp_dir = self.space.wrap(tmp_dir)
+
         foo_py = prefix.join('foo.py').write("pass")
         self.w_foo_py = self.space.wrap(str(foo_py))
 
     def test_setup_bootstrap_path(self):
-        import sys
+        # Check how sys.path is handled depending on if we can find a copy of
+        # the stdlib in setup_bootstrap_path.
+        import sys, os
         old_sys_path = sys.path[:]
+        old_cwd = os.getcwd()
+
         sys.path.append(self.goal_dir)
+        # make sure cwd does not contain a stdlib
+        os.chdir(self.tmp_dir)
+        tmp_pypy_c = os.path.join(self.tmp_dir, 'pypy-c')
         try:
             import app_main
-            app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found
+            app_main.setup_bootstrap_path(tmp_pypy_c)  # stdlib not found
             assert sys.executable == ''
             assert sys.path == old_sys_path + [self.goal_dir]
 
@@ -933,6 +944,7 @@
             assert newpath[:len(self.expected_path)] == self.expected_path
         finally:
             sys.path[:] = old_sys_path
+            os.chdir(old_cwd)
 
     def test_trunk_can_be_prefix(self):
         import sys
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
@@ -936,6 +936,21 @@
         output = s.getvalue()
         assert "LOAD_GLOBAL" not in output
 
+    def test_folding_of_list_constants(self):
+        source = 'a in [1, 2, 3]'
+        co = compile(source, '', 'exec')
+        i = co.co_consts.index((1, 2, 3))
+        assert i > -1
+        assert isinstance(co.co_consts[i], tuple)
+
+    def test_folding_of_set_constants(self):
+        source = 'a in {1, 2, 3}'
+        co = compile(source, '', 'exec')
+        i = co.co_consts.index(set([1, 2, 3]))
+        assert i > -1
+        assert isinstance(co.co_consts[i], frozenset)
+
+
 class AppTestCallMethod(object):
     spaceconfig = {'objspace.opcodes.CALL_METHOD': True}
         
diff --git a/pypy/module/_cffi_backend/__init__.py b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -7,7 +7,7 @@
     appleveldefs = {
         }
     interpleveldefs = {
-        '__version__': 'space.wrap("0.6")',
+        '__version__': 'space.wrap("0.7")',
 
         'load_library': 'libraryobj.load_library',
 
@@ -30,6 +30,8 @@
         'typeoffsetof': 'func.typeoffsetof',
         'rawaddressof': 'func.rawaddressof',
         'getcname': 'func.getcname',
+        'newp_handle': 'handle.newp_handle',
+        'from_handle': 'handle.from_handle',
         '_get_types': 'func._get_types',
 
         'string': 'func.string',
diff --git a/pypy/module/_cffi_backend/cdataobj.py b/pypy/module/_cffi_backend/cdataobj.py
--- a/pypy/module/_cffi_backend/cdataobj.py
+++ b/pypy/module/_cffi_backend/cdataobj.py
@@ -114,8 +114,11 @@
     ge = _make_comparison('ge')
 
     def hash(self):
-        h = (objectmodel.compute_identity_hash(self.ctype) ^
-             rffi.cast(lltype.Signed, self._cdata))
+        h = rffi.cast(lltype.Signed, self._cdata)
+        # To hash pointers in dictionaries.  Assumes that h shows some
+        # alignment (to 4, 8, maybe 16 bytes), so we use the following
+        # formula to avoid the trailing bits being always 0.
+        h = h ^ (h >> 4)
         return self.space.wrap(h)
 
     def getitem(self, w_index):
@@ -391,6 +394,19 @@
         return self.length
 
 
+class W_CDataHandle(W_CData):
+    _attrs_ = ['w_keepalive']
+    _immutable_fields_ = ['w_keepalive']
+
+    def __init__(self, space, cdata, ctype, w_keepalive):
+        W_CData.__init__(self, space, cdata, ctype)
+        self.w_keepalive = w_keepalive
+
+    def _repr_extra(self):
+        w_repr = self.space.repr(self.w_keepalive)
+        return "handle to %s" % (self.space.str_w(w_repr),)
+
+
 W_CData.typedef = TypeDef(
     'CData',
     __module__ = '_cffi_backend',
diff --git a/pypy/module/_cffi_backend/ctypeptr.py b/pypy/module/_cffi_backend/ctypeptr.py
--- a/pypy/module/_cffi_backend/ctypeptr.py
+++ b/pypy/module/_cffi_backend/ctypeptr.py
@@ -172,8 +172,8 @@
 
 
 class W_CTypePointer(W_CTypePtrBase):
-    _attrs_ = ['is_file', 'cache_array_type']
-    _immutable_fields_ = ['is_file', 'cache_array_type?']
+    _attrs_ = ['is_file', 'cache_array_type', 'is_void_ptr']
+    _immutable_fields_ = ['is_file', 'cache_array_type?', 'is_void_ptr']
     kind = "pointer"
     cache_array_type = None
 
@@ -186,6 +186,7 @@
             extra = " *"
         self.is_file = (ctitem.name == "struct _IO_FILE" or
                         ctitem.name == "struct $FILE")
+        self.is_void_ptr = isinstance(ctitem, ctypevoid.W_CTypeVoid)
         W_CTypePtrBase.__init__(self, space, size, extra, 2, ctitem)
 
     def newp(self, w_init):
diff --git a/pypy/module/_cffi_backend/handle.py b/pypy/module/_cffi_backend/handle.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/handle.py
@@ -0,0 +1,93 @@
+import weakref
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.gateway import unwrap_spec
+from pypy.module._cffi_backend import ctypeobj, ctypeptr, cdataobj
+from pypy.module._weakref.interp__weakref import dead_ref
+from rpython.rtyper.lltypesystem import lltype, rffi
+
+
+def reduced_value(s):
+    while True:
+        divide = s & 1
+        s >>= 1
+        if not divide:
+            return s
+
+# ____________________________________________________________
+
+
+class CffiHandles:
+    def __init__(self, space):
+        self.handles = []
+        self.look_distance = 0
+
+    def reserve_next_handle_index(self):
+        # The reservation ordering done here is tweaked for pypy's
+        # memory allocator.  We look from index 'look_distance'.
+        # Look_distance increases from 0.  But we also look at
+        # "look_distance/2" or "/4" or "/8", etc.  If we find that one
+        # of these secondary locations is free, we assume it's because
+        # there was recently a minor collection; so we reset
+        # look_distance to 0 and start again from the lowest locations.
+        length = len(self.handles)
+        for d in range(self.look_distance, length):
+            if self.handles[d]() is None:
+                self.look_distance = d + 1
+                return d
+            s = reduced_value(d)
+            if self.handles[s]() is None:
+                break
+        # restart from the beginning
+        for d in range(0, length):
+            if self.handles[d]() is None:
+                self.look_distance = d + 1
+                return d
+        # full! extend, but don't use '!=' here
+        self.handles = self.handles + [dead_ref] * (length // 3 + 5)
+        self.look_distance = length + 1
+        return length
+
+    def store_handle(self, index, content):
+        self.handles[index] = weakref.ref(content)
+
+    def fetch_handle(self, index):
+        if 0 <= index < len(self.handles):
+            return self.handles[index]()
+        return None
+
+def get(space):
+    return space.fromcache(CffiHandles)
+
+# ____________________________________________________________
+
+ at unwrap_spec(w_ctype=ctypeobj.W_CType)
+def newp_handle(space, w_ctype, w_x):
+    if (not isinstance(w_ctype, ctypeptr.W_CTypePointer) or
+        not w_ctype.is_void_ptr):
+        raise operationerrfmt(space.w_TypeError,
+                              "needs 'void *', got '%s'", w_ctype.name)
+    index = get(space).reserve_next_handle_index()
+    _cdata = rffi.cast(rffi.CCHARP, index + 1)
+    new_cdataobj = cdataobj.W_CDataHandle(space, _cdata, w_ctype, w_x)
+    get(space).store_handle(index, new_cdataobj)
+    return new_cdataobj
+
+ at unwrap_spec(w_cdata=cdataobj.W_CData)
+def from_handle(space, w_cdata):
+    ctype = w_cdata.ctype
+    if (not isinstance(ctype, ctypeptr.W_CTypePtrOrArray) or
+        not ctype.can_cast_anything):
+        raise operationerrfmt(space.w_TypeError,
+                              "expected a 'cdata' object with a 'void *' out "
+                              "of new_handle(), got '%s'", ctype.name)
+    index = rffi.cast(lltype.Signed, w_cdata._cdata)
+    original_cdataobj = get(space).fetch_handle(index - 1)
+    #
+    if isinstance(original_cdataobj, cdataobj.W_CDataHandle):
+        return original_cdataobj.w_keepalive
+    else:
+        if index == 0:
+            msg = "cannot use from_handle() on NULL pointer"
+        else:
+            msg = "'void *' value does not correspond to any object"
+        raise OperationError(space.w_RuntimeError, space.wrap(msg))
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -365,8 +365,9 @@
     BInt = new_primitive_type("int")
     BFloat = new_primitive_type("float")
     for i in range(1, 20):
-        if (hash(cast(BChar, chr(i))) !=
-            hash(cast(BInt, i))):
+        x1 = cast(BChar, chr(i))
+        x2 = cast(BInt, i)
+        if hash(x1) != hash(x2):
             break
     else:
         raise AssertionError("hashes are equal")
@@ -2723,6 +2724,40 @@
     assert x.__name__ == '<cdata>'
     assert hasattr(x, '__doc__')
 
+def test_different_types_of_ptr_equality():
+    BVoidP = new_pointer_type(new_void_type())
+    BIntP = new_pointer_type(new_primitive_type("int"))
+    x = cast(BVoidP, 12345)
+    assert x == cast(BIntP, 12345)
+    assert x != cast(BIntP, 12344)
+    assert hash(x) == hash(cast(BIntP, 12345))
+
+def test_new_handle():
+    import _weakref
+    BVoidP = new_pointer_type(new_void_type())
+    BCharP = new_pointer_type(new_primitive_type("char"))
+    class mylist(list):
+        pass
+    o = mylist([2, 3, 4])
+    x = newp_handle(BVoidP, o)
+    assert repr(x) == "<cdata 'void *' handle to [2, 3, 4]>"
+    assert x
+    assert from_handle(x) is o
+    assert from_handle(cast(BCharP, x)) is o
+    wr = _weakref.ref(o)
+    del o
+    import gc; gc.collect()
+    assert wr() is not None
+    assert from_handle(x) == list((2, 3, 4))
+    assert from_handle(cast(BCharP, x)) == list((2, 3, 4))
+    del x
+    for i in range(3):
+        if wr() is not None:
+            import gc; gc.collect()
+    assert wr() is None
+    py.test.raises(RuntimeError, from_handle, cast(BCharP, 0))
+
+
 def test_version():
     # this test is here mostly for PyPy
-    assert __version__ == "0.6"
+    assert __version__ == "0.7"
diff --git a/pypy/module/_cffi_backend/test/test_handle.py b/pypy/module/_cffi_backend/test/test_handle.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/_cffi_backend/test/test_handle.py
@@ -0,0 +1,59 @@
+import random
+from pypy.module._cffi_backend.handle import CffiHandles, reduced_value
+
+
+def test_reduced_value():
+    assert reduced_value(0) == 0
+    assert reduced_value(1) == 0
+    assert reduced_value(2) == 1
+    assert reduced_value(3) == 0
+    assert reduced_value(4) == 2
+    assert reduced_value(5) == 1
+    assert reduced_value(6) == 3
+    assert reduced_value(7) == 0
+    assert reduced_value(8) == 4
+    assert reduced_value(9) == 2
+    assert reduced_value(10) == 5
+    assert reduced_value(11) == 1
+
+
+class PseudoWeakRef(object):
+    _content = 42
+
+    def __call__(self):
+        return self._content
+
+
+def test_cffi_handles_1():
+    ch = CffiHandles(None)
+    expected_content = {}
+    for i in range(10000):
+        index = ch.reserve_next_handle_index()
+        assert 0 <= index < len(ch.handles)
+        assert ch.handles[index]() is None
+        pwr = PseudoWeakRef()
+        expected_content[index] = pwr
+        ch.handles[index] = pwr
+    assert len(ch.handles) < 13500
+    for index, pwr in expected_content.items():
+        assert ch.handles[index] is pwr
+
+def test_cffi_handles_2():
+    ch = CffiHandles(None)
+    expected_content = {}
+    for i in range(10000):
+        index = ch.reserve_next_handle_index()
+        assert 0 <= index < len(ch.handles)
+        assert ch.handles[index]() is None
+        pwr = PseudoWeakRef()
+        expected_content[index] = pwr
+        ch.handles[index] = pwr
+        #
+        if len(expected_content) > 20:
+            r = random.choice(list(expected_content))
+            pwr = expected_content.pop(r)
+            pwr._content = None
+        #
+    assert len(ch.handles) < 100
+    for index, pwr in expected_content.items():
+        assert ch.handles[index] is pwr
diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py
--- a/pypy/module/_ffi/test/test_funcptr.py
+++ b/pypy/module/_ffi/test/test_funcptr.py
@@ -74,9 +74,9 @@
         from _ffi import CDLL, types
         # this should return *all* loaded libs, dlopen(NULL)
         dll = CDLL(None)
-        # Assume CPython, or PyPy compiled with cpyext
-        res = dll.getfunc('Py_IsInitialized', [], types.slong)()
-        assert res == 1
+        # libm should be loaded
+        res = dll.getfunc('sqrt', [types.double], types.double)(1.0)
+        assert res == 1.0
 
     def test_callfunc(self):
         from _ffi import CDLL, types
@@ -139,7 +139,7 @@
 
     def test_pointer_args(self):
         """
-            extern int dummy; // defined in test_void_result 
+            extern int dummy; // defined in test_void_result
             DLLEXPORT int* get_dummy_ptr() { return &dummy; }
             DLLEXPORT void set_val_to_ptr(int* ptr, int val) { *ptr = val; }
         """
@@ -158,7 +158,7 @@
 
     def test_convert_pointer_args(self):
         """
-            extern int dummy; // defined in test_void_result 
+            extern int dummy; // defined in test_void_result
             DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args
             DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto
         """
@@ -170,7 +170,7 @@
             def _as_ffi_pointer_(self, ffitype):
                 assert ffitype is types.void_p
                 return self.value
-        
+
         libfoo = CDLL(self.libfoo_name)
         get_dummy = libfoo.getfunc('get_dummy', [], types.sint)
         get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p)
@@ -259,7 +259,7 @@
 
     def test_typed_pointer_args(self):
         """
-            extern int dummy; // defined in test_void_result 
+            extern int dummy; // defined in test_void_result
             DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args
             DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto
         """
@@ -551,7 +551,7 @@
         from _ffi import CDLL, types
         libfoo = CDLL(self.libfoo_name)
         raises(TypeError, "libfoo.getfunc('sum_xy', [types.void], types.sint)")
-        
+
     def test_OSError_loading(self):
         from _ffi import CDLL, types
         raises(OSError, "CDLL('I do not exist')")
@@ -606,7 +606,7 @@
         from _rawffi import FUNCFLAG_STDCALL
         libm = CDLL(self.libm_name)
         pow_addr = libm.getaddressindll('pow')
-        wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow', 
+        wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow',
                 [types.double, types.double], types.double, FUNCFLAG_STDCALL)
         try:
             wrong_pow(2, 3) == 8
@@ -622,7 +622,7 @@
         from _rawffi import FUNCFLAG_STDCALL
         kernel = WinDLL('Kernel32.dll')
         sleep_addr = kernel.getaddressindll('Sleep')
-        sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint], 
+        sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint],
                             types.void, FUNCFLAG_STDCALL)
         sleep(10)
 
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
@@ -232,9 +232,9 @@
         import _rawffi
         # this should return *all* loaded libs, dlopen(NULL)
         dll = _rawffi.CDLL(None)
-        # Assume CPython, or PyPy compiled with cpyext
-        res = dll.ptr('Py_IsInitialized', [], 'l')()
-        assert res[0] == 1
+        func = dll.ptr('rand', [], 'i')
+        res = func()
+        assert res[0] != 0
 
     def test_libc_load(self):
         import _rawffi
diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py
--- a/pypy/module/cpyext/setobject.py
+++ b/pypy/module/cpyext/setobject.py
@@ -6,7 +6,6 @@
     borrow_from, make_ref, from_ref)
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
 from pypy.objspace.std.setobject import W_SetObject, newset
-from pypy.objspace.std.smalltupleobject import W_SmallTupleObject
 
 
 PySet_Check, PySet_CheckExact = build_type_checkers("Set")
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
@@ -344,7 +344,7 @@
             return
 
         @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real,
-                     error=-1, external=True) # XXX should not be exported
+                     error=-1, external=False)
         @func_renamer("cpyext_tp_setattro_%s" % (typedef.name,))
         def slot_tp_setattro(space, w_self, w_name, w_value):
             if w_value is not None:
diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py
--- a/pypy/module/micronumpy/arrayimpl/concrete.py
+++ b/pypy/module/micronumpy/arrayimpl/concrete.py
@@ -69,6 +69,7 @@
             new_backstrides = [0] * ndims
             for nd in range(ndims):
                 new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
+            assert isinstance(orig_array, W_NDimArray) or orig_array is None
             return SliceArray(self.start, new_strides, new_backstrides,
                               new_shape, self, orig_array)
         else:
@@ -356,13 +357,13 @@
         self.strides = strides
         self.backstrides = backstrides
         self.shape = shape
+        if dtype is None:
+            dtype = parent.dtype
         if isinstance(parent, SliceArray):
             parent = parent.parent # one level only
         self.parent = parent
         self.storage = parent.storage
         self.order = parent.order
-        if dtype is None:
-            dtype = parent.dtype
         self.dtype = dtype
         self.size = support.product(shape) * self.dtype.itemtype.get_element_size()
         self.start = start
diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py
--- a/pypy/module/micronumpy/arrayimpl/scalar.py
+++ b/pypy/module/micronumpy/arrayimpl/scalar.py
@@ -2,6 +2,7 @@
 from pypy.module.micronumpy.arrayimpl import base
 from pypy.module.micronumpy.base import W_NDimArray, convert_to_array
 from pypy.module.micronumpy import support
+from pypy.module.micronumpy.interp_boxes import W_GenericBox
 from pypy.interpreter.error import OperationError
 
 class ScalarIterator(base.BaseArrayIterator):
@@ -48,6 +49,7 @@
         return self.value
 
     def set_scalar_value(self, w_val):
+        assert isinstance(w_val, W_GenericBox)
         self.value = w_val.convert_to(self.dtype)
 
     def copy(self, space):
@@ -73,7 +75,7 @@
         dtype = self.dtype.float_type or self.dtype
         if len(w_arr.get_shape()) > 0:
             raise OperationError(space.w_ValueError, space.wrap(
-                "could not broadcast input array from shape " + 
+                "could not broadcast input array from shape " +
                 "(%s) into shape ()" % (
                     ','.join([str(x) for x in w_arr.get_shape()],))))
         if self.dtype.is_complex_type():
@@ -102,7 +104,7 @@
         dtype = self.dtype.float_type
         if len(w_arr.get_shape()) > 0:
             raise OperationError(space.w_ValueError, space.wrap(
-                "could not broadcast input array from shape " + 
+                "could not broadcast input array from shape " +
                 "(%s) into shape ()" % (
                     ','.join([str(x) for x in w_arr.get_shape()],))))
         self.value = self.dtype.itemtype.composite(
diff --git a/pypy/module/micronumpy/arrayimpl/sort.py b/pypy/module/micronumpy/arrayimpl/sort.py
--- a/pypy/module/micronumpy/arrayimpl/sort.py
+++ b/pypy/module/micronumpy/arrayimpl/sort.py
@@ -12,7 +12,7 @@
 from rpython.rlib.objectmodel import specialize
 from pypy.interpreter.error import OperationError
 from pypy.module.micronumpy.base import W_NDimArray
-from pypy.module.micronumpy import types
+from pypy.module.micronumpy import interp_dtype, types
 from pypy.module.micronumpy.iter import AxisIterator
 
 INT_SIZE = rffi.sizeof(lltype.Signed)
@@ -20,7 +20,7 @@
 def make_sort_function(space, itemtype, comp_type, count=1):
     TP = itemtype.T
     step = rffi.sizeof(TP)
-
+    
     class Repr(object):
         def __init__(self, index_stride_size, stride_size, size, values,
                      indexes, index_start, start):
@@ -69,13 +69,12 @@
 
     class ArgArrayRepWithStorage(Repr):
         def __init__(self, index_stride_size, stride_size, size):
-            from pypy.module.micronumpy import interp_dtype
             start = 0
             dtype = interp_dtype.get_dtype_cache(space).w_longdtype
             self.indexes = dtype.itemtype.malloc(size*dtype.get_size())
-            self.values = alloc_raw_storage(size * stride_size,
+            self.values = alloc_raw_storage(size * stride_size, 
                                             track_allocation=False)
-            Repr.__init__(self, index_stride_size, stride_size,
+            Repr.__init__(self, index_stride_size, stride_size, 
                           size, self.values, self.indexes, start, start)
 
         def __del__(self):
@@ -97,7 +96,7 @@
         for i in range(stop-start):
             retval.setitem(i, lst.getitem(i+start))
         return retval
-
+    
     if count < 2:
         def arg_lt(a, b):
             # Does numpy do <= ?
@@ -109,14 +108,13 @@
                     return True
                 elif a[0][i] > b[0][i]:
                     return False
-            # Does numpy do True?
+            # Does numpy do True?    
             return False
 
     ArgSort = make_timsort_class(arg_getitem, arg_setitem, arg_length,
                                  arg_getitem_slice, arg_lt)
 
     def argsort(arr, space, w_axis, itemsize):
-        from pypy.module.micronumpy import interp_dtype
         if w_axis is space.w_None:
             # note that it's fine ot pass None here as we're not going
             # to pass the result around (None is the link to base in slices)
@@ -182,7 +180,7 @@
 
 class SortCache(object):
     built = False
-
+    
     def __init__(self, space):
         if self.built:
             return
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
@@ -27,10 +27,10 @@
         from pypy.module.micronumpy.arrayimpl import concrete, scalar
 
         if not shape:
-            impl = scalar.Scalar(dtype)
+            impl = scalar.Scalar(dtype.base)
         else:
-            strides, backstrides = calc_strides(shape, dtype, order)
-            impl = concrete.ConcreteArray(shape, dtype, order, strides,
+            strides, backstrides = calc_strides(shape, dtype.base, order)
+            impl = concrete.ConcreteArray(shape, dtype.base, order, strides,
                                       backstrides)
         return W_NDimArray(impl)
 
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
@@ -14,6 +14,7 @@
 from pypy.module.micronumpy.interp_arrayops import where
 from pypy.module.micronumpy import interp_ufuncs
 from rpython.rlib.objectmodel import specialize, instantiate
+from rpython.rlib.nonconst import NonConstant
 
 
 class BogusBytecode(Exception):
@@ -40,6 +41,10 @@
 TWO_ARG_FUNCTIONS = ["dot", 'take']
 THREE_ARG_FUNCTIONS = ['where']
 
+class W_TypeObject(W_Root):
+    def __init__(self, name):
+        self.name = name
+
 class FakeSpace(object):
     w_ValueError = "ValueError"
     w_TypeError = "TypeError"
@@ -48,17 +53,17 @@
     w_NotImplementedError = "NotImplementedError"
     w_None = None
 
-    w_bool = "bool"
-    w_int = "int"
-    w_float = "float"
-    w_list = "list"
-    w_long = "long"
-    w_tuple = 'tuple'
-    w_slice = "slice"
-    w_str = "str"
-    w_unicode = "unicode"
-    w_complex = "complex"
-    w_dict = "dict"
+    w_bool = W_TypeObject("bool")
+    w_int = W_TypeObject("int")
+    w_float = W_TypeObject("float")
+    w_list = W_TypeObject("list")
+    w_long = W_TypeObject("long")
+    w_tuple = W_TypeObject('tuple')
+    w_slice = W_TypeObject("slice")
+    w_str = W_TypeObject("str")
+    w_unicode = W_TypeObject("unicode")
+    w_complex = W_TypeObject("complex")
+    w_dict = W_TypeObject("dict")
 
     def __init__(self):
         """NOT_RPYTHON"""
@@ -73,6 +78,13 @@
     def issequence_w(self, w_obj):
         return isinstance(w_obj, ListObject) or isinstance(w_obj, W_NDimArray)
 
+    def len(self, w_obj):
+        assert isinstance(w_obj, ListObject)
+        return self.wrap(len(w_obj.items))
+
+    def getattr(self, w_obj, w_attr):
+        return StringObject(NonConstant('foo'))
+
     def isinstance_w(self, w_obj, w_tp):
         return w_obj.tp == w_tp
 
diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py
--- a/pypy/module/micronumpy/interp_boxes.py
+++ b/pypy/module/micronumpy/interp_boxes.py
@@ -268,14 +268,30 @@
 
 
 class W_VoidBox(W_FlexibleBox):
-    @unwrap_spec(item=str)
-    def descr_getitem(self, space, item):
+    def descr_getitem(self, space, w_item):
+        from pypy.module.micronumpy.types import VoidType
+        if space.isinstance_w(w_item, space.w_str):
+            item = space.str_w(w_item)
+        elif space.isinstance_w(w_item, space.w_int):
+            #Called by iterator protocol
+            indx = space.int_w(w_item)
+            try:
+                item = self.dtype.fieldnames[indx]
+            except IndexError:
+                raise OperationError(space.w_IndexError,
+                     space.wrap("Iterated over too many fields %d" % indx))
+        else:
+            raise OperationError(space.w_IndexError, space.wrap(
+                    "Can only access fields of record with int or str"))
         try:
             ofs, dtype = self.dtype.fields[item]
         except KeyError:
             raise OperationError(space.w_IndexError,
                                  space.wrap("Field %s does not exist" % item))
-        read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype)
+        if isinstance(dtype.itemtype, VoidType):
+            read_val = dtype.itemtype.readarray(self.arr, self.ofs, ofs, dtype)
+        else:
+            read_val = dtype.itemtype.read(self.arr, self.ofs, ofs, dtype)
         if isinstance (read_val, W_StringBox):
             # StringType returns a str
             return space.wrap(dtype.itemtype.to_str(read_val))
@@ -373,7 +389,7 @@
     W_LongDoubleBox = W_Float64Box
     W_CLongDoubleBox = W_Complex64Box
 
-    
+
 W_GenericBox.typedef = TypeDef("generic",
     __module__ = "numpypy",
 
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -65,6 +65,10 @@
         self.float_type = None
         self.shape = list(shape)
         self.subdtype = subdtype
+        if not subdtype:
+            self.base = self
+        else:
+            self.base = subdtype.base
 
     @specialize.argtype(1)
     def box(self, value):
@@ -80,7 +84,8 @@
         return self.itemtype.coerce(space, self, w_item)
 
     def getitem(self, arr, i):
-        return self.itemtype.read(arr, i, 0)
+        item = self.itemtype.read(arr, i, 0)
+        return item
 
     def getitem_bool(self, arr, i):
         return self.itemtype.read_bool(arr, i, 0)
@@ -113,6 +118,9 @@
     def descr_get_alignment(self, space):
         return space.wrap(self.itemtype.alignment)
 
+    def descr_get_base(self, space):
+        return space.wrap(self.base)
+
     def descr_get_subdtype(self, space):
         return space.newtuple([space.wrap(self.subdtype), self.descr_get_shape(space)])
 
@@ -423,6 +431,7 @@
     fields = GetSetProperty(W_Dtype.descr_get_fields),
     names = GetSetProperty(W_Dtype.descr_get_names),
     subdtype = GetSetProperty(W_Dtype.descr_get_subdtype),
+    base = GetSetProperty(W_Dtype.descr_get_base),
 )
 W_Dtype.typedef.acceptable_as_base_class = False
 
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -21,7 +21,7 @@
 from rpython.rlib.rstring import StringBuilder
 from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation
 
-def _find_shape(space, w_size):
+def _find_shape(space, w_size, dtype):
     if space.is_none(w_size):
         return []
     if space.isinstance_w(w_size, space.w_int):
@@ -29,6 +29,7 @@
     shape = []
     for w_item in space.fixedview(w_size):
         shape.append(space.int_w(w_item))
+    shape += dtype.shape
     return shape[:]
 
 class __extend__(W_NDimArray):
@@ -829,7 +830,7 @@
                              space.wrap("unsupported param"))
     dtype = space.interp_w(interp_dtype.W_Dtype,
           space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype))
-    shape = _find_shape(space, w_shape)
+    shape = _find_shape(space, w_shape, dtype)
     if not shape:
         return W_NDimArray.new_scalar(space, dtype)
     return W_NDimArray.from_shape(shape, dtype)
@@ -842,10 +843,10 @@
     """
     from rpython.rtyper.lltypesystem import rffi
     from rpython.rlib.rawstorage import RAW_STORAGE_PTR
-    shape = _find_shape(space, w_shape)
     storage = rffi.cast(RAW_STORAGE_PTR, addr)
     dtype = space.interp_w(interp_dtype.W_Dtype,
                            space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype))
+    shape = _find_shape(space, w_shape, dtype)
     return W_NDimArray.from_shape_and_storage(shape, storage, dtype)
 
 W_NDimArray.typedef = TypeDef(
@@ -1029,7 +1030,7 @@
     dtype = space.interp_w(interp_dtype.W_Dtype,
         space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
     )
-    shape = _find_shape(space, w_shape)
+    shape = _find_shape(space, w_shape, dtype)
     if not shape:
         return W_NDimArray.new_scalar(space, dtype, space.wrap(0))
     return space.wrap(W_NDimArray.from_shape(shape, dtype=dtype, order=order))
@@ -1039,7 +1040,7 @@
     dtype = space.interp_w(interp_dtype.W_Dtype,
         space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
     )
-    shape = _find_shape(space, w_shape)
+    shape = _find_shape(space, w_shape, dtype)
     if not shape:
         return W_NDimArray.new_scalar(space, dtype, space.wrap(0))
     arr = W_NDimArray.from_shape(shape, dtype=dtype, order=order)
diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py
--- a/pypy/module/micronumpy/iter.py
+++ b/pypy/module/micronumpy/iter.py
@@ -32,13 +32,13 @@
 shape dimension
   which is back 25 and forward 1,
   which is x.strides[1] * (x.shape[1] - 1) + x.strides[0]
-so if we precalculate the overflow backstride as 
+so if we precalculate the overflow backstride as
 [x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))]
 we can go faster.
 All the calculations happen in next()
 
 next_skip_x() tries to do the iteration for a number of steps at once,
-but then we cannot gaurentee that we only overflow one single shape 
+but then we cannot gaurentee that we only overflow one single shape
 dimension, perhaps we could overflow times in one big step.
 """
 
@@ -170,7 +170,8 @@
         self.dtype.setitem(self.array, self.offset, elem)
 
     def getitem(self):
-        return self.dtype.getitem(self.array, self.offset)
+        item = self.dtype.getitem(self.array, self.offset)
+        return item
 
     def getitem_bool(self):
         return self.dtype.getitem_bool(self.array, self.offset)
@@ -288,12 +289,13 @@
         self.dim = dim
         self.array = array
         self.dtype = array.dtype
-        
+
     def setitem(self, elem):
         self.dtype.setitem(self.array, self.offset, elem)
 
     def getitem(self):
-        return self.dtype.getitem(self.array, self.offset)
+        item = self.dtype.getitem(self.array, self.offset)
+        return item
 
     @jit.unroll_safe
     def next(self):
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
@@ -275,7 +275,10 @@
         from numpypy import array, dtype
         from cPickle import loads, dumps
         a = array([1,2,3])
-        assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0))
+         if self.ptr_size == 8:
+            assert a.dtype.__reduce__() == (dtype, ('i8', 0, 1), (3, '<', None, None, None, -1, -1, 0))
+        else:
+            assert a.dtype.__reduce__() == (dtype, ('i4', 0, 1), (3, '<', None, None, None, -1, -1, 0))
         assert loads(dumps(a.dtype)) == a.dtype
 
 class AppTestTypes(BaseAppTestDtypes):
@@ -768,6 +771,7 @@
         assert d.num == 20
         assert d.itemsize == 20
         assert d.kind == 'V'
+        assert d.base == d
         assert d.type is void
         assert d.char == 'V'
         assert d.names == ("x", "y", "z", "value")
@@ -798,7 +802,8 @@
         assert dt.shape == (10,)
         assert dt.kind == 'V'
         assert dt.fields == None
-        assert dt.subdtype == (dtype("float64"), (10,))
+        assert dt.subdtype == (dtype(float), (10,))
+        assert dt.base == dtype(float)
 
     def test_pickle_record(self):
         from numpypy import array, dtype
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -18,10 +18,12 @@
         def get_element_size():
             return 1
 
+    def __init__(self):
+        self.base = self
+
     def get_size(self):
         return 1
 
-
 def create_slice(a, chunks):
     return Chunks(chunks).apply(W_NDimArray(a)).implementation
 
@@ -2700,7 +2702,7 @@
         assert a[1]['y'] == 1
 
     def test_subarrays(self):
-        from numpypy import dtype, array
+        from numpypy import dtype, array, zeros
 
         d = dtype([("x", "int", 3), ("y", "float", 5)])
         a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d)
@@ -2713,6 +2715,42 @@
         a[0]["x"][0] = 200
         assert a[0]["x"][0] == 200
 
+        d = dtype([("x", "int", (2, 3))])
+        a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d)
+
+        assert a[0]["x"].dtype == dtype("int64")
+        assert a[0]["x"][0].dtype == dtype("int64")
+
+        assert (a[0]["x"][0] == [1, 2, 3]).all()
+        assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all()
+
+        d = dtype((float, (10, 10)))
+        a = zeros((3,3), dtype=d)
+        assert a[0, 0].shape == (10, 10)
+        assert a.shape == (3, 3, 10, 10)
+        a[0, 0] = 500
+        assert (a[0, 0, 0] == 500).all()
+        assert a[0, 0, 0].shape == (10,)
+
+    def test_multidim_subarray(self):
+        from numpypy import dtype, array
+
+        d = dtype([("x", "int", (2, 3))])
+        a = array([([[1, 2, 3], [4, 5, 6]],)], dtype=d)
+
+        assert a[0]["x"].dtype == dtype("int64")
+        assert a[0]["x"][0].dtype == dtype("int64")
+
+        assert (a[0]["x"][0] == [1, 2, 3]).all()
+        assert (a[0]["x"] == [[1, 2, 3], [4, 5, 6]]).all()
+
+    def test_list_record(self):
+        from numpypy import dtype, array
+
+        d = dtype([("x", "int", 3), ("y", "float", 5)])
+        a = array([([1, 2, 3], [0.5, 1.5, 2.5, 3.5, 4.5]), ([4, 5, 6], [5.5, 6.5, 7.5, 8.5, 9.5])], dtype=d)
+
+        assert len(list(a[0])) == 2
 
 class AppTestPyPy(BaseNumpyAppTest):
     def setup_class(cls):
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
@@ -1686,6 +1686,7 @@
         return space.wrap(self.to_str(box))
 
     def build_and_convert(self, space, mydtype, box):
+        assert isinstance(box, interp_boxes.W_GenericBox)
         if box.get_dtype(space).is_str_or_unicode():
             arg = box.get_dtype(space).itemtype.to_str(box)
         else:
@@ -1702,16 +1703,47 @@
 class VoidType(BaseType, BaseStringType):
     T = lltype.Char
 
-    def coerce(self, space, dtype, w_items):
+    def _coerce(self, space, arr, ofs, dtype, w_items, shape):
         items_w = space.fixedview(w_items)
-        arr = VoidBoxStorage(self.size, dtype)
-        ofs = 0
         for i in range(len(items_w)):
             subdtype = dtype.subdtype
             itemtype = subdtype.itemtype
-            w_box = itemtype.coerce(space, dtype.subdtype, items_w[i])
-            itemtype.store(arr, 0, ofs, w_box)
-            ofs += itemtype.get_element_size()
+            if space.len_w(shape) <= 1:
+                w_box = itemtype.coerce(space, dtype.subdtype, items_w[i])
+                itemtype.store(arr, 0, ofs, w_box)
+                ofs += itemtype.get_element_size()
+            else:
+                size = 1
+                for dimension in shape[1:]:
+                    size *= dimension
+                size *= itemtype.get_element_size()
+                for w_item in items_w:
+                    self._coerce(space, arr, ofs, dtype, w_items, shape[1:])
+                    ofs += size
+        return arr
+
+    def _coerce(self, space, arr, ofs, dtype, w_items, shape):
+        # TODO: Make sure the shape and the array match
+        items_w = space.fixedview(w_items)
+        subdtype = dtype.subdtype
+        itemtype = subdtype.itemtype
+        if len(shape) <= 1:
+            for i in range(len(items_w)):
+                w_box = itemtype.coerce(space, dtype.subdtype, items_w[i])
+                itemtype.store(arr, 0, ofs, w_box)
+                ofs += itemtype.get_element_size()
+        else:
+            for w_item in items_w:
+                size = 1
+                for dimension in shape[1:]:
+                    size *= dimension
+                size *= itemtype.get_element_size()
+                self._coerce(space, arr, ofs, dtype, w_item, shape[1:])
+                ofs += size
+
+    def coerce(self, space, dtype, w_items):
+        arr = VoidBoxStorage(self.size, dtype)
+        self._coerce(space, arr, 0, dtype, w_items, dtype.shape)
         return interp_boxes.W_VoidBox(arr, 0, dtype)
 
     @jit.unroll_safe
@@ -1720,12 +1752,13 @@
         for k in range(self.get_element_size()):
             arr.storage[k + ofs] = box.arr.storage[k + box.ofs]
 
-    def read(self, arr, i, offset, dtype=None):
+    def readarray(self, arr, i, offset, dtype=None):
         from pypy.module.micronumpy.base import W_NDimArray
         if dtype is None:
             dtype = arr.dtype
         strides, backstrides = support.calc_strides(dtype.shape, dtype.subdtype, arr.order)
-        implementation = SliceArray(i + offset, strides, backstrides, dtype.shape, arr, arr, dtype.subdtype)
+        implementation = SliceArray(i + offset, strides, backstrides,
+                             dtype.shape, arr, W_NDimArray(arr), dtype.subdtype)
         return W_NDimArray(implementation)
 
 NonNativeVoidType = VoidType
diff --git a/pypy/module/pypyjit/interp_resop.py b/pypy/module/pypyjit/interp_resop.py
--- a/pypy/module/pypyjit/interp_resop.py
+++ b/pypy/module/pypyjit/interp_resop.py
@@ -75,16 +75,19 @@
     cache.w_optimize_hook = w_hook
     cache.in_recursion = NonConstant(False)
 
+
 def set_abort_hook(space, w_hook):
     """ set_abort_hook(hook)
 
     Set a hook (callable) that will be called each time there is tracing
     aborted due to some reason.
 
-    The hook will be called as in: hook(jitdriver_name, greenkey, reason)
+    The hook will be called with the signature:
+
+        hook(jitdriver_name, greenkey, reason, operations)
 
     Reason is a string, the meaning of other arguments is the same
-    as attributes on JitLoopInfo object
+    as attributes on JitLoopInfo object.
     """
     cache = space.fromcache(Cache)
     cache.w_abort_hook = w_hook
diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py
--- a/pypy/module/pypyjit/policy.py
+++ b/pypy/module/pypyjit/policy.py
@@ -1,26 +1,29 @@
 from rpython.jit.codewriter.policy import JitPolicy
+from rpython.rlib import jit_hooks
 from rpython.rlib.jit import JitHookInterface, Counters
-from rpython.rlib import jit_hooks
+
 from pypy.interpreter.error import OperationError
-from pypy.module.pypyjit.interp_resop import Cache, wrap_greenkey,\
-     WrappedOp, W_JitLoopInfo
+from pypy.module.pypyjit.interp_resop import (Cache, wrap_greenkey,
+    WrappedOp, W_JitLoopInfo, wrap_oplist)
+
 
 class PyPyJitIface(JitHookInterface):
-    def on_abort(self, reason, jitdriver, greenkey, greenkey_repr):
+    def on_abort(self, reason, jitdriver, greenkey, greenkey_repr, logops, operations):
         space = self.space
         cache = space.fromcache(Cache)
         if cache.in_recursion:
             return
         if space.is_true(cache.w_abort_hook):
             cache.in_recursion = True
+            oplist_w = wrap_oplist(space, logops, operations)
             try:
                 try:
                     space.call_function(cache.w_abort_hook,
-                                        space.wrap(jitdriver.name),
-                                        wrap_greenkey(space, jitdriver,
-                                                      greenkey, greenkey_repr),
-                                        space.wrap(
-                                            Counters.counter_names[reason]))
+                        space.wrap(jitdriver.name),
+                        wrap_greenkey(space, jitdriver, greenkey, greenkey_repr),
+                        space.wrap(Counters.counter_names[reason]),
+                        space.newlist(oplist_w)
+                    )
                 except OperationError, e:
                     e.write_unraisable(space, "jit hook ", cache.w_abort_hook)
             finally:
diff --git a/pypy/module/pypyjit/test/test_jit_hook.py b/pypy/module/pypyjit/test/test_jit_hook.py
--- a/pypy/module/pypyjit/test/test_jit_hook.py
+++ b/pypy/module/pypyjit/test/test_jit_hook.py
@@ -16,6 +16,7 @@
 from rpython.jit.metainterp.typesystem import llhelper
 from rpython.rlib.jit import JitDebugInfo, AsmInfo, Counters
 
+
 class MockJitDriverSD(object):
     class warmstate(object):
         @staticmethod
@@ -34,8 +35,10 @@
 
     jitdrivers_sd = [MockJitDriverSD]
 
+
 class AppTestJitHook(object):
     spaceconfig = dict(usemodules=('pypyjit',))
+
     def setup_class(cls):
         if cls.runappdirect:
             py.test.skip("Can't run this test with -A")
@@ -86,7 +89,7 @@
 
         def interp_on_abort():
             pypy_hooks.on_abort(Counters.ABORT_TOO_LONG, pypyjitdriver,
-                                greenkey, 'blah')
+                                greenkey, 'blah', Logger(MockSD), [])
 
         space = cls.space
         cls.w_on_compile = space.wrap(interp2app(interp_on_compile))
@@ -189,12 +192,12 @@
         import pypyjit
         l = []
 
-        def hook(jitdriver_name, greenkey, reason):
-            l.append((jitdriver_name, reason))
+        def hook(jitdriver_name, greenkey, reason, operations):
+            l.append((jitdriver_name, reason, operations))
 
         pypyjit.set_abort_hook(hook)
         self.on_abort()
-        assert l == [('pypyjit', 'ABORT_TOO_LONG')]
+        assert l == [('pypyjit', 'ABORT_TOO_LONG', [])]
 
     def test_on_optimize(self):
         import pypyjit
diff --git a/pypy/module/pypyjit/test_pypy_c/bug1.py b/pypy/module/pypyjit/test_pypy_c/bug1.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/pypyjit/test_pypy_c/bug1.py
@@ -0,0 +1,57 @@
+import cffi, thread, time, sys
+
+
+ffi = cffi.FFI()
+
+ffi.cdef("""
+    long foobar(long a, long b, long c, long d, long e, long f,
+                long a2, long b2, long c2, long d2, long e2, long f2,
+                long a3, long b3, long c3, long d3, long e3, long f3,
+                long a4, long b4, long c4, long d4, long e4, long f4);
+""")
+
+lib = ffi.verify("""
+    long foobar(long a, long b, long c, long d, long e, long f,
+                long a2, long b2, long c2, long d2, long e2, long f2,
+                long a3, long b3, long c3, long d3, long e3, long f3,
+                long a4, long b4, long c4, long d4, long e4, long f4)
+    {
+        return a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 +
+               (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) +
+               (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) +
+               (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7);
+    }
+""")
+
+
+def runme():
+    for j in range(10):
+        for i in range(10000):
+            args = [i-k for k in range(24)]
+            x = lib.foobar(*args)
+            (a,b,c,d,e,f,a2,b2,c2,d2,e2,f2,
+             a3,b3,c3,d3,e3,f3,a4,b4,c4,d4,e4,f4) = args
+            assert x == (
+                a * 1 + b * 2 + c * 3 + d * 4 + e * 5 + f * 6 +
+                (a2 * 1 + b2 * 2 + c2 * 3 + d2 * 4 + e2 * 5 + f2 * 6) * (-3) +
+                (a3 * 1 + b3 * 2 + c3 * 3 + d3 * 4 + e3 * 5 + f3 * 6) * (-5) +
+                (a4 * 1 + b4 * 2 + c4 * 3 + d4 * 4 + e4 * 5 + f4 * 6) * (-7))
+
+done = []
+
+def submain():
+    try:
+        runme()
+        err = None
+    except:
+        err = sys.exc_info()
+    done.append(err)
+
+for i in range(2):
+    thread.start_new_thread(submain, ())
+while len(done) < 2:
+    time.sleep(0.1)
+
+for err in done:
+    if err is not None:
+        raise err[0], err[1], err[2]
diff --git a/pypy/module/pypyjit/test_pypy_c/test_array.py b/pypy/module/pypyjit/test_pypy_c/test_array.py
--- a/pypy/module/pypyjit/test_pypy_c/test_array.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_array.py
@@ -105,6 +105,7 @@
         assert loop.match("""
             i10 = int_lt(i6, 1000)
             guard_true(i10, descr=...)
+            guard_not_invalidated(descr=...)
             i11 = int_lt(i6, i7)
             guard_true(i11, descr=...)
             f13 = getarrayitem_raw(i8, i6, descr=<ArrayF 8>)
@@ -141,6 +142,7 @@
         assert loop.match("""
             i10 = int_lt(i6, 1000)
             guard_true(i10, descr=...)
+            guard_not_invalidated(descr=...)
             i11 = int_lt(i6, i7)
             guard_true(i11, descr=...)
             i13 = getarrayitem_raw(i8, i6, descr=<Array. 4>)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_bug.py b/pypy/module/pypyjit/test_pypy_c/test_bug.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/pypyjit/test_pypy_c/test_bug.py
@@ -0,0 +1,14 @@
+import os, sys, py, subprocess
+
+localdir = os.path.dirname(os.path.abspath(__file__))
+
+
+def test_bug1():
+    if not sys.platform.startswith('linux'):
+        py.test.skip("linux-only test")
+
+    cmdline = ['taskset', '-c', '0',
+               sys.executable, os.path.join(localdir, 'bug1.py')]
+    popen = subprocess.Popen(cmdline)
+    err = popen.wait()
+    assert err == 0
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -487,6 +487,7 @@
         assert loop.match("""
             i2 = int_lt(i0, i1)
             guard_true(i2, descr=...)
+            guard_not_invalidated(descr=...)
             i3 = force_token()
             i4 = int_add(i0, 1)
             --TICK--
@@ -586,7 +587,6 @@
         """, [1000])
         loop, = log.loops_by_id('call')
         assert loop.match_by_id('call', '''
-        guard_not_invalidated(descr=<.*>)
         i1 = force_token()
         ''')
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_containers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py
@@ -44,6 +44,7 @@
         # gc_id call is hoisted out of the loop, the id of a value obviously
         # can't change ;)
         assert loop.match_by_id("getitem", """
+            ...
             i26 = call(ConstClass(ll_dict_lookup), p18, p6, i25, descr=...)
             ...
             p33 = getinteriorfield_gc(p31, i26, descr=<InteriorFieldDescr <FieldP dictentry.value .*>>)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -36,7 +36,7 @@
         assert loop0.match(expected)
         # XXX: The retracing fails to form a loop since j


More information about the pypy-commit mailing list