Author: Richard Plangger <planri...@gmail.com>
Branch: s390x-backend
Changeset: r80788:ccd0b940856e
Date: 2015-11-20 11:01 +0100
http://bitbucket.org/pypy/pypy/changeset/ccd0b940856e/

Log:    merged default

diff too long, truncating to 2000 out of 6622 lines

diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -17,3 +17,4 @@
 295ee98b69288471b0fcf2e0ede82ce5209eb90b release-2.6.0
 f3ad1e1e1d6215e20d34bb65ab85ff9188c9f559 release-2.6.1
 850edf14b2c75573720f59e95767335fb1affe55 release-4.0.0
+5f8302b8bf9f53056e40426f10c72151564e5b19 release-4.0.1
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -56,14 +56,15 @@
   Anders Chrigstrom
   Eric van Riet Paap
   Wim Lavrijsen
+  Richard Plangger
   Richard Emslie
   Alexander Schremmer
   Dan Villiom Podlaski Christiansen
   Lukas Diekmann
   Sven Hager
   Anders Lehmann
+  Remi Meier
   Aurelien Campeas
-  Remi Meier
   Niklaus Haldimann
   Camillo Bruni
   Laura Creighton
@@ -87,7 +88,6 @@
   Ludovic Aubry
   Jacob Hallen
   Jason Creighton
-  Richard Plangger
   Alex Martelli
   Michal Bendowski
   stian
@@ -200,9 +200,12 @@
   Alex Perry
   Vincent Legoll
   Alan McIntyre
+  Spenser Bauman
   Alexander Sedov
   Attila Gobi
   Christopher Pope
+  Devin Jeanpierre
+  Vaibhav Sood
   Christian Tismer 
   Marc Abramowitz
   Dan Stromberg
@@ -234,6 +237,7 @@
   Lutz Paelike
   Lucio Torre
   Lars Wassermann
+  Philipp Rustemeuer
   Henrik Vendelbo
   Dan Buch
   Miguel de Val Borro
@@ -244,6 +248,7 @@
   Martin Blais
   Lene Wagner
   Tomo Cocoa
+  Kim Jin Su
   Toni Mattis
   Lucas Stadler
   Julian Berman
@@ -253,6 +258,7 @@
   Anna Katrina Dominguez
   William Leslie
   Bobby Impollonia
+  Faye Zhao
   t...@eistee.fritz.box
   Andrew Thompson
   Yusei Tahara
@@ -283,6 +289,7 @@
   shoma hosaka
   Daniel Neuh&#228;user
   Ben Mather
+  Niclas Olofsson
   halgari
   Boglarka Vezer
   Chris Pressey
@@ -309,13 +316,16 @@
   Stefan Marr
   jiaaro
   Mads Kiilerich
+  Richard Lancaster
   opassembler.py
   Antony Lee
+  Yaroslav Fedevych
   Jim Hunziker
   Markus Unterwaditzer
   Even Wiik Thomassen
   jbs
   squeaky
+  Zearin
   soareschen
   Kurt Griffiths
   Mike Bayer
@@ -327,6 +337,7 @@
   Anna Ravencroft
   Andrey Churin
   Dan Crosta
+  Tobias Diaz
   Julien Phalip
   Roman Podoliaka
   Dan Loewenherz
diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO
--- a/lib_pypy/cffi.egg-info/PKG-INFO
+++ b/lib_pypy/cffi.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cffi
-Version: 1.3.0
+Version: 1.3.1
 Summary: Foreign Function Interface for Python calling C code.
 Home-page: http://cffi.readthedocs.org
 Author: Armin Rigo, Maciej Fijalkowski
diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py
--- a/lib_pypy/cffi/__init__.py
+++ b/lib_pypy/cffi/__init__.py
@@ -4,8 +4,8 @@
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "1.3.0"
-__version_info__ = (1, 3, 0)
+__version__ = "1.3.1"
+__version_info__ = (1, 3, 1)
 
 # The verifier module file names are based on the CRC32 of a string that
 # contains the following version number.  It may be older than __version__
diff --git a/lib_pypy/cffi/cparser.py b/lib_pypy/cffi/cparser.py
--- a/lib_pypy/cffi/cparser.py
+++ b/lib_pypy/cffi/cparser.py
@@ -62,7 +62,8 @@
         if csource.startswith('*', endpos):
             parts.append('('); closing += ')'
         level = 0
-        for i in xrange(endpos, len(csource)):
+        i = endpos
+        while i < len(csource):
             c = csource[i]
             if c == '(':
                 level += 1
@@ -73,6 +74,7 @@
             elif c in ',;=':
                 if level == 0:
                     break
+            i += 1
         csource = csource[endpos:i] + closing + csource[i:]
         #print repr(''.join(parts)+csource)
     parts.append(csource)
diff --git a/lib_pypy/cffi/model.py b/lib_pypy/cffi/model.py
--- a/lib_pypy/cffi/model.py
+++ b/lib_pypy/cffi/model.py
@@ -514,12 +514,17 @@
         if self.baseinttype is not None:
             return self.baseinttype.get_cached_btype(ffi, finishlist)
         #
+        from . import api
         if self.enumvalues:
             smallest_value = min(self.enumvalues)
             largest_value = max(self.enumvalues)
         else:
-            smallest_value = 0
-            largest_value = 0
+            import warnings
+            warnings.warn("%r has no values explicitly defined; next version "
+                          "will refuse to guess which integer type it is "
+                          "meant to be (unsigned/signed, int/long)"
+                          % self._get_c_name())
+            smallest_value = largest_value = 0
         if smallest_value < 0:   # needs a signed type
             sign = 1
             candidate1 = PrimitiveType("int")
diff --git a/pypy/doc/build.rst b/pypy/doc/build.rst
--- a/pypy/doc/build.rst
+++ b/pypy/doc/build.rst
@@ -85,13 +85,16 @@
 _ssl
     libssl
 
+gdbm
+    libgdbm-dev
+
 Make sure to have these libraries (with development headers) installed before
 building PyPy, otherwise the resulting binary will not contain these modules.
 
 On Debian, this is the command to install all build-time dependencies::
 
     apt-get install gcc make libffi-dev pkg-config libz-dev libbz2-dev \
-    libsqlite3-dev libncurses-dev libexpat1-dev libssl-dev
+    libsqlite3-dev libncurses-dev libexpat1-dev libssl-dev libgdbm-dev
 
 For the optional lzma module on PyPy3 you will also need ``liblzma-dev``.
 
diff --git a/pypy/doc/contributor.rst b/pypy/doc/contributor.rst
--- a/pypy/doc/contributor.rst
+++ b/pypy/doc/contributor.rst
@@ -26,15 +26,15 @@
   Anders Chrigstrom
   Eric van Riet Paap
   Wim Lavrijsen
+  Richard Plangger
   Richard Emslie
   Alexander Schremmer
   Dan Villiom Podlaski Christiansen
   Lukas Diekmann
   Sven Hager
   Anders Lehmann
-  Richard Plangger
+  Remi Meier
   Aurelien Campeas
-  Remi Meier
   Niklaus Haldimann
   Camillo Bruni
   Laura Creighton
@@ -170,9 +170,12 @@
   Alex Perry
   Vincent Legoll
   Alan McIntyre
+  Spenser Bauman
   Alexander Sedov
   Attila Gobi
   Christopher Pope
+  Devin Jeanpierre
+  Vaibhav Sood
   Christian Tismer 
   Marc Abramowitz
   Dan Stromberg
@@ -204,6 +207,7 @@
   Lutz Paelike
   Lucio Torre
   Lars Wassermann
+  Philipp Rustemeuer
   Henrik Vendelbo
   Dan Buch
   Miguel de Val Borro
@@ -214,6 +218,7 @@
   Martin Blais
   Lene Wagner
   Tomo Cocoa
+  Kim Jin Su
   Toni Mattis
   Lucas Stadler
   Julian Berman
@@ -223,6 +228,7 @@
   Anna Katrina Dominguez
   William Leslie
   Bobby Impollonia
+  Faye Zhao
   t...@eistee.fritz.box
   Andrew Thompson
   Yusei Tahara
@@ -280,13 +286,16 @@
   Stefan Marr
   jiaaro
   Mads Kiilerich
+  Richard Lancaster
   opassembler.py
   Antony Lee
+  Yaroslav Fedevych
   Jim Hunziker
   Markus Unterwaditzer
   Even Wiik Thomassen
   jbs
   squeaky
+  Zearin
   soareschen
   Kurt Griffiths
   Mike Bayer
@@ -298,6 +307,7 @@
   Anna Ravencroft
   Andrey Churin
   Dan Crosta
+  Tobias Diaz
   Julien Phalip
   Roman Podoliaka
   Dan Loewenherz
diff --git a/pypy/doc/index-of-release-notes.rst 
b/pypy/doc/index-of-release-notes.rst
--- a/pypy/doc/index-of-release-notes.rst
+++ b/pypy/doc/index-of-release-notes.rst
@@ -6,6 +6,7 @@
 
 .. toctree::
 
+   release-4.0.1.rst
    release-4.0.0.rst
    release-2.6.1.rst
    release-2.6.0.rst
diff --git a/pypy/doc/index-of-whatsnew.rst b/pypy/doc/index-of-whatsnew.rst
--- a/pypy/doc/index-of-whatsnew.rst
+++ b/pypy/doc/index-of-whatsnew.rst
@@ -7,6 +7,7 @@
 .. toctree::
 
    whatsnew-head.rst
+   whatsnew-4.0.1.rst
    whatsnew-4.0.0.rst
    whatsnew-2.6.1.rst
    whatsnew-2.6.0.rst
diff --git a/pypy/doc/release-4.0.1.rst b/pypy/doc/release-4.0.1.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-4.0.1.rst
@@ -0,0 +1,106 @@
+==========
+PyPy 4.0.1
+==========
+
+We have released PyPy 4.0.1, three weeks after PyPy 4.0.0. We have fixed
+a few critical bugs in the JIT compiled code, reported by users. We therefore
+encourage all users of PyPy to update to this version. There are a few minor
+enhancements in this version as well.
+
+You can download the PyPy 4.0.1 release here:
+
+    http://pypy.org/download.html
+
+We would like to thank our donors for the continued support of the PyPy
+project.
+
+We would also like to thank our contributors and 
+encourage new people to join the project. PyPy has many
+layers and we need help with all of them: `PyPy`_ and `RPython`_ documentation
+improvements, tweaking popular `modules`_ to run on pypy, or general `help`_ 
+with making RPython's JIT even better. 
+
+CFFI
+====
+
+While not applicable only to PyPy, `cffi`_ is arguably our most significant
+contribution to the python ecosystem. PyPy 4.0.1 ships with 
+`cffi-1.3.1`_ with the improvements it brings.
+
+.. _`PyPy`: http://doc.pypy.org 
+.. _`RPython`: https://rpython.readthedocs.org
+.. _`cffi`: https://cffi.readthedocs.org
+.. _`cffi-1.3.1`: http://cffi.readthedocs.org/en/latest/whatsnew.html#v1-3-1
+.. _`modules`: 
http://doc.pypy.org/en/latest/project-ideas.html#make-more-python-modules-pypy-friendly
+.. _`help`: http://doc.pypy.org/en/latest/project-ideas.html
+.. _`numpy`: https://bitbucket.org/pypy/numpy
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy and cpython 2.7.x`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+We also welcome developers of other
+`dynamic languages`_ to see what RPython can do for them.
+
+This release supports **x86** machines on most common operating systems
+(Linux 32/64, Mac OS X 64, Windows 32, OpenBSD, freebsd),
+newer **ARM** hardware (ARMv6 or ARMv7, with VFPv3) running Linux, and the
+big- and little-endian variants of **ppc64** running Linux.
+
+.. _`pypy and cpython 2.7.x`: http://speed.pypy.org
+.. _`dynamic languages`: http://pypyjs.org
+
+Other Highlights (since 4.0.0 released three weeks ago)
+=======================================================
+
+* Bug Fixes
+
+  * Fix a bug when unrolling double loops in JITted code
+
+  * Fix multiple memory leaks in the ssl module, one of which affected
+    `cpython` as well (thanks to Alex Gaynor for pointing those out)
+
+  * Use pkg-config to find ssl headers on OS-X
+
+  * Issues reported with our previous release were resolved_ after reports 
from users on
+    our issue tracker at https://bitbucket.org/pypy/pypy/issues or on IRC at
+    #pypy
+
+* New features:
+
+  * Internal cleanup of RPython class handling
+
+  * Support stackless and greenlets on PPC machines
+
+  * Improve debug logging in subprocesses: use PYPYLOG=jit:log.%d
+    for example to have all subprocesses write the JIT log to a file
+    called 'log.%d', with '%d' replaced with the subprocess' PID.
+
+  * Support PyOS_double_to_string in our cpyext capi compatibility layer
+
+* Numpy:
+
+  * Improve support for __array_interface__
+
+  * Propagate NAN mantissas through float16-float32-float64 conversions
+
+
+* Performance improvements and refactorings:
+
+  * Improvements in slicing byte arrays
+
+  * Improvements in enumerate()
+
+  * Silence some warnings while translating
+
+.. _resolved: http://doc.pypy.org/en/latest/whatsnew-4.0.1.html
+
+Please update, and continue to help us make PyPy better.
+
+Cheers
+
+The PyPy Team
+
diff --git a/pypy/doc/tool/makecontributor.py b/pypy/doc/tool/makecontributor.py
--- a/pypy/doc/tool/makecontributor.py
+++ b/pypy/doc/tool/makecontributor.py
@@ -69,7 +69,9 @@
     'Rami Chowdhury': ['necaris'],
     'Stanislaw Halik':['w31rd0'],
     'Wenzhu Man':['wenzhu man', 'wenzhuman'],
-    'Anton Gulenko':['anton gulenko'],
+    'Anton Gulenko':['anton gulenko', 'anton_gulenko'],
+    'Richard Lancaster':['richardlancaster'],
+    'William Leslie':['William ML Leslie'],
     }
 
 alias_map = {}
diff --git a/pypy/doc/whatsnew-4.0.1.rst b/pypy/doc/whatsnew-4.0.1.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/whatsnew-4.0.1.rst
@@ -0,0 +1,35 @@
+=========================
+What's new in PyPy 4.0.1
+=========================
+
+.. this is a revision shortly after release-4.0.0
+.. startrev: 57c9a47c70f6
+
+.. branch: 2174-fix-osx-10-11-translation
+
+Use pkg-config to find ssl headers on OS-X
+
+.. branch: Zearin/minor-whatsnewrst-markup-tweaks-edited-o-1446387512092
+
+.. branch: ppc-stacklet
+
+The PPC machines now support the _continuation module (stackless, greenlets)
+
+.. branch: int_0/i-need-this-library-to-build-on-ubuntu-1-1446717626227
+
+Document that libgdbm-dev is required for translation/packaging
+
+.. branch: propogate-nans
+
+Ensure that ndarray conversion from int16->float16->float32->float16->int16
+preserves all int16 values, even across nan conversions. Also fix argmax, 
argmin
+for nan comparisons
+
+.. branch: array_interface
+
+Support common use-cases for __array_interface__, passes upstream tests
+
+.. branch: no-class-specialize
+
+Some refactoring of class handling in the annotator. 
+Remove class specialisation and _settled_ flag.
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
@@ -2,15 +2,6 @@
 What's new in PyPy 4.0.+
 =========================
 
-.. this is a revision shortly after release-4.0.0
-.. startrev: 57c9a47c70f6
+.. this is a revision shortly after release-4.0.1
+.. startrev: 4b5c840d0da2
 
-.. branch: 2174-fix-osx-10-11-translation
-
-Use pkg-config to find ssl headers on OS-X
-
-.. branch: Zearin/minor-whatsnewrst-markup-tweaks-edited-o-1446387512092
-
-.. branch: ppc-stacklet
-
-The PPC machines now support the _continuation module (stackless, greenlets)
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -28,7 +28,6 @@
     """This is the abstract root class of all wrapped objects that live
     in a 'normal' object space like StdObjSpace."""
     __slots__ = ()
-    _settled_ = True
     user_overridden_class = False
 
     def getdict(self, space):
@@ -392,7 +391,7 @@
         self.check_signal_action = None   # changed by the signal module
         self.user_del_action = UserDelAction(self)
         self._code_of_sys_exc_info = None
-
+        
         # can be overridden to a subclass
         self.initialize()
 
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -50,6 +50,9 @@
     kwargname = varnames[argcount] if code.co_flags & CO_VARKEYWORDS else None
     return Signature(argnames, varargname, kwargname)
 
+class CodeHookCache(object):
+    def __init__(self, space):
+        self._code_hook = None
 
 class PyCode(eval.Code):
     "CPython-style code objects."
@@ -86,6 +89,15 @@
         self._signature = cpython_code_signature(self)
         self._initialize()
         self._init_ready()
+        self.new_code_hook()
+
+    def new_code_hook(self):
+        code_hook = self.space.fromcache(CodeHookCache)._code_hook
+        if code_hook is not None:
+            try:
+                self.space.call_function(code_hook, self)
+            except OperationError, e:
+                e.write_unraisable(self.space, "new_code_hook()")
 
     def _initialize(self):
         if self.co_cellvars:
diff --git a/pypy/interpreter/test/test_zzpickle_and_slow.py 
b/pypy/interpreter/test/test_zzpickle_and_slow.py
--- a/pypy/interpreter/test/test_zzpickle_and_slow.py
+++ b/pypy/interpreter/test/test_zzpickle_and_slow.py
@@ -390,15 +390,20 @@
 
     def test_pickle_enum(self):
         import pickle
-        e      = enumerate(range(10))
+        e = enumerate(range(100, 106))
         e.next()
         e.next()
         pckl   = pickle.dumps(e)
         result = pickle.loads(pckl)
-        e.next()
-        result.next()
+        res = e.next()
+        assert res == (2, 102)
+        res = result.next()
+        assert res == (2, 102)
         assert type(e) is type(result)
-        assert list(e) == list(result)
+        res = list(e)
+        assert res == [(3, 103), (4, 104), (5, 105)]
+        res = list(result)
+        assert res == [(3, 103), (4, 104), (5, 105)]
 
     def test_pickle_xrangeiter(self):
         import pickle
diff --git a/pypy/module/__builtin__/functional.py 
b/pypy/module/__builtin__/functional.py
--- a/pypy/module/__builtin__/functional.py
+++ b/pypy/module/__builtin__/functional.py
@@ -8,7 +8,7 @@
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
 from pypy.interpreter.typedef import TypeDef
-from rpython.rlib import jit
+from rpython.rlib import jit, rarithmetic
 from rpython.rlib.objectmodel import specialize
 from rpython.rlib.rarithmetic import r_uint, intmask
 from rpython.rlib.rbigint import rbigint
@@ -229,27 +229,70 @@
     return min_max(space, __args__, "min")
 
 
+
 class W_Enumerate(W_Root):
-    def __init__(self, w_iter, w_start):
-        self.w_iter = w_iter
+    def __init__(self, w_iter_or_list, start, w_start):
+        # 'w_index' should never be a wrapped int here; if it would be,
+        # then it is actually None and the unwrapped int is in 'index'.
+        self.w_iter_or_list = w_iter_or_list
+        self.index = start
         self.w_index = w_start
 
     def descr___new__(space, w_subtype, w_iterable, w_start=None):
-        self = space.allocate_instance(W_Enumerate, w_subtype)
+        from pypy.objspace.std.listobject import W_ListObject
+
         if w_start is None:
-            w_start = space.wrap(0)
+            start = 0
         else:
             w_start = space.index(w_start)
-        self.__init__(space.iter(w_iterable), w_start)
+            if space.is_w(space.type(w_start), space.w_int):
+                start = space.int_w(w_start)
+                w_start = None
+            else:
+                start = -1
+
+        if start == 0 and type(w_iterable) is W_ListObject:
+            w_iter = w_iterable
+        else:
+            w_iter = space.iter(w_iterable)
+
+        self = space.allocate_instance(W_Enumerate, w_subtype)
+        self.__init__(w_iter, start, w_start)
         return space.wrap(self)
 
     def descr___iter__(self, space):
         return space.wrap(self)
 
     def descr_next(self, space):
-        w_item = space.next(self.w_iter)
+        from pypy.objspace.std.listobject import W_ListObject
         w_index = self.w_index
-        self.w_index = space.add(w_index, space.wrap(1))
+        w_iter_or_list = self.w_iter_or_list
+        w_item = None
+        if w_index is None:
+            index = self.index
+            if type(w_iter_or_list) is W_ListObject:
+                try:
+                    w_item = w_iter_or_list.getitem(index)
+                except IndexError:
+                    self.w_iter_or_list = None
+                    raise OperationError(space.w_StopIteration, space.w_None)
+                self.index = index + 1
+            elif w_iter_or_list is None:
+                raise OperationError(space.w_StopIteration, space.w_None)
+            else:
+                try:
+                    newval = rarithmetic.ovfcheck(index + 1)
+                except OverflowError:
+                    w_index = space.wrap(index)
+                    self.w_index = space.add(w_index, space.wrap(1))
+                    self.index = -1
+                else:
+                    self.index = newval
+            w_index = space.wrap(index)
+        else:
+            self.w_index = space.add(w_index, space.wrap(1))
+        if w_item is None:
+            w_item = space.next(self.w_iter_or_list)
         return space.newtuple([w_index, w_item])
 
     def descr___reduce__(self, space):
@@ -257,12 +300,20 @@
         w_mod    = space.getbuiltinmodule('_pickle_support')
         mod      = space.interp_w(MixedModule, w_mod)
         w_new_inst = mod.get('enumerate_new')
-        w_info = space.newtuple([self.w_iter, self.w_index])
+        w_index = self.w_index
+        if w_index is None:
+            w_index = space.wrap(self.index)
+        w_info = space.newtuple([self.w_iter_or_list, w_index])
         return space.newtuple([w_new_inst, w_info])
 
 # exported through _pickle_support
-def _make_enumerate(space, w_iter, w_index):
-    return space.wrap(W_Enumerate(w_iter, w_index))
+def _make_enumerate(space, w_iter_or_list, w_index):
+    if space.is_w(space.type(w_index), space.w_int):
+        index = space.int_w(w_index)
+        w_index = None
+    else:
+        index = -1
+    return space.wrap(W_Enumerate(w_iter_or_list, index, w_index))
 
 W_Enumerate.typedef = TypeDef("enumerate",
     __new__=interp2app(W_Enumerate.descr___new__.im_func),
diff --git a/pypy/module/__builtin__/test/test_builtin.py 
b/pypy/module/__builtin__/test/test_builtin.py
--- a/pypy/module/__builtin__/test/test_builtin.py
+++ b/pypy/module/__builtin__/test/test_builtin.py
@@ -264,6 +264,7 @@
         raises(StopIteration,x.next)
 
     def test_enumerate(self):
+        import sys
         seq = range(2,4)
         enum = enumerate(seq)
         assert enum.next() == (0, 2)
@@ -274,6 +275,15 @@
         enum = enumerate(range(5), 2)
         assert list(enum) == zip(range(2, 7), range(5))
 
+        enum = enumerate(range(2), 2**100)
+        assert list(enum) == [(2**100, 0), (2**100+1, 1)]
+
+        enum = enumerate(range(2), sys.maxint)
+        assert list(enum) == [(sys.maxint, 0), (sys.maxint+1, 1)]
+
+        raises(TypeError, enumerate, range(2), 5.5)
+
+
     def test_next(self):
         x = iter(['a', 'b', 'c'])
         assert next(x) == 'a'
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -86,6 +86,7 @@
         'specialized_zip_2_lists'   : 'interp_magic.specialized_zip_2_lists',
         'set_debug'                 : 'interp_magic.set_debug',
         'locals_to_fast'            : 'interp_magic.locals_to_fast',
+        'set_code_callback'         : 'interp_magic.set_code_callback',
         'save_module_content_for_future_reload':
                           'interp_magic.save_module_content_for_future_reload',
     }
diff --git a/pypy/module/__pypy__/interp_magic.py 
b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -1,5 +1,6 @@
 from pypy.interpreter.error import OperationError, wrap_oserror
 from pypy.interpreter.gateway import unwrap_spec
+from pypy.interpreter.pycode import CodeHookCache
 from pypy.interpreter.pyframe import PyFrame
 from pypy.interpreter.mixedmodule import MixedModule
 from rpython.rlib.objectmodel import we_are_translated
@@ -151,3 +152,10 @@
 def specialized_zip_2_lists(space, w_list1, w_list2):
     from pypy.objspace.std.specialisedtupleobject import 
specialized_zip_2_lists
     return specialized_zip_2_lists(space, w_list1, w_list2)
+
+def set_code_callback(space, w_callable):
+    cache = space.fromcache(CodeHookCache)
+    if space.is_none(w_callable):
+        cache._code_hook = None
+    else:
+        cache._code_hook = w_callable
\ No newline at end of file
diff --git a/pypy/module/__pypy__/test/test_magic.py 
b/pypy/module/__pypy__/test/test_magic.py
--- a/pypy/module/__pypy__/test/test_magic.py
+++ b/pypy/module/__pypy__/test/test_magic.py
@@ -13,3 +13,21 @@
         #
         sys.dont_write_bytecode = d
         __pypy__.save_module_content_for_future_reload(sys)
+
+    def test_new_code_hook(self):
+        l = []
+
+        def callable(code):
+            l.append(code)
+
+        import __pypy__
+        __pypy__.set_code_callback(callable)
+        d = {}
+        try:
+            exec """
+def f():
+    pass
+""" in d
+        finally:
+            __pypy__.set_code_callback(None)
+        assert d['f'].__code__ in l
\ No newline at end of file
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
@@ -2,7 +2,7 @@
 from pypy.interpreter.mixedmodule import MixedModule
 from rpython.rlib import rdynload, clibffi
 
-VERSION = "1.3.0"
+VERSION = "1.3.1"
 
 FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI
 try:
diff --git a/pypy/module/_cffi_backend/ffi_obj.py 
b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -448,7 +448,7 @@
 
 'alloc' is called with the size as argument.  If it returns NULL, a
 MemoryError is raised.  'free' is called with the result of 'alloc'
-as argument.  Both can be either Python function or directly C
+as argument.  Both can be either Python functions or directly C
 functions.  If 'free' is None, then no free function is called.
 If both 'alloc' and 'free' are None, the default is used.
 
diff --git a/pypy/module/_cffi_backend/src/parse_c_type.c 
b/pypy/module/_cffi_backend/src/parse_c_type.c
--- a/pypy/module/_cffi_backend/src/parse_c_type.c
+++ b/pypy/module/_cffi_backend/src/parse_c_type.c
@@ -4,6 +4,7 @@
 #include <errno.h>
 
 #if defined(_MSC_VER)
+# define MS_WIN32
 typedef size_t uintptr_t;
 #else
 # include <stdint.h>
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
@@ -1,7 +1,7 @@
 # ____________________________________________________________
 
 import sys
-assert __version__ == "1.3.0", ("This test_c.py file is for testing a version"
+assert __version__ == "1.3.1", ("This test_c.py file is for testing a version"
                                 " of cffi that differs from the one that we"
                                 " get from 'import _cffi_backend'")
 if sys.version_info < (3,):
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py 
b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -16,8 +16,8 @@
         from cffi import ffiplatform
     except ImportError:
         py.test.skip("system cffi module not found or older than 1.0.0")
-    if cffi.__version_info__ < (1, 2, 0):
-        py.test.skip("system cffi module needs to be at least 1.2.0")
+    if cffi.__version_info__ < (1, 3, 0):
+        py.test.skip("system cffi module needs to be at least 1.3.0")
     space.appexec([], """():
         import _cffi_backend     # force it to be initialized
     """)
diff --git a/pypy/module/_minimal_curses/interp_curses.py 
b/pypy/module/_minimal_curses/interp_curses.py
--- a/pypy/module/_minimal_curses/interp_curses.py
+++ b/pypy/module/_minimal_curses/interp_curses.py
@@ -13,7 +13,7 @@
     def __init__(self, msg):
         self.msg = msg
 
-from rpython.annotator.description import FORCE_ATTRIBUTES_INTO_CLASSES
+from rpython.annotator.classdesc import FORCE_ATTRIBUTES_INTO_CLASSES
 from rpython.annotator.model import SomeString
 
 # this is necessary due to annmixlevel
diff --git a/pypy/module/_multiprocessing/interp_win32.py 
b/pypy/module/_multiprocessing/interp_win32.py
--- a/pypy/module/_multiprocessing/interp_win32.py
+++ b/pypy/module/_multiprocessing/interp_win32.py
@@ -17,7 +17,7 @@
     NMPWAIT_WAIT_FOREVER
     ERROR_PIPE_CONNECTED ERROR_SEM_TIMEOUT ERROR_PIPE_BUSY
     ERROR_NO_SYSTEM_RESOURCES ERROR_BROKEN_PIPE ERROR_MORE_DATA
-    ERROR_ALREADY_EXISTS
+    ERROR_ALREADY_EXISTS ERROR_NO_DATA
 """.split()
 
 class CConfig:
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -1,4 +1,4 @@
-from rpython.rlib import rpoll, rsocket, rthread, rweakref
+from rpython.rlib import rpoll, rsocket, rthread, rweakref, rgc
 from rpython.rlib.rarithmetic import intmask, widen, r_uint
 from rpython.rlib.ropenssl import *
 from pypy.module._socket import interp_socket
@@ -852,55 +852,58 @@
                     names = rffi.cast(GENERAL_NAMES, method[0].c_d2i(
                         null, p_ptr, length))
 
-            for j in range(libssl_sk_GENERAL_NAME_num(names)):
-                # Get a rendering of each name in the set of names
+            try:
+                for j in range(libssl_sk_GENERAL_NAME_num(names)):
+                    # Get a rendering of each name in the set of names
 
-                name = libssl_sk_GENERAL_NAME_value(names, j)
-                gntype = intmask(name.c_type)
-                if gntype == GEN_DIRNAME:
-                    # we special-case DirName as a tuple of tuples of
-                    # attributes
-                    dirname = libssl_pypy_GENERAL_NAME_dirn(name)
-                    w_t = space.newtuple([
-                        space.wrap("DirName"),
-                        _create_tuple_for_X509_NAME(space, dirname)
-                        ])
-                elif gntype in (GEN_EMAIL, GEN_DNS, GEN_URI):
-                    # GENERAL_NAME_print() doesn't handle NULL bytes in
-                    # ASN1_string correctly, CVE-2013-4238
-                    if gntype == GEN_EMAIL:
-                        v = space.wrap("email")
-                    elif gntype == GEN_DNS:
-                        v = space.wrap("DNS")
-                    elif gntype == GEN_URI:
-                        v = space.wrap("URI")
+                    name = libssl_sk_GENERAL_NAME_value(names, j)
+                    gntype = intmask(name.c_type)
+                    if gntype == GEN_DIRNAME:
+                        # we special-case DirName as a tuple of tuples of
+                        # attributes
+                        dirname = libssl_pypy_GENERAL_NAME_dirn(name)
+                        w_t = space.newtuple([
+                            space.wrap("DirName"),
+                            _create_tuple_for_X509_NAME(space, dirname)
+                            ])
+                    elif gntype in (GEN_EMAIL, GEN_DNS, GEN_URI):
+                        # GENERAL_NAME_print() doesn't handle NULL bytes in
+                        # ASN1_string correctly, CVE-2013-4238
+                        if gntype == GEN_EMAIL:
+                            v = space.wrap("email")
+                        elif gntype == GEN_DNS:
+                            v = space.wrap("DNS")
+                        elif gntype == GEN_URI:
+                            v = space.wrap("URI")
+                        else:
+                            assert False
+                        as_ = libssl_pypy_GENERAL_NAME_dirn(name)
+                        as_ = rffi.cast(ASN1_STRING, as_)
+                        buf = libssl_ASN1_STRING_data(as_)
+                        length = libssl_ASN1_STRING_length(as_)
+                        w_t = space.newtuple([
+                            v, space.wrap(rffi.charpsize2str(buf, length))])
                     else:
-                        assert False
-                    as_ = libssl_pypy_GENERAL_NAME_dirn(name)
-                    as_ = rffi.cast(ASN1_STRING, as_)
-                    buf = libssl_ASN1_STRING_data(as_)
-                    length = libssl_ASN1_STRING_length(as_)
-                    w_t = space.newtuple([
-                        v, space.wrap(rffi.charpsize2str(buf, length))])
-                else:
-                    # for everything else, we use the OpenSSL print form
-                    if gntype not in (GEN_OTHERNAME, GEN_X400, GEN_EDIPARTY,
-                                      GEN_IPADD, GEN_RID):
-                        space.warn(space.wrap("Unknown general name type"),
-                                   space.w_RuntimeWarning)
-                    libssl_BIO_reset(biobuf)
-                    libssl_GENERAL_NAME_print(biobuf, name)
-                    with lltype.scoped_alloc(rffi.CCHARP.TO, 2048) as buf:
-                        length = libssl_BIO_gets(biobuf, buf, 2047)
-                        if length < 0:
-                            raise _ssl_seterror(space, None, 0)
+                        # for everything else, we use the OpenSSL print form
+                        if gntype not in (GEN_OTHERNAME, GEN_X400, 
GEN_EDIPARTY,
+                                          GEN_IPADD, GEN_RID):
+                            space.warn(space.wrap("Unknown general name type"),
+                                       space.w_RuntimeWarning)
+                        libssl_BIO_reset(biobuf)
+                        libssl_GENERAL_NAME_print(biobuf, name)
+                        with lltype.scoped_alloc(rffi.CCHARP.TO, 2048) as buf:
+                            length = libssl_BIO_gets(biobuf, buf, 2047)
+                            if length < 0:
+                                raise _ssl_seterror(space, None, 0)
 
-                        v = rffi.charpsize2str(buf, length)
-                    v1, v2 = v.split(':', 1)
-                    w_t = space.newtuple([space.wrap(v1),
-                                          space.wrap(v2)])
+                            v = rffi.charpsize2str(buf, length)
+                        v1, v2 = v.split(':', 1)
+                        w_t = space.newtuple([space.wrap(v1),
+                                              space.wrap(v2)])
 
-                alt_names_w.append(w_t)
+                    alt_names_w.append(w_t)
+            finally:
+                libssl_pypy_GENERAL_NAME_pop_free(names)
     finally:
         libssl_BIO_free(biobuf)
 
@@ -921,8 +924,11 @@
         length = libssl_ASN1_STRING_to_UTF8(buf_ptr, value)
         if length < 0:
             raise _ssl_seterror(space, None, 0)
-        w_value = space.wrap(rffi.charpsize2str(buf_ptr[0], length))
-        w_value = space.call_method(w_value, "decode", space.wrap("utf-8"))
+        try:
+            w_value = space.wrap(rffi.charpsize2str(buf_ptr[0], length))
+            w_value = space.call_method(w_value, "decode", space.wrap("utf-8"))
+        finally:
+            libssl_OPENSSL_free(buf_ptr[0])
 
     return space.newtuple([w_name, w_value])
 
@@ -930,9 +936,10 @@
 def _get_aia_uri(space, certificate, nid):
     info = rffi.cast(AUTHORITY_INFO_ACCESS, libssl_X509_get_ext_d2i(
         certificate, NID_info_access, None, None))
-    if not info or libssl_sk_ACCESS_DESCRIPTION_num(info) == 0:
-        return
     try:
+        if not info or libssl_sk_ACCESS_DESCRIPTION_num(info) == 0:
+            return
+
         result_w = []
         for i in range(libssl_sk_ACCESS_DESCRIPTION_num(info)):
             ad = libssl_sk_ACCESS_DESCRIPTION_value(info, i)
@@ -962,20 +969,24 @@
     if not dps:
         return None
 
-    cdp_w = []
-    for i in range(libssl_sk_DIST_POINT_num(dps)):
-        dp = libssl_sk_DIST_POINT_value(dps, i)
-        gns = libssl_pypy_DIST_POINT_fullname(dp)
+    try:
+        cdp_w = []
+        for i in range(libssl_sk_DIST_POINT_num(dps)):
+            dp = libssl_sk_DIST_POINT_value(dps, i)
+            gns = libssl_pypy_DIST_POINT_fullname(dp)
 
-        for j in range(libssl_sk_GENERAL_NAME_num(gns)):
-            name = libssl_sk_GENERAL_NAME_value(gns, j)
-            gntype = intmask(name.c_type)
-            if gntype != GEN_URI:
-                continue
-            uri = libssl_pypy_GENERAL_NAME_uri(name)
-            length = intmask(uri.c_length)
-            s_uri = rffi.charpsize2str(uri.c_data, length)
-            cdp_w.append(space.wrap(s_uri))
+            for j in range(libssl_sk_GENERAL_NAME_num(gns)):
+                name = libssl_sk_GENERAL_NAME_value(gns, j)
+                gntype = intmask(name.c_type)
+                if gntype != GEN_URI:
+                    continue
+                uri = libssl_pypy_GENERAL_NAME_uri(name)
+                length = intmask(uri.c_length)
+                s_uri = rffi.charpsize2str(uri.c_data, length)
+                cdp_w.append(space.wrap(s_uri))
+    finally:
+        if OPENSSL_VERSION_NUMBER < 0x10001000:
+            libssl_sk_DIST_POINT_free(dps)
     return space.newtuple(cdp_w[:])
 
 def checkwait(space, w_sock, writing):
@@ -1270,6 +1281,7 @@
         if not ctx:
             raise ssl_error(space, "failed to allocate SSL context")
 
+        rgc.add_memory_pressure(10 * 1024 * 1024)
         self = space.allocate_instance(_SSLContext, w_subtype)
         self.ctx = ctx
         self.check_hostname = False
@@ -1296,6 +1308,9 @@
 
         return self
 
+    def __del__(self):
+        libssl_SSL_CTX_free(self.ctx)
+
     @unwrap_spec(server_side=int)
     def descr_wrap_socket(self, space, w_sock, server_side, 
w_server_hostname=None, w_ssl_sock=None):
         return _SSLSocket.descr_new(space, self, w_sock, server_side, 
w_server_hostname, w_ssl_sock)
diff --git a/pypy/module/cpyext/pystrtod.py b/pypy/module/cpyext/pystrtod.py
--- a/pypy/module/cpyext/pystrtod.py
+++ b/pypy/module/cpyext/pystrtod.py
@@ -5,10 +5,23 @@
 from rpython.rlib import rdtoa
 from rpython.rlib import rfloat
 from rpython.rlib import rposix, jit
+from rpython.rlib.rarithmetic import intmask
 from rpython.rtyper.lltypesystem import lltype
 from rpython.rtyper.lltypesystem import rffi
 
 
+# PyOS_double_to_string's "type", if non-NULL, will be set to one of:
+Py_DTST_FINITE = 0
+Py_DTST_INFINITE = 1
+Py_DTST_NAN = 2
+
+# Match the "type" back to values in CPython
+DOUBLE_TO_STRING_TYPES_MAP = {
+    rfloat.DIST_FINITE: Py_DTST_FINITE,
+    rfloat.DIST_INFINITY: Py_DTST_INFINITE,
+    rfloat.DIST_NAN: Py_DTST_NAN
+}
+
 @cpython_api([rffi.CCHARP, rffi.CCHARPP, PyObject], rffi.DOUBLE, error=-1.0)
 @jit.dont_look_inside       # direct use of _get_errno()
 def PyOS_string_to_double(space, s, endptr, w_overflow_exception):
@@ -68,3 +81,42 @@
     finally:
         if not user_endptr:
             lltype.free(endptr, flavor='raw')
+
+@cpython_api([rffi.DOUBLE, lltype.Char, rffi.INT_real, rffi.INT_real, 
rffi.INTP], rffi.CCHARP)
+def PyOS_double_to_string(space, val, format_code, precision, flags, ptype):
+    """Convert a double val to a string using supplied
+    format_code, precision, and flags.
+
+    format_code must be one of 'e', 'E', 'f', 'F',
+    'g', 'G' or 'r'.  For 'r', the supplied precision
+    must be 0 and is ignored.  The 'r' format code specifies the
+    standard repr() format.
+
+    flags can be zero or more of the values Py_DTSF_SIGN,
+    Py_DTSF_ADD_DOT_0, or Py_DTSF_ALT, or-ed together:
+
+    Py_DTSF_SIGN means to always precede the returned string with a sign
+    character, even if val is non-negative.
+
+    Py_DTSF_ADD_DOT_0 means to ensure that the returned string will not look
+    like an integer.
+
+    Py_DTSF_ALT means to apply "alternate" formatting rules.  See the
+    documentation for the PyOS_snprintf() '#' specifier for
+    details.
+
+    If ptype is non-NULL, then the value it points to will be set to one of
+    Py_DTST_FINITE, Py_DTST_INFINITE, or Py_DTST_NAN, signifying that
+    val is a finite number, an infinite number, or not a number, respectively.
+
+    The return value is a pointer to buffer with the converted string or
+    NULL if the conversion failed. The caller is responsible for freeing the
+    returned string by calling PyMem_Free().
+    """
+    buffer, rtype = rfloat.double_to_string(val, format_code,
+                                            intmask(precision),
+                                            intmask(flags))
+    if ptype != lltype.nullptr(rffi.INTP.TO):
+        ptype[0] = rffi.cast(rffi.INT, DOUBLE_TO_STRING_TYPES_MAP[rtype])
+    bufp = rffi.str2charp(buffer)
+    return bufp
diff --git a/pypy/module/cpyext/test/test_pystrtod.py 
b/pypy/module/cpyext/test/test_pystrtod.py
--- a/pypy/module/cpyext/test/test_pystrtod.py
+++ b/pypy/module/cpyext/test/test_pystrtod.py
@@ -1,5 +1,6 @@
 import math
 
+from pypy.module.cpyext import pystrtod
 from pypy.module.cpyext.test.test_api import BaseApiTest
 from rpython.rtyper.lltypesystem import rffi
 from rpython.rtyper.lltypesystem import lltype
@@ -91,3 +92,76 @@
         api.PyErr_Clear()
         rffi.free_charp(s)
         lltype.free(endp, flavor='raw')
+
+
+class TestPyOS_double_to_string(BaseApiTest):
+
+    def test_format_code(self, api):
+        ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+        r = api.PyOS_double_to_string(150.0, 'e', 1, 0, ptype)
+        assert '1.5e+02' == rffi.charp2str(r)
+        type_value = rffi.cast(lltype.Signed, ptype[0])
+        assert pystrtod.Py_DTST_FINITE == type_value
+        rffi.free_charp(r)
+        lltype.free(ptype, flavor='raw')
+
+    def test_precision(self, api):
+        ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+        r = api.PyOS_double_to_string(3.14159269397, 'g', 5, 0, ptype)
+        assert '3.1416' == rffi.charp2str(r)
+        type_value = rffi.cast(lltype.Signed, ptype[0])
+        assert pystrtod.Py_DTST_FINITE == type_value
+        rffi.free_charp(r)
+        lltype.free(ptype, flavor='raw')
+
+    def test_flags_sign(self, api):
+        ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+        r = api.PyOS_double_to_string(-3.14, 'g', 3, 1, ptype)
+        assert '-3.14' == rffi.charp2str(r)
+        type_value = rffi.cast(lltype.Signed, ptype[0])
+        assert pystrtod.Py_DTST_FINITE == type_value
+        rffi.free_charp(r)
+        lltype.free(ptype, flavor='raw')
+
+    def test_flags_add_dot_0(self, api):
+        ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+        r = api.PyOS_double_to_string(3, 'g', 5, 2, ptype)
+        assert '3.0' == rffi.charp2str(r)
+        type_value = rffi.cast(lltype.Signed, ptype[0])
+        assert pystrtod.Py_DTST_FINITE == type_value
+        rffi.free_charp(r)
+        lltype.free(ptype, flavor='raw')
+
+    def test_flags_alt(self, api):
+        ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+        r = api.PyOS_double_to_string(314., 'g', 3, 4, ptype)
+        assert '314.' == rffi.charp2str(r)
+        type_value = rffi.cast(lltype.Signed, ptype[0])
+        assert pystrtod.Py_DTST_FINITE == type_value
+        rffi.free_charp(r)
+        lltype.free(ptype, flavor='raw')
+
+    def test_ptype_nan(self, api):
+        ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+        r = api.PyOS_double_to_string(float('nan'), 'g', 3, 4, ptype)
+        assert 'nan' == rffi.charp2str(r)
+        type_value = rffi.cast(lltype.Signed, ptype[0])
+        assert pystrtod.Py_DTST_NAN == type_value
+        rffi.free_charp(r)
+        lltype.free(ptype, flavor='raw')
+
+    def test_ptype_infinity(self, api):
+        ptype = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+        r = api.PyOS_double_to_string(1e200 * 1e200, 'g', 0, 0, ptype)
+        assert 'inf' == rffi.charp2str(r)
+        type_value = rffi.cast(lltype.Signed, ptype[0])
+        assert pystrtod.Py_DTST_INFINITE == type_value
+        rffi.free_charp(r)
+        lltype.free(ptype, flavor='raw')
+
+    def test_ptype_null(self, api):
+        ptype = lltype.nullptr(rffi.INTP.TO)
+        r = api.PyOS_double_to_string(3.14, 'g', 3, 0, ptype)
+        assert '3.14' == rffi.charp2str(r)
+        assert ptype == lltype.nullptr(rffi.INTP.TO)
+        rffi.free_charp(r)
\ No newline at end of file
diff --git a/pypy/module/marshal/interp_marshal.py 
b/pypy/module/marshal/interp_marshal.py
--- a/pypy/module/marshal/interp_marshal.py
+++ b/pypy/module/marshal/interp_marshal.py
@@ -156,9 +156,6 @@
     put_tuple_w(TYPE, tuple_w)  puts tuple_w, an unwrapped list of wrapped 
objects
     """
 
-    # _annspecialcase_ = "specialize:ctr_location" # polymorphic
-    # does not work with subclassing
-
     def __init__(self, space, writer, version):
         self.space = space
         ## self.put = putfunc
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
@@ -371,6 +371,8 @@
     @specialize.arg(2)
     def call_method(self, w_obj, s, *args):
         # XXX even the hacks have hacks
+        if s == 'size': # used in _array() but never called by tests
+            return IntObject(0)
         return getattr(w_obj, 'descr_' + s)(self, *args)
 
     @specialize.arg(1)
diff --git a/pypy/module/micronumpy/ctors.py b/pypy/module/micronumpy/ctors.py
--- a/pypy/module/micronumpy/ctors.py
+++ b/pypy/module/micronumpy/ctors.py
@@ -2,6 +2,7 @@
 from pypy.interpreter.gateway import unwrap_spec, WrappedDefault
 from rpython.rlib.buffer import SubBuffer
 from rpython.rlib.rstring import strip_spaces
+from rpython.rlib.rawstorage import RAW_STORAGE_PTR
 from rpython.rtyper.lltypesystem import lltype, rffi
 
 from pypy.module.micronumpy import descriptor, loop, support
@@ -45,7 +46,7 @@
     try:
         w_interface = space.getattr(w_object, 
space.wrap("__array_interface__"))
         if w_interface is None:
-            return None
+            return None, False
         version_w = space.finditem(w_interface, space.wrap("version"))
         if version_w is None:
             raise oefmt(space.w_ValueError, "__array_interface__ found without"
@@ -67,19 +68,46 @@
             raise oefmt(space.w_ValueError,
                     "__array_interface__ missing one or more required keys: 
shape, typestr"
                     )
-        raise oefmt(space.w_NotImplementedError,
-                    "creating array from __array_interface__ not supported 
yet")
-        '''
-        data_w = space.listview()
+        if w_descr is not None:
+            raise oefmt(space.w_NotImplementedError,
+                    "__array_interface__ descr not supported yet")
+        if w_strides is None or space.is_w(w_strides, space.w_None):
+            strides = None
+        else:
+            strides = [space.int_w(i) for i in space.listview(w_strides)]
         shape = [space.int_w(i) for i in space.listview(w_shape)]
         dtype = descriptor.decode_w_dtype(space, w_dtype)
-        rw = space.is_true(data_w[1])
-        '''
-        #print 'create view from 
shape',shape,'dtype',dtype,'descr',w_descr,'data',data_w[0],'rw',rw
-        return None
+        if dtype is None:
+            raise oefmt(space.w_ValueError,
+                    "__array_interface__ could not decode dtype %R", w_dtype
+                    )
+        if w_data is not None and (space.isinstance_w(w_data, space.w_tuple) 
or space.isinstance_w(w_data, space.w_list)):
+            data_w = space.listview(w_data)
+            data = rffi.cast(RAW_STORAGE_PTR, space.int_w(data_w[0]))
+            read_only = True # XXX why not space.is_true(data_w[1])
+            offset = 0
+            return W_NDimArray.from_shape_and_storage(space, shape, data, 
+                                    dtype, strides=strides, start=offset), 
read_only
+        if w_data is None:
+            data = w_object
+        else:
+            data = w_data
+        w_offset = space.finditem(w_interface, space.wrap('offset'))
+        if w_offset is None:
+            offset = 0
+        else:
+            offset = space.int_w(w_offset)
+        #print 'create view from shape',shape,'dtype',dtype,'data',data
+        if strides is not None:
+            raise oefmt(space.w_NotImplementedError,
+                   "__array_interface__ strides not fully supported yet") 
+        arr = frombuffer(space, data, dtype, support.product(shape), offset)
+        new_impl = arr.implementation.reshape(arr, shape)
+        return W_NDimArray(new_impl), False
+        
     except OperationError as e:
         if e.match(space, space.w_AttributeError):
-            return None
+            return None, False
         raise
 
 
@@ -103,19 +131,20 @@
     if space.isinstance_w(w_object, space.w_type):
         raise oefmt(space.w_ValueError, "cannot create ndarray from type 
instance")
     # for anything that isn't already an array, try __array__ method first
+    dtype = descriptor.decode_w_dtype(space, w_dtype)
     if not isinstance(w_object, W_NDimArray):
         w_array = try_array_method(space, w_object, w_dtype)
         if w_array is not None:
             # continue with w_array, but do further operations in place
             w_object = w_array
             copy = False
+            dtype = w_object.get_dtype()
     if not isinstance(w_object, W_NDimArray):
-        w_array = try_interface_method(space, w_object)
+        w_array, _copy = try_interface_method(space, w_object)
         if w_array is not None:
             w_object = w_array
-            copy = False
-    dtype = descriptor.decode_w_dtype(space, w_dtype)
-
+            copy = _copy
+            dtype = w_object.get_dtype()
 
     if isinstance(w_object, W_NDimArray):
         npy_order = order_converter(space, w_order, NPY.ANYORDER)
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
@@ -534,10 +534,10 @@
             while not inner_iter.done(inner_state):
                 arg_driver.jit_merge_point(shapelen=shapelen, dtype=dtype)
                 w_val = inner_iter.getitem(inner_state)
-                new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val)
-                if dtype.itemtype.ne(new_best, cur_best):
+                old_best = getattr(dtype.itemtype, op_name)(cur_best, w_val)
+                if not old_best:
                     result = idx
-                    cur_best = new_best
+                    cur_best = w_val
                 inner_state = inner_iter.next(inner_state)
                 idx += 1
             result = get_dtype_cache(space).w_longdtype.box(result)
@@ -557,17 +557,17 @@
         while not iter.done(state):
             arg_flat_driver.jit_merge_point(shapelen=shapelen, dtype=dtype)
             w_val = iter.getitem(state)
-            new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val)
-            if dtype.itemtype.ne(new_best, cur_best):
+            old_best = getattr(dtype.itemtype, op_name)(cur_best, w_val)
+            if not old_best:
                 result = idx
-                cur_best = new_best
+                cur_best = w_val
             state = iter.next(state)
             idx += 1
         return result
 
     return argmin_argmax, argmin_argmax_flat
-argmin, argmin_flat = _new_argmin_argmax('min')
-argmax, argmax_flat = _new_argmin_argmax('max')
+argmin, argmin_flat = _new_argmin_argmax('argmin')
+argmax, argmax_flat = _new_argmin_argmax('argmax')
 
 dot_driver = jit.JitDriver(name = 'numpy_dot',
                            greens = ['dtype'],
@@ -684,8 +684,9 @@
     arr_iter, arr_state = arr.create_iter()
     arr_dtype = arr.get_dtype()
     index_dtype = index.get_dtype()
-    # XXX length of shape of index as well?
-    while not index_iter.done(index_state):
+    # support the deprecated form where arr([True]) will return arr[0, ...]
+    # by iterating over res_iter, not index_iter
+    while not res_iter.done(res_state):
         getitem_filter_driver.jit_merge_point(shapelen=shapelen,
                                               index_dtype=index_dtype,
                                               arr_dtype=arr_dtype,
diff --git a/pypy/module/micronumpy/test/test_ndarray.py 
b/pypy/module/micronumpy/test/test_ndarray.py
--- a/pypy/module/micronumpy/test/test_ndarray.py
+++ b/pypy/module/micronumpy/test/test_ndarray.py
@@ -1852,6 +1852,24 @@
         a = array([(1, 2)], dtype=[('a', 'int64'), ('b', 'int64')])
         assert a.view('S16')[0] == '\x01' + '\x00' * 7 + '\x02'
 
+    def test_half_conversions(self):
+        from numpy import array, arange
+        from math import isnan, isinf
+        e = array([0, -1, -float('inf'), float('nan'), 6], dtype='float16')
+        assert map(isnan, e) == [False, False, False, True, False]
+        assert map(isinf, e) == [False, False, True, False, False]
+        assert e.argmax() == 3
+        # numpy preserves value for uint16 -> cast_as_float16 -> 
+        #     convert_to_float64 -> convert_to_float16 -> uint16
+        #  even for float16 various float16 nans
+        all_f16 = arange(0xfe00, 0xffff, dtype='uint16')
+        all_f16.dtype = 'float16'
+        all_f32 = array(all_f16, dtype='float32')
+        b = array(all_f32, dtype='float16')
+        c = b.view(dtype='uint16')
+        d = all_f16.view(dtype='uint16')
+        assert (c == d).all()
+
     def test_ndarray_view_empty(self):
         from numpy import array, dtype
         x = array([], dtype=[('a', 'int8'), ('b', 'int8')])
@@ -2220,6 +2238,9 @@
         c = array([True,False,True],bool)
         b = a[c]
         assert (a[c] == [[1, 2, 3], [7, 8, 9]]).all()
+        c = array([True])
+        b = a[c]
+        assert b.shape == (1, 3)
 
     def test_bool_array_index_setitem(self):
         from numpy import arange, array
@@ -3052,7 +3073,7 @@
         assert (b == zeros(10)).all()
 
     def test_array_interface(self):
-        from numpy import array
+        from numpy import array, ones
         a = array(2.5)
         i = a.__array_interface__
         assert isinstance(i['data'][0], int)
@@ -3075,7 +3096,7 @@
 
         class Dummy(object):
             def __init__(self, aif=None):
-                if aif:
+                if aif is not None:
                     self.__array_interface__ = aif
 
         a = array(Dummy())
@@ -3084,6 +3105,31 @@
         raises(ValueError, array, Dummy({'version': 0}))
         raises(ValueError, array, Dummy({'version': 'abc'}))
         raises(ValueError, array, Dummy({'version': 3}))
+        raises(TypeError, array, Dummy({'version': 3, 'typestr': 'f8', 
'shape': ('a', 3)}))
+
+        a = array([1, 2, 3])
+        b = array(Dummy(a.__array_interface__))
+        b[1] = 200
+        assert a[1] == 2 # upstream compatibility, is this a bug?
+        interface_a = a.__array_interface__
+        interface_b = b.__array_interface__
+        # only the data[0] value should differ
+        assert interface_a['data'][0] != interface_b['data'][0]
+        assert interface_b['data'][1] == interface_a['data'][1]
+        interface_b.pop('data')
+        interface_a.pop('data')
+        assert interface_a == interface_b
+
+        b = array(Dummy({'version':3, 'shape': (50,), 'typestr': 'u1',
+                         'data': 'a'*100}))
+        assert b.dtype == 'uint8'
+        assert b.shape == (50,)
+
+        a = ones((1,), dtype='float16')
+        b = Dummy(a.__array_interface__)
+        c = array(b)
+        assert c.dtype == 'float16'
+        assert (a == c).all()
 
     def test_array_indexing_one_elem(self):
         from numpy import array, arange
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
@@ -345,6 +345,14 @@
     def min(self, v1, v2):
         return min(v1, v2)
 
+    @raw_binary_op
+    def argmax(self, v1, v2):
+        return v1 >= v2
+
+    @raw_binary_op
+    def argmin(self, v1, v2):
+        return v1 <= v2
+
     @raw_unary_op
     def rint(self, v):
         float64 = Float64(self.space)
@@ -820,6 +828,14 @@
     def min(self, v1, v2):
         return v1 if v1 <= v2 or rfloat.isnan(v1) else v2
 
+    @raw_binary_op
+    def argmax(self, v1, v2):
+        return v1 >= v2 or rfloat.isnan(v1)
+
+    @raw_binary_op
+    def argmin(self, v1, v2):
+        return v1 <= v2 or rfloat.isnan(v1)
+
     @simple_binary_op
     def fmax(self, v1, v2):
         return v1 if v1 >= v2 or rfloat.isnan(v2) else v2
@@ -1407,6 +1423,16 @@
             return v1
         return v2
 
+    def argmin(self, v1, v2):
+        if self.le(v1, v2) or self.isnan(v1):
+            return True
+        return False
+
+    def argmax(self, v1, v2):
+        if self.ge(v1, v2) or self.isnan(v1):
+            return True
+        return False
+
     @complex_binary_op
     def floordiv(self, v1, v2):
         (r1, i1), (r2, i2) = v1, v2
@@ -1927,6 +1953,18 @@
             return v1
         return v2
 
+    @raw_binary_op
+    def argmax(self, v1, v2):
+        if self.space.is_true(self.space.ge(v1, v2)):
+            return True
+        return False
+
+    @raw_binary_op
+    def argmin(self, v1, v2):
+        if self.space.is_true(self.space.le(v1, v2)):
+            return True
+        return False
+
     @raw_unary_op
     def bool(self,v):
         return self._obool(v)
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
@@ -248,3 +248,23 @@
         loop, = log.loops_by_filename(self.filepath)
         ops = loop.ops_by_id('getitem', include_guard_not_invalidated=False)
         assert log.opnames(ops) == []
+
+    def test_enumerate_list(self):
+        def main(n):
+            for a, b in enumerate([1, 2] * 1000):
+                a + b
+
+        log = self.run(main, [1000])
+        loop, = log.loops_by_filename(self.filepath)
+        opnames = log.opnames(loop.allops())
+        assert opnames.count('new_with_vtable') == 0
+
+    def test_enumerate(self):
+        def main(n):
+            for a, b in enumerate("abc" * 1000):
+                a + ord(b)
+
+        log = self.run(main, [1000])
+        loop, = log.loops_by_filename(self.filepath)
+        opnames = log.opnames(loop.allops())
+        assert opnames.count('new_with_vtable') == 0
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py 
b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
@@ -1336,7 +1336,8 @@
         # these depend on user-defined data, so should not be shared
         assert ffi1.typeof("struct foo") is not ffi2.typeof("struct foo")
         assert ffi1.typeof("union foo *") is not ffi2.typeof("union foo*")
-        assert ffi1.typeof("enum foo") is not ffi2.typeof("enum foo")
+        # the following test is an opaque enum, which we no longer support
+        #assert ffi1.typeof("enum foo") is not ffi2.typeof("enum foo")
         # sanity check: twice 'ffi1'
         assert ffi1.typeof("struct foo*") is ffi1.typeof("struct foo *")
 
@@ -1348,6 +1349,17 @@
         assert ffi.getctype("pe") == 'e *'
         assert ffi.getctype("e1*") == 'e1 *'
 
+    def test_opaque_enum(self):
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("enum foo;")
+        from cffi import __version_info__
+        if __version_info__ < (1, 4):
+            py.test.skip("re-enable me in version 1.4")
+        e = py.test.raises(CDefError, ffi.cast, "enum foo", -1)
+        assert str(e.value) == (
+            "'enum foo' has no values explicitly defined: refusing to guess "
+            "which integer type it is meant to be (unsigned/signed, int/long)")
+
     def test_new_ctype(self):
         ffi = FFI(backend=self.Backend())
         p = ffi.new("int *")
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_commontypes.py 
b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_commontypes.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_commontypes.py
@@ -0,0 +1,35 @@
+# Generated by pypy/tool/import_cffi.py
+import py, os, cffi, re
+import _cffi_backend
+
+
+def getlines():
+    try:
+        f = open(os.path.join(os.path.dirname(cffi.__file__),
+                              '..', 'c', 'commontypes.c'))
+    except IOError:
+        py.test.skip("cannot find ../c/commontypes.c")
+    lines = [line for line in f.readlines() if line.strip().startswith('EQ(')]
+    f.close()
+    return lines
+
+def test_alphabetical_order():
+    lines = getlines()
+    assert lines == sorted(lines)
+
+def test_dependencies():
+    r = re.compile(r'EQ[(]"([^"]+)",(?:\s*"([A-Z0-9_]+)\s*[*]*"[)])?')
+    lines = getlines()
+    d = {}
+    for line in lines:
+        match = r.search(line)
+        if match is not None:
+            d[match.group(1)] = match.group(2)
+    for value in d.values():
+        if value:
+            assert value in d
+
+def test_get_common_types():
+    d = {}
+    _cffi_backend._get_common_types(d)
+    assert d["bool"] == "_Bool"
diff --git a/pypy/objspace/std/bytearrayobject.py 
b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -1231,6 +1231,21 @@
     def setitem(self, index, char):
         self.data[index] = char
 
+    def getslice(self, start, stop, step, size):
+        if size == 0:
+            return ""
+        if step == 1:
+            assert 0 <= start <= stop
+            if start == 0 and stop == len(self.data):
+                return "".join(self.data)
+            return "".join(self.data[start:stop])
+        return Buffer.getslice(self, start, stop, step, size)
+
+    def setslice(self, start, string):
+        # No bounds checks.
+        for i in range(len(string)):
+            self.data[start + i] = string[i]
+
 
 @specialize.argtype(1)
 def _memcmp(selfvalue, buffer, length):
diff --git a/pypy/objspace/std/test/test_tupleobject.py 
b/pypy/objspace/std/test/test_tupleobject.py
--- a/pypy/objspace/std/test/test_tupleobject.py
+++ b/pypy/objspace/std/test/test_tupleobject.py
@@ -413,8 +413,9 @@
             from __pypy__ import specialized_zip_2_lists
         except ImportError:
             specialized_zip_2_lists = zip
-        raises(TypeError, specialized_zip_2_lists, [], ())
-        raises(TypeError, specialized_zip_2_lists, (), [])
+        else:
+            raises(TypeError, specialized_zip_2_lists, [], ())
+            raises(TypeError, specialized_zip_2_lists, (), [])
         assert specialized_zip_2_lists([], []) == [
             ]
         assert specialized_zip_2_lists([2, 3], []) == [
diff --git a/pypy/tool/ann_override.py b/pypy/tool/ann_override.py
--- a/pypy/tool/ann_override.py
+++ b/pypy/tool/ann_override.py
@@ -2,6 +2,7 @@
 from rpython.annotator.policy import AnnotatorPolicy
 from rpython.flowspace.model import Constant
 from rpython.annotator import specialize
+from rpython.annotator.classdesc import InstanceSource, ClassDef
 
 
 
@@ -20,7 +21,6 @@
 
     def specialize__wrap(self,  funcdesc, args_s):
         from pypy.interpreter.baseobjspace import W_Root
-        from rpython.annotator.classdef import ClassDef
         W_Root_def = funcdesc.bookkeeper.getuniqueclassdef(W_Root)
         typ = args_s[1].knowntype
         if isinstance(typ, ClassDef):
@@ -50,54 +50,34 @@
                 typ = (None, str)
         return funcdesc.cachedgraph(typ)
 
-    def _remember_immutable(self, t, cached):
-        # for jit benefit
-        if cached not in t._immutable_fields_: # accessed this way just
-                                               # for convenience
-            t._immutable_fields_.append(cached)
-
-    def attach_lookup(self, t, attr):
-        cached = "cached_%s" % attr
-        if not t.is_heaptype() and not t.is_cpytype():
-            self._remember_immutable(t, cached)
-            setattr(t, cached, t._lookup(attr))
-            return True
-        return False
-
-    def attach_lookup_in_type_where(self, t, attr):
-        cached = "cached_where_%s" % attr
-        if not t.is_heaptype() and not t.is_cpytype():
-            self._remember_immutable(t, cached)
-            setattr(t, cached, t._lookup_where(attr))
-            return True
-        return False
-
     def consider_lookup(self, bookkeeper, attr):
-        from rpython.annotator.classdef import InstanceSource
         assert attr not in self.lookups
         from pypy.objspace.std import typeobject
         cached = "cached_%s" % attr
         clsdef = bookkeeper.getuniqueclassdef(typeobject.W_TypeObject)
         classdesc = clsdef.classdesc
+        classdesc.immutable_fields.add(cached)
         classdesc.classdict[cached] = Constant(None)
         clsdef.add_source_for_attribute(cached, classdesc)
         for t in self.pypytypes:
-            if self.attach_lookup(t, attr):
+            if not (t.is_heaptype() or t.is_cpytype()):
+                setattr(t, cached, t._lookup(attr))
                 source = InstanceSource(bookkeeper, t)
                 clsdef.add_source_for_attribute(cached, source)
         self.lookups[attr] = True
 
     def consider_lookup_in_type_where(self, bookkeeper, attr):
-        from rpython.annotator.classdef import InstanceSource
         assert attr not in self.lookups_where
         from pypy.objspace.std import typeobject
         cached = "cached_where_%s" % attr
         clsdef = bookkeeper.getuniqueclassdef(typeobject.W_TypeObject)
         classdesc = clsdef.classdesc
+        classdesc.immutable_fields.add(cached)
         classdesc.classdict[cached] = Constant((None, None))
         clsdef.add_source_for_attribute(cached, classdesc)
         for t in self.pypytypes:
-            if self.attach_lookup_in_type_where(t, attr):
+            if not (t.is_heaptype() or t.is_cpytype()):
+                setattr(t, cached, t._lookup_where(attr))
                 source = InstanceSource(bookkeeper, t)
                 clsdef.add_source_for_attribute(cached, source)
         self.lookups_where[attr] = True
@@ -135,18 +115,19 @@
     def event(self, bookkeeper, what, x):
         from pypy.objspace.std import typeobject
         if isinstance(x, typeobject.W_TypeObject):
-            from rpython.annotator.classdef import InstanceSource
             clsdef = bookkeeper.getuniqueclassdef(typeobject.W_TypeObject)
             self.pypytypes[x] = True
             #print "TYPE", x
             for attr in self.lookups:
-                if attr and self.attach_lookup(x, attr):
+                if attr and not (x.is_heaptype() or x.is_cpytype()):
                     cached = "cached_%s" % attr
+                    setattr(x, cached, x._lookup(attr))
                     source = InstanceSource(bookkeeper, x)
                     clsdef.add_source_for_attribute(cached, source)
             for attr in self.lookups_where:
-                if attr and self.attach_lookup_in_type_where(x, attr):
+                if attr and not (x.is_heaptype() or x.is_cpytype()):
                     cached = "cached_where_%s" % attr
+                    setattr(x, cached, x._lookup_where(attr))
                     source = InstanceSource(bookkeeper, x)
                     clsdef.add_source_for_attribute(cached, source)
         return
diff --git a/rpython/annotator/bookkeeper.py b/rpython/annotator/bookkeeper.py
--- a/rpython/annotator/bookkeeper.py
+++ b/rpython/annotator/bookkeeper.py
@@ -14,8 +14,8 @@
     SomeDict, SomeBuiltin, SomePBC, SomeInteger, TLS, SomeUnicodeCodePoint,
     s_None, s_ImpossibleValue, SomeBool, SomeTuple,
     SomeImpossibleValue, SomeUnicodeString, SomeList, HarmlesslyBlocked,
-    SomeWeakRef, SomeByteArray, SomeConstantType, SomeProperty, AnnotatorError)
-from rpython.annotator.classdef import InstanceSource, ClassDef
+    SomeWeakRef, SomeByteArray, SomeConstantType, SomeProperty)
+from rpython.annotator.classdesc import ClassDef, ClassDesc
 from rpython.annotator.listdef import ListDef, ListItem
 from rpython.annotator.dictdef import DictDef
 from rpython.annotator import description
@@ -23,7 +23,6 @@
 from rpython.annotator.argument import simple_args
 from rpython.rlib.objectmodel import r_dict, r_ordereddict, Symbolic
 from rpython.tool.algo.unionfind import UnionFind
-from rpython.tool.flattenrec import FlattenRecursion
 from rpython.rtyper import extregistry
 
 
@@ -163,9 +162,7 @@
             s_callable.consider_call_site(args, s_result, call_op)
 
     def getuniqueclassdef(self, cls):
-        """Get the ClassDef associated with the given user cls.
-        Avoid using this!  It breaks for classes that must be specialized.
-        """
+        """Get the ClassDef associated with the given user cls."""
         assert cls is not object
         desc = self.getdesc(cls)
         return desc.getuniqueclassdef()
@@ -334,8 +331,9 @@
                  and x.__class__.__module__ != '__builtin__':
             if hasattr(x, '_cleanup_'):
                 x._cleanup_()
-            self.see_mutable(x)
-            result = SomeInstance(self.getuniqueclassdef(x.__class__))
+            classdef = self.getuniqueclassdef(x.__class__)
+            classdef.see_instance(x)
+            result = SomeInstance(classdef)
         elif x is None:
             return s_None
         else:
@@ -362,7 +360,7 @@
                 if pyobj.__module__ == '__builtin__': # avoid making classdefs 
for builtin types
                     result = self.getfrozen(pyobj)
                 else:
-                    result = description.ClassDesc(self, pyobj)
+                    result = ClassDesc(self, pyobj)
             elif isinstance(pyobj, types.MethodType):
                 if pyobj.im_self is None:   # unbound
                     return self.getdesc(pyobj.im_func)
@@ -375,11 +373,11 @@
                         self.getdesc(pyobj.im_self))            # frozendesc
                 else: # regular method
                     origincls, name = origin_of_meth(pyobj)
-                    self.see_mutable(pyobj.im_self)
+                    classdef = self.getuniqueclassdef(pyobj.im_class)
+                    classdef.see_instance(pyobj.im_self)
                     assert pyobj == getattr(pyobj.im_self, name), (
                         "%r is not %s.%s ??" % (pyobj, pyobj.im_self, name))
                     # emulate a getattr to make sure it's on the classdef
-                    classdef = self.getuniqueclassdef(pyobj.im_class)
                     classdef.find_attribute(name)
                     result = self.getmethoddesc(
                         self.getdesc(pyobj.im_func),            # funcdesc
@@ -400,15 +398,6 @@
             self.descs[pyobj] = result
             return result
 
-    def have_seen(self, x):
-        # this might need to expand some more.
-        if x in self.descs:
-            return True
-        elif (x.__class__, x) in self.seen_mutable:
-            return True
-        else:
-            return False
-
     def getfrozen(self, pyobj):
         return description.FrozenDesc(self, pyobj)
 
@@ -425,22 +414,6 @@
             self.methoddescs[key] = result
             return result
 
-    _see_mutable_flattenrec = FlattenRecursion()
-
-    def see_mutable(self, x):
-        key = (x.__class__, x)
-        if key in self.seen_mutable:
-            return
-        clsdef = self.getuniqueclassdef(x.__class__)
-        self.seen_mutable[key] = True
-        self.event('mutable', x)
-        source = InstanceSource(self, x)
-        def delayed():
-            for attr in source.all_instance_attributes():
-                clsdef.add_source_for_attribute(attr, source)
-                # ^^^ can trigger reflowing
-        self._see_mutable_flattenrec(delayed)
-
     def valueoftype(self, t):
         return annotationoftype(t, self)
 
@@ -495,6 +468,20 @@
 
         return s_result
 
+    def getattr_locations(self, clsdesc, attrname):
+        attrdef = clsdesc.classdef.find_attribute(attrname)
+        return attrdef.read_locations
+
+    def record_getattr(self, clsdesc, attrname):
+        locations = self.getattr_locations(clsdesc, attrname)
+        locations.add(self.position_key)
+
+    def update_attr(self, clsdef, attrdef):
+        locations = self.getattr_locations(clsdef.classdesc, attrdef.name)
+        for position in locations:
+            self.annotator.reflowfromposition(position)
+        attrdef.validate(homedef=clsdef)
+
     def pbc_call(self, pbc, args, emulated=None):
         """Analyse a call to a SomePBC() with the given args (list of
         annotations).
diff --git a/rpython/annotator/builtin.py b/rpython/annotator/builtin.py
--- a/rpython/annotator/builtin.py
+++ b/rpython/annotator/builtin.py
@@ -5,13 +5,14 @@
 from collections import OrderedDict
 
 from rpython.annotator.model import (
-    SomeInteger, SomeObject, SomeChar, SomeBool, SomeString, SomeTuple,
+    SomeInteger, SomeChar, SomeBool, SomeString, SomeTuple,
     SomeUnicodeCodePoint, SomeFloat, unionof, SomeUnicodeString,
     SomePBC, SomeInstance, SomeDict, SomeList, SomeWeakRef, SomeIterator,
     SomeOrderedDict, SomeByteArray, add_knowntypedata, s_ImpossibleValue,)
 from rpython.annotator.bookkeeper import (
     getbookkeeper, immutablevalue, BUILTIN_ANALYZERS, analyzer_for)
 from rpython.annotator import description
+from rpython.annotator.classdesc import ClassDef
 from rpython.flowspace.model import Constant
 import rpython.rlib.rarithmetic
 import rpython.rlib.objectmodel
@@ -124,7 +125,6 @@
 
 def our_issubclass(cls1, cls2):
     """ we're going to try to be less silly in the face of old-style classes"""
-    from rpython.annotator.classdef import ClassDef
     if cls2 is object:
         return True
     def classify(cls):
diff --git a/rpython/annotator/classdef.py b/rpython/annotator/classdef.py
deleted file mode 100644
--- a/rpython/annotator/classdef.py
+++ /dev/null
@@ -1,434 +0,0 @@
-"""
-Type inference for user-defined classes.
-"""
-from rpython.annotator.model import (
-    SomePBC, s_ImpossibleValue, unionof, s_None, AnnotatorError)
-from rpython.annotator import description
-
-
-# The main purpose of a ClassDef is to collect information about class/instance
-# attributes as they are really used.  An Attribute object is stored in the
-# most general ClassDef where an attribute of that name is read/written:
-#    classdef.attrs = {'attrname': Attribute()}
-#
-# The following invariants hold:
-#
-# (A) if an attribute is read/written on an instance of class A, then the
-#     classdef of A or a parent class of A has an Attribute object 
corresponding
-#     to that name.
-#
-# (I) if B is a subclass of A, then they don't both have an Attribute for the
-#     same name.  (All information from B's Attribute must be merged into A's.)
-#
-# Additionally, each ClassDef records an 'attr_sources': it maps attribute 
names
-# to a list of 'source' objects that want to provide a constant value for this
-# attribute at the level of this class.  The attr_sources provide information
-# higher in the class hierarchy than concrete Attribute()s.  It is for the case
-# where (so far or definitely) the user program only reads/writes the attribute
-# at the level of a subclass, but a value for this attribute could possibly
-# exist in the parent class or in an instance of a parent class.
-#
-# The point of not automatically forcing the Attribute instance up to the
-# parent class which has a class attribute of the same name is apparent with
-# multiple subclasses:
-#
-#                                    A
-#                                 attr=s1
-#                                  /   \
-#                                 /     \
-#                                B       C
-#                             attr=s2  attr=s3
-#
-# XXX this does not seem to be correct, but I don't know how to phrase
-#     it correctly. See test_specific_attributes in test_annrpython
-#
-# In this case, as long as 'attr' is only read/written from B or C, the
-# Attribute on B says that it can be 's1 or s2', and the Attribute on C says
-# it can be 's1 or s3'.  Merging them into a single Attribute on A would give
-# the more imprecise 's1 or s2 or s3'.
-#
-# The following invariant holds:
-#
-# (II) if a class A has an Attribute, the 'attr_sources' for the same name is
-#      empty.  It is also empty on all subclasses of A.  (The information goes
-#      into the Attribute directly in this case.)
-#
-# The following invariant holds:
-#
-#  (III) for a class A, each attrsource that comes from the class (as opposed 
to
-#        from a prebuilt instance) must be merged into all Attributes of the
-#        same name in all subclasses of A, if any.  (Parent class attributes 
can
-#        be visible in reads from instances of subclasses.)
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to