[pypy-commit] pypy win32-stdlib: merge default into branch

mattip noreply at buildbot.pypy.org
Sat Apr 21 20:43:52 CEST 2012


Author: Matti Picus <matti.picus at gmail.com>
Branch: win32-stdlib
Changeset: r54609:af9cef062227
Date: 2012-04-21 21:39 +0300
http://bitbucket.org/pypy/pypy/changeset/af9cef062227/

Log:	merge default into branch

diff --git a/_pytest/assertion/oldinterpret.py b/_pytest/assertion/oldinterpret.py
--- a/_pytest/assertion/oldinterpret.py
+++ b/_pytest/assertion/oldinterpret.py
@@ -1,8 +1,7 @@
 import py
 import sys, inspect
 from compiler import parse, ast, pycodegen
-from _pytest.assertion.util import format_explanation
-from _pytest.assertion.reinterpret import BuiltinAssertionError
+from _pytest.assertion.util import format_explanation, BuiltinAssertionError
 
 passthroughex = py.builtin._sysex
 
diff --git a/_pytest/assertion/reinterpret.py b/_pytest/assertion/reinterpret.py
--- a/_pytest/assertion/reinterpret.py
+++ b/_pytest/assertion/reinterpret.py
@@ -1,7 +1,6 @@
 import sys
 import py
-
-BuiltinAssertionError = py.builtin.builtins.AssertionError
+from _pytest.assertion.util import BuiltinAssertionError
 
 class AssertionError(BuiltinAssertionError):
     def __init__(self, *args):
diff --git a/_pytest/assertion/util.py b/_pytest/assertion/util.py
--- a/_pytest/assertion/util.py
+++ b/_pytest/assertion/util.py
@@ -2,6 +2,7 @@
 
 import py
 
+BuiltinAssertionError = py.builtin.builtins.AssertionError
 
 # The _reprcompare attribute on the util module is used by the new assertion
 # interpretation code and assertion rewriter to detect this plugin was
diff --git a/lib_pypy/_ctypes/builtin.py b/lib_pypy/_ctypes/builtin.py
--- a/lib_pypy/_ctypes/builtin.py
+++ b/lib_pypy/_ctypes/builtin.py
@@ -3,7 +3,8 @@
 try:
     from thread import _local as local
 except ImportError:
-    local = object    # no threads
+    class local(object):    # no threads
+        pass
 
 class ConvMode:
     encoding = 'ascii'
diff --git a/lib_pypy/numpypy/core/fromnumeric.py b/lib_pypy/numpypy/core/fromnumeric.py
--- a/lib_pypy/numpypy/core/fromnumeric.py
+++ b/lib_pypy/numpypy/core/fromnumeric.py
@@ -411,7 +411,8 @@
             [3, 7]]])
 
     """
-    raise NotImplementedError('Waiting on interp level method')
+    swapaxes = a.swapaxes
+    return swapaxes(axis1, axis2)
 
 
 def transpose(a, axes=None):
diff --git a/lib_pypy/pyrepl/reader.py b/lib_pypy/pyrepl/reader.py
--- a/lib_pypy/pyrepl/reader.py
+++ b/lib_pypy/pyrepl/reader.py
@@ -152,8 +152,8 @@
      (r'\<delete>', 'delete'),
      (r'\<backspace>', 'backspace'),
      (r'\M-\<backspace>', 'backward-kill-word'),
-     (r'\<end>', 'end'),
-     (r'\<home>', 'home'),
+     (r'\<end>', 'end-of-line'),         # was 'end'
+     (r'\<home>', 'beginning-of-line'),  # was 'home'
      (r'\<f1>', 'help'),
      (r'\EOF', 'end'),  # the entries in the terminfo database for xterms
      (r'\EOH', 'home'), # seem to be wrong.  this is a less than ideal
diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -229,8 +229,8 @@
                     return thing
                 elif hasattr(thing, '__name__'): # mostly types and functions
                     return thing.__name__
-                elif hasattr(thing, 'name'): # mostly ClassDescs
-                    return thing.name
+                elif hasattr(thing, 'name') and isinstance(thing.name, str):
+                    return thing.name            # mostly ClassDescs
                 elif isinstance(thing, tuple):
                     return '_'.join(map(nameof, thing))
                 else:
diff --git a/pypy/annotation/test/test_annrpython.py b/pypy/annotation/test/test_annrpython.py
--- a/pypy/annotation/test/test_annrpython.py
+++ b/pypy/annotation/test/test_annrpython.py
@@ -3746,9 +3746,9 @@
             return g(i)
         def main(i):
             if i == 2:
-                return f(i)
+                return f(2)
             elif i == 3:
-                return f(i)
+                return f(3)
             else:
                 raise NotImplementedError
 
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -320,10 +320,14 @@
                    default=False),
         BoolOption("getattributeshortcut",
                    "track types that override __getattribute__",
-                   default=False),
+                   default=False,
+                   # weakrefs needed, because of get_subclasses()
+                   requires=[("translation.rweakref", True)]),
         BoolOption("newshortcut",
                    "cache and shortcut calling __new__ from builtin types",
-                   default=False),
+                   default=False,
+                   # weakrefs needed, because of get_subclasses()
+                   requires=[("translation.rweakref", True)]),
 
         BoolOption("logspaceoptypes",
                    "a instrumentation option: before exit, print the types seen by "
@@ -337,7 +341,9 @@
                    requires=[("objspace.std.builtinshortcut", True)]),
         BoolOption("withidentitydict",
                    "track types that override __hash__, __eq__ or __cmp__ and use a special dict strategy for those which do not",
-                   default=False),
+                   default=False,
+                   # weakrefs needed, because of get_subclasses()
+                   requires=[("translation.rweakref", True)]),
      ]),
 ])
 
diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/cppyy.rst
@@ -0,0 +1,333 @@
+============================
+cppyy: C++ bindings for PyPy
+============================
+
+The cppyy module provides C++ bindings for PyPy by using the reflection
+information extracted from C++ header files by means of the
+`Reflex package`_.
+For this to work, you have to both install Reflex and build PyPy from the
+reflex-support branch.
+As indicated by this being a branch, support for Reflex is still
+experimental.
+However, it is functional enough to put it in the hands of those who want
+to give it a try.
+In the medium term, cppyy will move away from Reflex and instead use
+`cling`_ as its backend, which is based on `llvm`_.
+Although that will change the logistics on the generation of reflection
+information, it will not change the python-side interface.
+
+.. _`Reflex package`: http://root.cern.ch/drupal/content/reflex
+.. _`cling`: http://root.cern.ch/drupal/content/cling
+.. _`llvm`: http://llvm.org/
+
+
+Installation
+============
+
+For now, the easiest way of getting the latest version of Reflex, is by
+installing the ROOT package.
+Besides getting the latest version of Reflex, another advantage is that with
+the full ROOT package, you can also use your Reflex-bound code on `CPython`_.
+`Download`_ a binary or install from `source`_.
+Some Linux and Mac systems may have ROOT provided in the list of scientific
+software of their packager.
+A current, standalone version of Reflex should be provided at some point,
+once the dependencies and general packaging have been thought out.
+Also, make sure you have a version of `gccxml`_ installed, which is most
+easily provided by the packager of your system.
+If you read up on gccxml, you'll probably notice that it is no longer being
+developed and hence will not provide C++11 support.
+That's why the medium term plan is to move to `cling`_.
+
+.. _`Download`: http://root.cern.ch/drupal/content/downloading-root
+.. _`source`: http://root.cern.ch/drupal/content/installing-root-source
+.. _`gccxml`: http://www.gccxml.org
+
+Next, get the `PyPy sources`_, select the reflex-support branch, and build
+pypy-c.
+For the build to succeed, the ``$ROOTSYS`` environment variable must point to
+the location of your ROOT installation::
+
+    $ hg clone https://bitbucket.org/pypy/pypy
+    $ cd pypy
+    $ hg up reflex-support
+    $ cd pypy/translator/goal
+    $ python translate.py -O jit --gcrootfinder=shadowstack targetpypystandalone.py --withmod-cppyy
+
+This will build a ``pypy-c`` that includes the cppyy module, and through that,
+Reflex support.
+Of course, if you already have a pre-built version of the ``pypy`` interpreter,
+you can use that for the translation rather than ``python``.
+
+.. _`PyPy sources`: https://bitbucket.org/pypy/pypy/overview
+
+
+Basic example
+=============
+
+Now test with a trivial example whether all packages are properly installed
+and functional.
+First, create a C++ header file with some class in it (note that all functions
+are made inline for convenience; a real-world example would of course have a
+corresponding source file)::
+
+    $ cat MyClass.h
+    class MyClass {
+    public:
+        MyClass(int i = -99) : m_myint(i) {}
+
+        int GetMyInt() { return m_myint; }
+        void SetMyInt(int i) { m_myint = i; }
+
+    public:
+       int m_myint;
+    };
+
+Then, generate the bindings using ``genreflex`` (part of ROOT), and compile the
+code::
+
+    $ genreflex MyClass.h
+    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o libMyClassDict.so
+
+Now you're ready to use the bindings.
+Since the bindings are designed to look pythonistic, it should be
+straightforward::
+
+    $ pypy-c
+    >>>> import cppyy
+    >>>> cppyy.load_reflection_info("libMyClassDict.so")
+    <CPPLibrary object at 0xb6fd7c4c>
+    >>>> myinst = cppyy.gbl.MyClass(42)
+    >>>> print myinst.GetMyInt()
+    42
+    >>>> myinst.SetMyInt(33)
+    >>>> print myinst.m_myint
+    33
+    >>>> myinst.m_myint = 77
+    >>>> print myinst.GetMyInt()
+    77
+    >>>> help(cppyy.gbl.MyClass)   # shows that normal python introspection works
+
+That's all there is to it!
+
+
+Features
+========
+
+The following is not meant to be an exhaustive list, since cppyy is still
+under active development.
+Furthermore, the intention is that every feature is as natural as possible on
+the python side, so if you find something missing in the list below, simply
+try it out.
+It is not always possible to provide exact mapping between python and C++
+(active memory management is one such case), but by and large, if the use of a
+feature does not strike you as obvious, it is more likely to simply be a bug.
+That is a strong statement to make, but also a worthy goal.
+
+* **abstract classes**: Are represented as python classes, since they are
+  needed to complete the inheritance hierarchies, but will raise an exception
+  if an attempt is made to instantiate from them.
+
+* **arrays**: Supported for builtin data types only, as used from module
+  ``array``.
+  Out-of-bounds checking is limited to those cases where the size is known at
+  compile time (and hence part of the reflection info).
+
+* **builtin data types**: Map onto the expected equivalent python types, with
+  the caveat that there may be size differences, and thus it is possible that
+  exceptions are raised if an overflow is detected.
+
+* **casting**: Is supposed to be unnecessary.
+  Object pointer returns from functions provide the most derived class known
+  in the hierarchy of the object being returned.
+  This is important to preserve object identity as well as to make casting,
+  a pure C++ feature after all, superfluous.
+
+* **classes and structs**: Get mapped onto python classes, where they can be
+  instantiated as expected.
+  If classes are inner classes or live in a namespace, their naming and
+  location will reflect that.
+
+* **data members**: Public data members are represented as python properties
+  and provide read and write access on instances as expected.
+
+* **default arguments**: C++ default arguments work as expected, but python
+  keywords are not supported.
+  It is technically possible to support keywords, but for the C++ interface,
+  the formal argument names have no meaning and are not considered part of the
+  API, hence it is not a good idea to use keywords.
+
+* **doc strings**: The doc string of a method or function contains the C++
+  arguments and return types of all overloads of that name, as applicable.
+
+* **functions**: Work as expected and live in their appropriate namespace
+  (which can be the global one, ``cppyy.gbl``).
+
+* **inheritance**: All combinations of inheritance on the C++ (single,
+  multiple, virtual) are supported in the binding.
+  However, new python classes can only use single inheritance from a bound C++
+  class.
+  Multiple inheritance would introduce two "this" pointers in the binding.
+  This is a current, not a fundamental, limitation.
+  The C++ side will not see any overridden methods on the python side, as
+  cross-inheritance is planned but not yet supported.
+
+* **methods**: Are represented as python methods and work as expected.
+  They are first class objects and can be bound to an instance.
+  Virtual C++ methods work as expected.
+  To select a specific virtual method, do like with normal python classes
+  that override methods: select it from the class that you need, rather than
+  calling the method on the instance.
+
+* **namespaces**: Are represented as python classes.
+  Namespaces are more open-ended than classes, so sometimes initial access may
+  result in updates as data and functions are looked up and constructed
+  lazily.
+  Thus the result of ``dir()`` on a namespace should not be relied upon: it
+  only shows the already accessed members. (TODO: to be fixed by implementing
+  __dir__.)
+  The global namespace is ``cppyy.gbl``.
+
+* **operator conversions**: If defined in the C++ class and a python
+  equivalent exists (i.e. all builtin integer and floating point types, as well
+  as ``bool``), it will map onto that python conversion.
+  Note that ``char*`` is mapped onto ``__str__``.
+
+* **operator overloads**: If defined in the C++ class and if a python
+  equivalent is available (not always the case, think e.g. of ``operator||``),
+  then they work as expected.
+  Special care needs to be taken for global operator overloads in C++: first,
+  make sure that they are actually reflected, especially for the global
+  overloads for ``operator==`` and ``operator!=`` of STL iterators in the case
+  of gcc.
+  Second, make sure that reflection info is loaded in the proper order.
+  I.e. that these global overloads are available before use.
+
+* **pointers**: For builtin data types, see arrays.
+  For objects, a pointer to an object and an object looks the same, unless
+  the pointer is a data member.
+  In that case, assigning to the data member will cause a copy of the pointer
+  and care should be taken about the object's life time.
+  If a pointer is a global variable, the C++ side can replace the underlying
+  object and the python side will immediately reflect that.
+
+* **static data members**: Are represented as python property objects on the
+  class and the meta-class.
+  Both read and write access is as expected.
+
+* **static methods**: Are represented as python's ``staticmethod`` objects
+  and can be called both from the class as well as from instances.
+
+* **strings**: The std::string class is considered a builtin C++ type and
+  mixes quite well with python's str.
+  Python's str can be passed where a ``const char*`` is expected, and an str
+  will be returned if the return type is ``const char*``.
+
+* **templated classes**: Are represented in a meta-class style in python.
+  This looks a little bit confusing, but conceptually is rather natural.
+  For example, given the class ``std::vector<int>``, the meta-class part would
+  be ``std.vector`` in python.
+  Then, to get the instantiation on ``int``, do ``std.vector(int)`` and to
+  create an instance of that class, do ``std.vector(int)()``.
+  Note that templates can be build up by handing actual types to the class
+  instantiation (as done in this vector example), or by passing in the list of
+  template arguments as a string.
+  The former is a lot easier to work with if you have template instantiations
+  using classes that themselves are templates (etc.) in the arguments.
+  All classes must already exist in the loaded reflection info.
+
+* **unary operators**: Are supported if a python equivalent exists, and if the
+  operator is defined in the C++ class.
+
+You can always find more detailed examples and see the full of supported
+features by looking at the tests in pypy/module/cppyy/test.
+
+If a feature or reflection info is missing, this is supposed to be handled
+gracefully.
+In fact, there are unit tests explicitly for this purpose (even as their use
+becomes less interesting over time, as the number of missing features
+decreases).
+Only when a missing feature is used, should there be an exception.
+For example, if no reflection info is available for a return type, then a
+class that has a method with that return type can still be used.
+Only that one specific method can not be used.
+
+
+The fast lane
+=============
+
+The following is an experimental feature of cppyy, and that makes it doubly
+experimental, so caveat emptor.
+With a slight modification of Reflex, it can provide function pointers for
+C++ methods, and hence allow PyPy to call those pointers directly, rather than
+calling C++ through a Reflex stub.
+This results in a rather significant speed-up.
+Mind you, the normal stub path is not exactly slow, so for now only use this
+out of curiosity or if you really need it.
+
+To install this patch of Reflex, locate the file genreflex-methptrgetter.patch
+in pypy/module/cppyy and apply it to the genreflex python scripts found in
+``$ROOTSYS/lib``::
+
+    $ cd $ROOTSYS/lib
+    $ patch -p2 < genreflex-methptrgetter.patch
+
+With this patch, ``genreflex`` will have grown the ``--with-methptrgetter``
+option.
+Use this option when running ``genreflex``, and add the
+``-Wno-pmf-conversions`` option to ``g++`` when compiling.
+The rest works the same way: the fast path will be used transparently (which
+also means that you can't actually find out whether it is in use, other than
+by running a micro-benchmark).
+
+
+CPython
+=======
+
+Most of the ideas in cppyy come originally from the `PyROOT`_ project.
+Although PyROOT does not support Reflex directly, it has an alter ego called
+"PyCintex" that, in a somewhat roundabout way, does.
+If you installed ROOT, rather than just Reflex, PyCintex should be available
+immediately if you add ``$ROOTSYS/lib`` to the ``PYTHONPATH`` environment
+variable.
+
+.. _`PyROOT`: http://root.cern.ch/drupal/content/pyroot
+
+There are a couple of minor differences between PyCintex and cppyy, most to do
+with naming.
+The one that you will run into directly, is that PyCintex uses a function
+called ``loadDictionary`` rather than ``load_reflection_info``.
+The reason for this is that Reflex calls the shared libraries that contain
+reflection info "dictionaries."
+However, in python, the name `dictionary` already has a well-defined meaning,
+so a more descriptive name was chosen for cppyy.
+In addition, PyCintex requires that the names of shared libraries so loaded
+start with "lib" in their name.
+The basic example above, rewritten for PyCintex thus goes like this::
+
+    $ python
+    >>> import PyCintex
+    >>> PyCintex.loadDictionary("libMyClassDict.so")
+    >>> myinst = PyCintex.gbl.MyClass(42)
+    >>> print myinst.GetMyInt()
+    42
+    >>> myinst.SetMyInt(33)
+    >>> print myinst.m_myint
+    33
+    >>> myinst.m_myint = 77
+    >>> print myinst.GetMyInt()
+    77
+    >>> help(PyCintex.gbl.MyClass)   # shows that normal python introspection works
+
+Other naming differences are such things as taking an address of an object.
+In PyCintex, this is done with ``AddressOf`` whereas in cppyy the choice was
+made to follow the naming as in ``ctypes`` and hence use ``addressof``
+(PyROOT/PyCintex predate ``ctypes`` by several years, and the ROOT project
+follows camel-case, hence the differences).
+
+Of course, this is python, so if any of the naming is not to your liking, all
+you have to do is provide a wrapper script that you import instead of
+importing the ``cppyy`` or ``PyCintex`` modules directly.
+In that wrapper script you can rename methods exactly the way you need it.
+
+In the cling world, all these differences will be resolved.
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -158,6 +158,12 @@
 .. __: http://morepypy.blogspot.com/2008/02/python-finalizers-semantics-part-1.html
 .. __: http://morepypy.blogspot.com/2008/02/python-finalizers-semantics-part-2.html
 
+Note that this difference might show up indirectly in some cases.  For
+example, a generator left pending in the middle is --- again ---
+garbage-collected later in PyPy than in CPython.  You can see the
+difference if the ``yield`` keyword it is suspended at is itself
+enclosed in a ``try:`` or a ``with:`` block.
+
 Using the default GC called ``minimark``, the built-in function ``id()``
 works like it does in CPython.  With other GCs it returns numbers that
 are not real addresses (because an object can move around several times)
diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst
--- a/pypy/doc/extending.rst
+++ b/pypy/doc/extending.rst
@@ -23,6 +23,8 @@
 
 * Write them in RPython as mixedmodule_, using *rffi* as bindings.
 
+* Write them in C++ and bind them through Reflex_ (EXPERIMENTAL)
+
 .. _ctypes: #CTypes
 .. _\_ffi: #LibFFI
 .. _mixedmodule: #Mixed Modules
@@ -110,3 +112,34 @@
 
 XXX we should provide detailed docs about lltype and rffi, especially if we
     want people to follow that way.
+
+Reflex
+======
+
+This method is only experimental for now, and is being exercised on a branch,
+`reflex-support`_, so you will have to build PyPy yourself.
+The method works by using the `Reflex package`_ to provide reflection
+information of the C++ code, which is then used to automatically generate
+bindings at runtime, which can then be used from python.
+Full details are `available here`_.
+
+.. _`reflex-support`: cppyy.html
+.. _`Reflex package`: http://root.cern.ch/drupal/content/reflex
+.. _`available here`: cppyy.html
+
+Pros
+----
+
+If it works, it is mostly automatic, and hence easy in use.
+The bindings can make use of direct pointers, in which case the calls are
+very fast.
+
+Cons
+----
+
+C++ is a large language, and these bindings are not yet feature-complete.
+Although missing features should do no harm if you don't use them, if you do
+need a particular feature, it may be necessary to work around it in python
+or with a C++ helper function.
+Although Reflex works on various platforms, the bindings with PyPy have only
+been tested on Linux.
diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py
--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -85,6 +85,10 @@
     Collects the arguments of a function call.
 
     Instances should be considered immutable.
+
+    Some parts of this class are written in a slightly convoluted style to help
+    the JIT. It is really crucial to get this right, because Python's argument
+    semantics are complex, but calls occur everywhere.
     """
 
     ###  Construction  ###
@@ -169,9 +173,17 @@
     def _combine_starstarargs_wrapped(self, w_starstararg):
         # unpack the ** arguments
         space = self.space
+        keywords, values_w = space.view_as_kwargs(w_starstararg)
+        if keywords is not None: # this path also taken for empty dicts
+            if self.keywords is None:
+                self.keywords = keywords[:] # copy to make non-resizable
+                self.keywords_w = values_w[:]
+            else:
+                self._check_not_duplicate_kwargs(keywords, values_w)
+                self.keywords = self.keywords + keywords
+                self.keywords_w = self.keywords_w + values_w
+            return not jit.isconstant(len(self.keywords))
         if space.isinstance_w(w_starstararg, space.w_dict):
-            if not space.is_true(w_starstararg):
-                return False # don't call unpackiterable - it's jit-opaque
             keys_w = space.unpackiterable(w_starstararg)
         else:
             try:
@@ -186,11 +198,8 @@
                                    "a mapping, not %s" % (typename,)))
                 raise
             keys_w = space.unpackiterable(w_keys)
-        if keys_w:
-            self._do_combine_starstarargs_wrapped(keys_w, w_starstararg)
-            return True
-        else:
-            return False    # empty dict; don't disable the JIT
+        self._do_combine_starstarargs_wrapped(keys_w, w_starstararg)
+        return True
 
     def _do_combine_starstarargs_wrapped(self, keys_w, w_starstararg):
         space = self.space
@@ -227,6 +236,20 @@
             self.keywords_w = self.keywords_w + keywords_w
         self.keyword_names_w = keys_w
 
+    @jit.look_inside_iff(lambda self, keywords, keywords_w:
+            jit.isconstant(len(keywords) and
+            jit.isconstant(self.keywords)))
+    def _check_not_duplicate_kwargs(self, keywords, keywords_w):
+        # looks quadratic, but the JIT should remove all of it nicely.
+        # Also, all the lists should be small
+        for key in keywords:
+            for otherkey in self.keywords:
+                if otherkey == key:
+                    raise operationerrfmt(self.space.w_TypeError,
+                                          "got multiple values "
+                                          "for keyword argument "
+                                          "'%s'", key)
+
     def fixedunpack(self, argcount):
         """The simplest argument parsing: get the 'argcount' arguments,
         or raise a real ValueError if the length is wrong."""
@@ -385,7 +408,7 @@
 
         # collect extra keyword arguments into the **kwarg
         if has_kwarg:
-            w_kwds = self.space.newdict()
+            w_kwds = self.space.newdict(kwargs=True)
             if num_remainingkwds:
                 #
                 limit = len(keywords)
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -914,6 +914,12 @@
         """
         return None
 
+    def view_as_kwargs(self, w_dict):
+        """ if w_dict is a kwargs-dict, return two lists, one of unwrapped
+        strings and one of wrapped values. otherwise return (None, None)
+        """
+        return (None, None)
+
     def newlist_str(self, list_s):
         return self.newlist([self.wrap(s) for s in list_s])
 
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -49,7 +49,9 @@
     def __repr__(self):
         # return "function %s.%s" % (self.space, self.name)
         # maybe we want this shorter:
-        name = getattr(self, 'name', '?')
+        name = getattr(self, 'name', None)
+        if not isinstance(name, str):
+            name = '?'
         return "<%s %s>" % (self.__class__.__name__, name)
 
     def call_args(self, args):
diff --git a/pypy/interpreter/test/test_argument.py b/pypy/interpreter/test/test_argument.py
--- a/pypy/interpreter/test/test_argument.py
+++ b/pypy/interpreter/test/test_argument.py
@@ -75,7 +75,10 @@
     def unpackiterable(self, it):
         return list(it)
 
-    def newdict(self):
+    def view_as_kwargs(self, x):
+        return None, None
+
+    def newdict(self, kwargs=False):
         return {}
 
     def newlist(self, l=[]):
@@ -488,6 +491,57 @@
         assert len(l) == 1
         assert l[0] == space.wrap(5)
 
+    def test_starstarargs_special(self):
+        class kwargs(object):
+            def __init__(self, k, v):
+                self.k = k
+                self.v = v
+        class MyDummySpace(DummySpace):
+            def view_as_kwargs(self, kw):
+                if isinstance(kw, kwargs):
+                    return kw.k, kw.v
+                return None, None
+        space = MyDummySpace()
+        for i in range(3):
+            kwds = [("c", 3)]
+            kwds_w = dict(kwds[:i])
+            keywords = kwds_w.keys()
+            keywords_w = kwds_w.values()
+            rest = dict(kwds[i:])
+            w_kwds = kwargs(rest.keys(), rest.values())
+            if i == 2:
+                w_kwds = None
+            assert len(keywords) == len(keywords_w)
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+            l = [None, None, None]
+            args._match_signature(None, l, Signature(["a", "b", "c"]), defaults_w=[4])
+            assert l == [1, 2, 3]
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+            l = [None, None, None, None]
+            args._match_signature(None, l, Signature(["a", "b", "b1", "c"]), defaults_w=[4, 5])
+            assert l == [1, 2, 4, 3]
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+            l = [None, None, None, None]
+            args._match_signature(None, l, Signature(["a", "b", "c", "d"]), defaults_w=[4, 5])
+            assert l == [1, 2, 3, 5]
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+            l = [None, None, None, None]
+            py.test.raises(ArgErr, args._match_signature, None, l,
+                           Signature(["c", "b", "a", "d"]), defaults_w=[4, 5])
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+            l = [None, None, None, None]
+            py.test.raises(ArgErr, args._match_signature, None, l,
+                           Signature(["a", "b", "c1", "d"]), defaults_w=[4, 5])
+            args = Arguments(space, [1, 2], keywords[:], keywords_w[:], w_starstararg=w_kwds)
+            l = [None, None, None]
+            args._match_signature(None, l, Signature(["a", "b"], None, "**"))
+            assert l == [1, 2, {'c': 3}]
+        excinfo = py.test.raises(OperationError, Arguments, space, [], ["a"],
+                                 [1], w_starstararg=kwargs(["a"], [2]))
+        assert excinfo.value.w_type is TypeError
+
+
+
 class TestErrorHandling(object):
     def test_missing_args(self):
         # got_nargs, nkwds, expected_nargs, has_vararg, has_kwarg,
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -1656,15 +1656,21 @@
         else:
             # XXX hard-coded assumption: to go from an object to its class
             # we use the following algorithm:
-            #   - read the typeid from mem(locs[0]), i.e. at offset 0
-            #   - keep the lower 16 bits read there
-            #   - multiply by 4 and use it as an offset in type_info_group
-            #   - add 16 bytes, to go past the TYPE_INFO structure
+            #   - read the typeid from mem(locs[0]), i.e. at offset 0;
+            #     this is a complete word (N=4 bytes on 32-bit, N=8 on
+            #     64-bits)
+            #   - keep the lower half of what is read there (i.e.
+            #     truncate to an unsigned 'N / 2' bytes value)
+            #   - multiply by 4 (on 32-bits only) and use it as an
+            #     offset in type_info_group
+            #   - add 16/32 bytes, to go past the TYPE_INFO structure
             loc = locs[1]
             assert isinstance(loc, ImmedLoc)
             classptr = loc.value
             # here, we have to go back from 'classptr' to the value expected
-            # from reading the 16 bits in the object header
+            # from reading the half-word in the object header.  Note that
+            # this half-word is at offset 0 on a little-endian machine;
+            # it would be at offset 2 or 4 on a big-endian machine.
             from pypy.rpython.memory.gctypelayout import GCData
             sizeof_ti = rffi.sizeof(GCData.TYPE_INFO)
             type_info_group = llop.gc_get_type_info_group(llmemory.Address)
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -1223,7 +1223,7 @@
     def run_one_step(self):
         # Execute the frame forward.  This method contains a loop that leaves
         # whenever the 'opcode_implementations' (which is one of the 'opimpl_'
-        # methods) returns True.  This is the case when the current frame
+        # methods) raises ChangeFrame.  This is the case when the current frame
         # changes, due to a call or a return.
         try:
             staticdata = self.metainterp.staticdata
diff --git a/pypy/module/_io/interp_iobase.py b/pypy/module/_io/interp_iobase.py
--- a/pypy/module/_io/interp_iobase.py
+++ b/pypy/module/_io/interp_iobase.py
@@ -341,9 +341,13 @@
 
     def add(self, w_iobase):
         assert w_iobase.streamholder is None
-        holder = StreamHolder(w_iobase)
-        w_iobase.streamholder = holder
-        self.streams[holder] = None
+        if rweakref.has_weakref_support():
+            holder = StreamHolder(w_iobase)
+            w_iobase.streamholder = holder
+            self.streams[holder] = None
+        #else:
+        #   no support for weakrefs, so ignore and we
+        #   will not get autoflushing
 
     def remove(self, w_iobase):
         holder = w_iobase.streamholder
diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py
--- a/pypy/module/_lsprof/interp_lsprof.py
+++ b/pypy/module/_lsprof/interp_lsprof.py
@@ -185,6 +185,7 @@
             if subentry is not None:
                 subentry._stop(tt, it)
 
+ at jit.elidable_promote()
 def create_spec(space, w_arg):
     if isinstance(w_arg, Method):
         w_function = w_arg.w_function
diff --git a/pypy/module/cpyext/iterator.py b/pypy/module/cpyext/iterator.py
--- a/pypy/module/cpyext/iterator.py
+++ b/pypy/module/cpyext/iterator.py
@@ -22,7 +22,7 @@
     cannot be iterated."""
     return space.iter(w_obj)
 
- at cpython_api([PyObject], PyObject, error=CANNOT_FAIL)
+ at cpython_api([PyObject], PyObject)
 def PyIter_Next(space, w_obj):
     """Return the next value from the iteration o.  If the object is an
     iterator, this retrieves the next value from the iteration, and returns
diff --git a/pypy/module/cpyext/pyerrors.py b/pypy/module/cpyext/pyerrors.py
--- a/pypy/module/cpyext/pyerrors.py
+++ b/pypy/module/cpyext/pyerrors.py
@@ -314,7 +314,10 @@
     """This function simulates the effect of a SIGINT signal arriving --- the
     next time PyErr_CheckSignals() is called, KeyboardInterrupt will be raised.
     It may be called without holding the interpreter lock."""
-    space.check_signal_action.set_interrupt()
+    if space.check_signal_action is not None:
+        space.check_signal_action.set_interrupt()
+    #else:
+    #   no 'signal' module present, ignore...  We can't return an error here
 
 @cpython_api([PyObjectP, PyObjectP, PyObjectP], lltype.Void)
 def PyErr_GetExcInfo(space, ptype, pvalue, ptraceback):
diff --git a/pypy/module/cpyext/test/test_iterator.py b/pypy/module/cpyext/test/test_iterator.py
--- a/pypy/module/cpyext/test/test_iterator.py
+++ b/pypy/module/cpyext/test/test_iterator.py
@@ -15,3 +15,8 @@
         assert space.unwrap(api.PyIter_Next(w_iter)) == 3
         assert api.PyIter_Next(w_iter) is None
         assert not api.PyErr_Occurred()
+
+    def test_iternext_error(self,space, api):
+        assert api.PyIter_Next(space.w_None) is None
+        assert api.PyErr_Occurred() is space.w_TypeError
+        api.PyErr_Clear()
diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py
--- a/pypy/module/cpyext/test/test_unicodeobject.py
+++ b/pypy/module/cpyext/test/test_unicodeobject.py
@@ -453,10 +453,22 @@
 
     def test_tailmatch(self, space, api):
         w_str = space.wrap(u"abcdef")
-        assert api.PyUnicode_Tailmatch(w_str, space.wrap("cde"), 2, 10, 1) == 1
-        assert api.PyUnicode_Tailmatch(w_str, space.wrap("cde"), 1, 5, -1) == 1
+        # prefix match
+        assert api.PyUnicode_Tailmatch(w_str, space.wrap("cde"), 2, 9, -1) == 1
+        assert api.PyUnicode_Tailmatch(w_str, space.wrap("cde"), 2, 4, -1) == 0 # ends at 'd'
+        assert api.PyUnicode_Tailmatch(w_str, space.wrap("cde"), 1, 6, -1) == 0 # starts at 'b'
+        assert api.PyUnicode_Tailmatch(w_str, space.wrap("cdf"), 2, 6, -1) == 0
+        # suffix match
+        assert api.PyUnicode_Tailmatch(w_str, space.wrap("cde"), 1, 5,  1) == 1
+        assert api.PyUnicode_Tailmatch(w_str, space.wrap("cde"), 3, 5,  1) == 0 # starts at 'd'
+        assert api.PyUnicode_Tailmatch(w_str, space.wrap("cde"), 1, 6,  1) == 0 # ends at 'f'
+        assert api.PyUnicode_Tailmatch(w_str, space.wrap("bde"), 1, 5,  1) == 0
+        # type checks
         self.raises(space, api, TypeError,
                     api.PyUnicode_Tailmatch, w_str, space.wrap(3), 2, 10, 1)
+        self.raises(space, api, TypeError,
+                    api.PyUnicode_Tailmatch, space.wrap(3), space.wrap("abc"),
+                    2, 10, 1)
 
     def test_count(self, space, api):
         w_str = space.wrap(u"abcabdab")
@@ -479,6 +491,8 @@
                 api.PyUnicode_Split(w_str, space.wrap('\n'), -1)))
         assert r"[u'a', u'b', u'c\nd']" == space.unwrap(space.repr(
                 api.PyUnicode_Split(w_str, space.wrap('\n'), 2)))
+        assert r"[u'a', u'b', u'c d']" == space.unwrap(space.repr(
+                api.PyUnicode_Split(space.wrap(u'a\nb  c d'), None, 2)))
         assert "[u'a', u'b', u'c', u'd']" == space.unwrap(space.repr(
                 api.PyUnicode_Splitlines(w_str, 0)))
         assert r"[u'a\n', u'b\n', u'c\n', u'd']" == space.unwrap(space.repr(
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -593,7 +593,7 @@
     suffix match), 0 otherwise. Return -1 if an error occurred."""
     str = space.unicode_w(w_str)
     substr = space.unicode_w(w_substr)
-    if rffi.cast(lltype.Signed, direction) >= 0:
+    if rffi.cast(lltype.Signed, direction) <= 0:
         return stringtype.stringstartswith(str, substr, start, end)
     else:
         return stringtype.stringendswith(str, substr, start, end)
@@ -630,6 +630,8 @@
     Otherwise, splits occur at the given separator.  At most maxsplit
     splits will be done.  If negative, no limit is set.  Separators
     are not included in the resulting list."""
+    if w_sep is None:
+        w_sep = space.w_None
     return space.call_method(w_str, "split", w_sep, space.wrap(maxsplit))
 
 @cpython_api([PyObject, rffi.INT_real], PyObject)
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -5,6 +5,7 @@
     interpleveldefs = {
         'debug_repr': 'interp_extras.debug_repr',
         'remove_invalidates': 'interp_extras.remove_invalidates',
+        'set_invalidation': 'interp_extras.set_invalidation',
     }
     appleveldefs = {}
 
@@ -30,6 +31,7 @@
         'isna': 'interp_numarray.isna',
         'concatenate': 'interp_numarray.concatenate',
         'repeat': 'interp_numarray.repeat',
+        'where': 'interp_arrayops.where',
 
         'set_string_function': 'appbridge.set_string_function',
 
diff --git a/pypy/module/micronumpy/interp_arrayops.py b/pypy/module/micronumpy/interp_arrayops.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/interp_arrayops.py
@@ -0,0 +1,90 @@
+
+from pypy.module.micronumpy.interp_numarray import convert_to_array,\
+     VirtualArray
+from pypy.module.micronumpy import signature
+
+class WhereArray(VirtualArray):
+    def __init__(self, space, arr, x, y):
+        self.arr = arr
+        self.x = x
+        self.y = y
+        VirtualArray.__init__(self, 'where', arr.shape[:],
+                              x.find_dtype())
+
+    def create_sig(self):
+        if self.forced_result is not None:
+            return self.forced_result.create_sig()
+        return signature.WhereSignature(self.res_dtype, self.arr.find_dtype(),
+                                        self.arr.create_sig(),
+                                        self.x.create_sig(),
+                                        self.y.create_sig())
+
+    def _del_sources(self):
+        self.arr = None
+        self.x = None
+        self.y = None
+
+def where(space, w_arr, w_x, w_y):
+    """where(condition, [x, y])
+
+    Return elements, either from `x` or `y`, depending on `condition`.
+
+    If only `condition` is given, return ``condition.nonzero()``.
+
+    Parameters
+    ----------
+    condition : array_like, bool
+        When True, yield `x`, otherwise yield `y`.
+    x, y : array_like, optional
+        Values from which to choose. `x` and `y` need to have the same
+        shape as `condition`.
+
+    Returns
+    -------
+    out : ndarray or tuple of ndarrays
+        If both `x` and `y` are specified, the output array contains
+        elements of `x` where `condition` is True, and elements from
+        `y` elsewhere.
+
+        If only `condition` is given, return the tuple
+        ``condition.nonzero()``, the indices where `condition` is True.
+
+    See Also
+    --------
+    nonzero, choose
+
+    Notes
+    -----
+    If `x` and `y` are given and input arrays are 1-D, `where` is
+    equivalent to::
+
+        [xv if c else yv for (c,xv,yv) in zip(condition,x,y)]
+
+    Examples
+    --------
+    >>> np.where([[True, False], [True, True]],
+    ...          [[1, 2], [3, 4]],
+    ...          [[9, 8], [7, 6]])
+    array([[1, 8],
+           [3, 4]])
+
+    >>> np.where([[0, 1], [1, 0]])
+    (array([0, 1]), array([1, 0]))
+
+    >>> x = np.arange(9.).reshape(3, 3)
+    >>> np.where( x > 5 )
+    (array([2, 2, 2]), array([0, 1, 2]))
+    >>> x[np.where( x > 3.0 )]               # Note: result is 1D.
+    array([ 4.,  5.,  6.,  7.,  8.])
+    >>> np.where(x < 5, x, -1)               # Note: broadcasting.
+    array([[ 0.,  1.,  2.],
+           [ 3.,  4., -1.],
+           [-1., -1., -1.]])
+
+    
+    NOTE: support for not passing x and y is unsupported
+    """
+    arr = convert_to_array(space, w_arr)
+    x = convert_to_array(space, w_x)
+    y = convert_to_array(space, w_y)
+    return WhereArray(space, arr, x, y)
diff --git a/pypy/module/micronumpy/interp_extras.py b/pypy/module/micronumpy/interp_extras.py
--- a/pypy/module/micronumpy/interp_extras.py
+++ b/pypy/module/micronumpy/interp_extras.py
@@ -1,5 +1,5 @@
 from pypy.interpreter.gateway import unwrap_spec
-from pypy.module.micronumpy.interp_numarray import BaseArray
+from pypy.module.micronumpy.interp_numarray import BaseArray, get_numarray_cache
 
 
 @unwrap_spec(array=BaseArray)
@@ -13,3 +13,7 @@
     """
     del array.invalidates[:]
     return space.w_None
+
+ at unwrap_spec(arg=bool)
+def set_invalidation(space, arg):
+    get_numarray_cache(space).enable_invalidation = arg
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
@@ -72,9 +72,10 @@
             arr.force_if_needed()
         del self.invalidates[:]
 
-    def add_invalidates(self, other):
-        self.invalidates.append(other)
-
+    def add_invalidates(self, space, other):
+        if get_numarray_cache(space).enable_invalidation:
+            self.invalidates.append(other)
+        
     def descr__new__(space, w_subtype, w_size, w_dtype=None):
         dtype = space.interp_w(interp_dtype.W_Dtype,
             space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
@@ -513,7 +514,30 @@
             arr = concrete.copy(space)
             arr.setshape(space, new_shape)
         return arr
-
+       
+    @unwrap_spec(axis1=int, axis2=int)
+    def descr_swapaxes(self, space, axis1, axis2):
+        """a.swapaxes(axis1, axis2)
+    
+        Return a view of the array with `axis1` and `axis2` interchanged.
+    
+        Refer to `numpy.swapaxes` for full documentation.
+    
+        See Also
+        --------
+        numpy.swapaxes : equivalent function
+        """
+        concrete = self.get_concrete()
+        shape = concrete.shape[:]
+        strides = concrete.strides[:]
+        backstrides = concrete.backstrides[:]
+        shape[axis1], shape[axis2] = shape[axis2], shape[axis1]   
+        strides[axis1], strides[axis2] = strides[axis2], strides[axis1]
+        backstrides[axis1], backstrides[axis2] = backstrides[axis2], backstrides[axis1] 
+        arr = W_NDimSlice(concrete.start, strides, 
+                           backstrides, shape, concrete)
+        return space.wrap(arr)   
+                                      
     def descr_tolist(self, space):
         if len(self.shape) == 0:
             assert isinstance(self, Scalar)
@@ -1412,6 +1436,7 @@
     copy = interp2app(BaseArray.descr_copy),
     flatten = interp2app(BaseArray.descr_flatten),
     reshape = interp2app(BaseArray.descr_reshape),
+    swapaxes = interp2app(BaseArray.descr_swapaxes),
     tolist = interp2app(BaseArray.descr_tolist),
     take = interp2app(BaseArray.descr_take),
     compress = interp2app(BaseArray.descr_compress),
@@ -1559,3 +1584,10 @@
         arr.fill(space, space.wrap(False))
         return arr
     return space.wrap(False)
+
+class NumArrayCache(object):
+    def __init__(self, space):
+        self.enable_invalidation = True
+
+def get_numarray_cache(space):
+    return space.fromcache(NumArrayCache)
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -278,7 +278,7 @@
         else:
             w_res = Call1(self.func, self.name, w_obj.shape, calc_dtype,
                                          res_dtype, w_obj)
-        w_obj.add_invalidates(w_res)
+        w_obj.add_invalidates(space, w_res)
         return w_res
 
 
@@ -347,8 +347,8 @@
         w_res = Call2(self.func, self.name,
                       new_shape, calc_dtype,
                       res_dtype, w_lhs, w_rhs, out)
-        w_lhs.add_invalidates(w_res)
-        w_rhs.add_invalidates(w_res)
+        w_lhs.add_invalidates(space, w_res)
+        w_rhs.add_invalidates(space, w_res)
         if out:
             w_res.get_concrete()
         return w_res
diff --git a/pypy/module/micronumpy/signature.py b/pypy/module/micronumpy/signature.py
--- a/pypy/module/micronumpy/signature.py
+++ b/pypy/module/micronumpy/signature.py
@@ -498,3 +498,63 @@
         arr.left.setitem(iterator.offset, value)
     def debug_repr(self):
         return 'AxisReduceSig(%s, %s)' % (self.name, self.right.debug_repr())
+
+class WhereSignature(Signature):
+    _immutable_fields_ = ['dtype', 'arrdtype', 'arrsig', 'xsig', 'ysig']
+    
+    def __init__(self, dtype, arrdtype, arrsig, xsig, ysig):
+        self.dtype = dtype
+        self.arrdtype = arrdtype
+        self.arrsig = arrsig
+        self.xsig = xsig
+        self.ysig = ysig
+
+    def hash(self):
+        return (intmask(self.arrsig.hash() << 1) ^
+                intmask(self.xsig.hash() << 2) ^
+                intmask(self.ysig.hash() << 3))
+
+    def eq(self, other, compare_array_no=True):
+        if type(self) is not type(other):
+            return False
+        assert isinstance(other, WhereSignature)
+        return (self.arrsig.eq(other.arrsig, compare_array_no) and
+                self.xsig.eq(other.xsig, compare_array_no) and
+                self.ysig.eq(other.ysig, compare_array_no))
+
+    def _invent_array_numbering(self, arr, cache):
+        from pypy.module.micronumpy.interp_arrayops import WhereArray
+        assert isinstance(arr, WhereArray)
+        self.arrsig._invent_array_numbering(arr.arr, cache)
+        self.xsig._invent_array_numbering(arr.x, cache)
+        self.ysig._invent_array_numbering(arr.y, cache)
+
+    def _invent_numbering(self, cache, allnumbers):
+        self.arrsig._invent_numbering(cache, allnumbers)
+        self.xsig._invent_numbering(cache, allnumbers)
+        self.ysig._invent_numbering(cache, allnumbers)
+
+    def _create_iter(self, iterlist, arraylist, arr, transforms):
+        from pypy.module.micronumpy.interp_arrayops import WhereArray
+
+        assert isinstance(arr, WhereArray)
+        # XXX this does not support broadcasting correctly
+        self.arrsig._create_iter(iterlist, arraylist, arr.arr, transforms)
+        self.xsig._create_iter(iterlist, arraylist, arr.x, transforms)
+        self.ysig._create_iter(iterlist, arraylist, arr.y, transforms)
+ 
+    def eval(self, frame, arr):
+        from pypy.module.micronumpy.interp_arrayops import WhereArray
+        assert isinstance(arr, WhereArray)
+        lhs = self.xsig.eval(frame, arr.x).convert_to(self.dtype)
+        rhs = self.ysig.eval(frame, arr.y).convert_to(self.dtype)
+        w_val = self.arrsig.eval(frame, arr.arr)
+        if self.arrdtype.itemtype.bool(w_val):
+            return lhs
+        else:
+            return rhs
+
+    def debug_repr(self):
+        return 'Where(%s, %s, %s)' % (self.arrsig.debug_repr(),
+                                      self.xsig.debug_repr(),
+                                      self.ysig.debug_repr())
diff --git a/pypy/module/micronumpy/test/test_arrayops.py b/pypy/module/micronumpy/test/test_arrayops.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_arrayops.py
@@ -0,0 +1,16 @@
+
+from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+
+class AppTestNumSupport(BaseNumpyAppTest):
+    def test_where(self):
+        from _numpypy import where, ones, zeros, array
+        a = [1, 2, 3, 0, -3]
+        a = where(array(a) > 0, ones(5), zeros(5))
+        assert (a == [1, 1, 1, 0, 0]).all()
+
+    def test_where_invalidates(self):
+        from _numpypy import where, ones, zeros, array
+        a = array([1, 2, 3, 0, -3])
+        b = where(a > 0, ones(5), zeros(5))
+        a[0] = 0
+        assert (b == [1, 1, 1, 0, 0]).all()
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
@@ -1,9 +1,8 @@
 
 import py
 
-from pypy.conftest import gettestobjspace, option
+from pypy.conftest import option
 from pypy.interpreter.error import OperationError
-from pypy.module.micronumpy import signature
 from pypy.module.micronumpy.appbridge import get_appbridge_cache
 from pypy.module.micronumpy.interp_iter import Chunk, Chunks
 from pypy.module.micronumpy.interp_numarray import W_NDimArray, shape_agreement
@@ -1410,6 +1409,35 @@
         assert (array([1, 2]).repeat(2) == array([1, 1, 2, 2])).all()
 
 
+    def test_swapaxes(self):
+        from _numpypy import array
+        # testcases from numpy docstring
+        x = array([[1, 2, 3]])
+        assert (x.swapaxes(0, 1) == array([[1], [2], [3]])).all() 
+        x = array([[[0,1],[2,3]],[[4,5],[6,7]]]) # shape = (2, 2, 2)
+        assert (x.swapaxes(0, 2) == array([[[0, 4], [2, 6]], 
+                                           [[1, 5], [3, 7]]])).all() 
+        assert (x.swapaxes(0, 1) == array([[[0, 1], [4, 5]], 
+                                           [[2, 3], [6, 7]]])).all()
+        assert (x.swapaxes(1, 2) == array([[[0, 2], [1, 3]], 
+                                           [[4, 6],[5, 7]]])).all()
+
+        # more complex shape i.e. (2, 2, 3)
+        x = array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]) 
+        assert (x.swapaxes(0, 1) == array([[[1, 2, 3], [7, 8, 9]], 
+                                           [[4, 5, 6], [10, 11, 12]]])).all() 
+        assert (x.swapaxes(0, 2) == array([[[1, 7], [4, 10]], [[2, 8], [5, 11]], 
+                                           [[3, 9], [6, 12]]])).all() 
+        assert (x.swapaxes(1, 2) == array([[[1, 4], [2, 5], [3, 6]], 
+                                           [[7, 10], [8, 11],[9, 12]]])).all() 
+        
+        # test slice
+        assert (x[0:1,0:2].swapaxes(0,2) == array([[[1], [4]], [[2], [5]], 
+                                                   [[3], [6]]])).all()
+        # test virtual
+        assert ((x + x).swapaxes(0,1) == array([[[ 2,  4,  6], [14, 16, 18]], 
+                                         [[ 8, 10, 12], [20, 22, 24]]])).all()
+                        
 class AppTestMultiDim(BaseNumpyAppTest):
     def test_init(self):
         import _numpypy
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -1,7 +1,6 @@
 
 from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
 
-
 class AppTestUfuncs(BaseNumpyAppTest):
     def test_ufunc_instance(self):
         from _numpypy import add, ufunc
@@ -149,7 +148,11 @@
         assert math.isnan(fmax(0, nan))
         assert math.isnan(fmax(nan, nan))
         # The numpy docs specify that the FIRST NaN should be used if both are NaN
-        assert math.copysign(1.0, fmax(nnan, nan)) == -1.0
+        # Since comparisons with nnan and nan all return false,
+        # use copysign on both sides to sidestep bug in nan representaion
+        # on Microsoft win32
+        assert math.copysign(1., fmax(nnan, nan)) == math.copysign(1., nnan)
+
 
     def test_fmin(self):
         from _numpypy import fmin
@@ -165,7 +168,9 @@
         assert math.isnan(fmin(0, nan))
         assert math.isnan(fmin(nan, nan))
         # The numpy docs specify that the FIRST NaN should be used if both are NaN
-        assert math.copysign(1.0, fmin(nnan, nan)) == -1.0
+        # use copysign on both sides to sidestep bug in nan representaion
+        # on Microsoft win32
+        assert math.copysign(1., fmin(nnan, nan)) == math.copysign(1., nnan)
 
     def test_fmod(self):
         from _numpypy import fmod
@@ -762,6 +767,8 @@
 
     def test_logaddexp(self):
         import math
+        import sys
+        float_max, float_min = sys.float_info.max, sys.float_info.min
         from _numpypy import logaddexp
 
         # From the numpy documentation
@@ -772,7 +779,8 @@
 
         assert logaddexp(0, 0) == math.log(2)
         assert logaddexp(float('-inf'), 0) == 0
-        assert logaddexp(12345678, 12345678) == float('inf')
+        assert logaddexp(float_max, float_max) == float_max
+        assert logaddexp(float_min, float_min) == math.log(2)
 
         assert math.isnan(logaddexp(float('nan'), 1))
         assert math.isnan(logaddexp(1, float('nan')))
@@ -785,6 +793,8 @@
 
     def test_logaddexp2(self):
         import math
+        import sys
+        float_max, float_min = sys.float_info.max, sys.float_info.min
         from _numpypy import logaddexp2
         log2 = math.log(2)
 
@@ -796,7 +806,8 @@
 
         assert logaddexp2(0, 0) == 1
         assert logaddexp2(float('-inf'), 0) == 0
-        assert logaddexp2(12345678, 12345678) == float('inf')
+        assert logaddexp2(float_max, float_max) == float_max
+        assert logaddexp2(float_min, float_min) == 1.0
 
         assert math.isnan(logaddexp2(float('nan'), 1))
         assert math.isnan(logaddexp2(1, float('nan')))
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
@@ -17,6 +17,7 @@
                                                 'render_as_void': True})
 degToRad = math.pi / 180.0
 log2 = math.log(2)
+log2e = 1./log2
 
 def simple_unary_op(func):
     specialize.argtype(1)(func)
@@ -841,45 +842,26 @@
 
     @simple_binary_op
     def logaddexp(self, v1, v2):
-        try:
-            v1e = math.exp(v1)
-        except OverflowError:
-            v1e = rfloat.INFINITY
-        try:
-            v2e = math.exp(v2)
-        except OverflowError:
-            v2e = rfloat.INFINITY
+        tmp = v1 - v2
+        if tmp > 0:
+            return v1 + rfloat.log1p(math.exp(-tmp))
+        elif tmp <= 0:
+            return v2 + rfloat.log1p(math.exp(tmp))
+        else:
+            return v1 + v2
 
-        v12e = v1e + v2e
-        try:
-            return math.log(v12e)
-        except ValueError:
-            if v12e == 0.0:
-                # CPython raises ValueError here, so we have to check
-                # the value to find the correct numpy return value
-                return -rfloat.INFINITY
-            return rfloat.NAN
+    def npy_log2_1p(self, v):
+        return log2e * rfloat.log1p(v)
 
     @simple_binary_op
     def logaddexp2(self, v1, v2):
-        try:
-            v1e = math.pow(2, v1)
-        except OverflowError:
-            v1e = rfloat.INFINITY
-        try:
-            v2e = math.pow(2, v2)
-        except OverflowError:
-            v2e = rfloat.INFINITY
-
-        v12e = v1e + v2e
-        try:
-            return math.log(v12e) / log2
-        except ValueError:
-            if v12e == 0.0:
-                # CPython raises ValueError here, so we have to check
-                # the value to find the correct numpy return value
-                return -rfloat.INFINITY
-            return rfloat.NAN
+        tmp = v1 - v2
+        if tmp > 0:
+            return v1 + self.npy_log2_1p(math.pow(2, -tmp))
+        if tmp <= 0:
+            return v2 + self.npy_log2_1p(math.pow(2, tmp))
+        else:
+            return v1 + v2
 
 class NonNativeFloat(NonNativePrimitive, Float):
     _mixin_ = True
diff --git a/pypy/module/mmap/test/test_mmap.py b/pypy/module/mmap/test/test_mmap.py
--- a/pypy/module/mmap/test/test_mmap.py
+++ b/pypy/module/mmap/test/test_mmap.py
@@ -596,7 +596,7 @@
         import sys
         size = 0x14FFFFFFF
         if sys.platform.startswith('win') or sys.platform == 'darwin':
-            self.skip('test requires %s bytes and a long time to run' % size)
+            skip('test requires %s bytes and a long time to run' % size)
 
         with open(self.tmpname, "w+b") as f:
             f.seek(size)
@@ -618,7 +618,7 @@
         import sys
         size = 0x17FFFFFFF
         if sys.platform.startswith('win') or sys.platform == 'darwin':
-            self.skip('test requires %s bytes and a long time to run' % size)
+            skip('test requires %s bytes and a long time to run' % size)
 
         with open(self.tmpname, "w+b") as f:
             f.seek(size)
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
@@ -244,6 +244,7 @@
         print guards
         assert len(guards) <= 20
 
+
     def test_stararg_virtual(self):
         def main(x):
             def g(*args):
@@ -486,3 +487,38 @@
             --TICK--
             jump(..., descr=...)
         """)
+
+    def test_kwargs_virtual2(self):
+        log = self.run("""
+        def f(*args, **kwargs):
+            kwargs['a'] = kwargs['z'] * 0
+            return g(1, *args, **kwargs)
+
+        def g(x, y, z=2, a=1):
+            return x - y + z + a
+
+        def main(stop):
+            res = 0
+            i = 0
+            while i < stop:
+                res = f(res, z=i) # ID: call
+                i += 1
+            return res""", [1000])
+        assert log.result == 500
+        loop, = log.loops_by_id('call')
+        print loop.ops_by_id('call')
+        assert loop.match("""
+            i65 = int_lt(i58, i29)
+            guard_true(i65, descr=...)
+            guard_not_invalidated(..., descr=...)
+            i66 = force_token()
+            i67 = force_token()
+            i69 = int_sub_ovf(1, i56)
+            guard_no_overflow(..., descr=...)
+            i70 = int_add_ovf(i69, i58)
+            guard_no_overflow(..., descr=...)
+            i71 = int_add(i58, 1)
+            --TICK--
+            jump(..., descr=...)
+        """)
+
diff --git a/pypy/module/pypyjit/test_pypy_c/test_exception.py b/pypy/module/pypyjit/test_pypy_c/test_exception.py
--- a/pypy/module/pypyjit/test_pypy_c/test_exception.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_exception.py
@@ -91,3 +91,29 @@
             --TICK--
             jump(..., descr=...)
         """)
+
+    def test_continue_in_finally(self):
+        # check that 'continue' inside a try:finally: block is correctly
+        # detected as closing a loop
+        py.test.skip("is this case important?")
+        def f(n):
+            i = 0
+            while 1:
+                try:
+                    if i < n:
+                        continue
+                finally:
+                    i += 1
+                return i
+
+        log = self.run(f, [2000])
+        assert log.result == 2001
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match("""
+            i40 = int_add_ovf(i31, 1)
+            guard_no_overflow(descr=...)
+            i41 = int_lt(i40, i33)
+            guard_true(i41, descr=...)
+            --TICK--
+            jump(..., descr=...)
+        """)
diff --git a/pypy/module/rctime/interp_time.py b/pypy/module/rctime/interp_time.py
--- a/pypy/module/rctime/interp_time.py
+++ b/pypy/module/rctime/interp_time.py
@@ -24,10 +24,9 @@
     from pypy.module.thread import ll_thread as thread
 
     eci = ExternalCompilationInfo(
+        includes = ['windows.h'],
         post_include_bits = ["BOOL pypy_timemodule_setCtrlHandler(HANDLE event);"],
         separate_module_sources=['''
-            #include <windows.h>
-
             static HANDLE interrupt_event;
 
             static BOOL WINAPI CtrlHandlerRoutine(
diff --git a/pypy/module/test_lib_pypy/numpypy/core/test_fromnumeric.py b/pypy/module/test_lib_pypy/numpypy/core/test_fromnumeric.py
--- a/pypy/module/test_lib_pypy/numpypy/core/test_fromnumeric.py
+++ b/pypy/module/test_lib_pypy/numpypy/core/test_fromnumeric.py
@@ -136,4 +136,11 @@
         raises(NotImplementedError, "transpose(x, axes=(1, 0, 2))")
         # x = ones((1, 2, 3))
         # assert transpose(x, (1, 0, 2)).shape == (2, 1, 3)
-        
+    
+    def test_fromnumeric(self):
+        from numpypy import array, swapaxes
+        x = array([[1,2,3]])
+        assert (swapaxes(x,0,1) == array([[1], [2], [3]])).all()
+        x = array([[[0,1],[2,3]],[[4,5],[6,7]]])
+        assert (swapaxes(x,0,2) == array([[[0, 4], [2, 6]], 
+                                          [[1, 5], [3, 7]]])).all()
diff --git a/pypy/module/zipimport/interp_zipimport.py b/pypy/module/zipimport/interp_zipimport.py
--- a/pypy/module/zipimport/interp_zipimport.py
+++ b/pypy/module/zipimport/interp_zipimport.py
@@ -229,7 +229,11 @@
         startpos = fullname.rfind('.') + 1 # 0 when not found
         assert startpos >= 0
         subname = fullname[startpos:]
-        return self.prefix + subname.replace('.', '/')
+        if ZIPSEP == os.path.sep:
+            return self.prefix + subname.replace('.', '/')
+        else:
+            return self.prefix.replace(os.path.sep, ZIPSEP) + \
+                    subname.replace('.', '/')
 
     def make_co_filename(self, filename):
         """
diff --git a/pypy/module/zipimport/test/test_zipimport.py b/pypy/module/zipimport/test/test_zipimport.py
--- a/pypy/module/zipimport/test/test_zipimport.py
+++ b/pypy/module/zipimport/test/test_zipimport.py
@@ -313,13 +313,11 @@
         assert z.get_filename("package") == mod.__file__
 
     def test_subdirectory_twice(self):
-        import os, zipimport
+        #import os, zipimport
  
         self.writefile("package/__init__.py", "")
         self.writefile("package/subpackage/__init__.py", "")
         self.writefile("package/subpackage/foo.py", "")
-        import sys
-        print sys.path
         mod = __import__('package.subpackage.foo', None, None, [])
         assert mod
 
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -414,7 +414,8 @@
     def contains(space, w_container, w_item):
         w_descr = space.lookup(w_container, '__contains__')
         if w_descr is not None:
-            return space.get_and_call_function(w_descr, w_container, w_item)
+            w_result = space.get_and_call_function(w_descr, w_container, w_item)
+            return space.nonzero(w_result)
         return space._contains(w_container, w_item)
 
     def _contains(space, w_container, w_item):
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -110,7 +110,7 @@
         "NOT_RPYTHON"
         raise NotImplementedError
 
-    def newdict(self, module=False, instance=False,
+    def newdict(self, module=False, instance=False, kwargs=False,
                 strdict=False):
         return w_some_obj()
 
diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -33,7 +33,7 @@
 
     @staticmethod
     def allocate_and_init_instance(space, w_type=None, module=False,
-                                   instance=False, strdict=False):
+                                   instance=False, strdict=False, kwargs=False):
 
         if space.config.objspace.std.withcelldict and module:
             from pypy.objspace.std.celldict import ModuleDictStrategy
@@ -46,11 +46,15 @@
             assert w_type is None
             strategy = space.fromcache(StringDictStrategy)
 
+        elif kwargs:
+            assert w_type is None
+            from pypy.objspace.std.kwargsdict import KwargsDictStrategy
+            strategy = space.fromcache(KwargsDictStrategy)
         else:
             strategy = space.fromcache(EmptyDictStrategy)
-
         if w_type is None:
             w_type = space.w_dict
+
         storage = strategy.get_empty_storage()
         w_self = space.allocate_instance(W_DictMultiObject, w_type)
         W_DictMultiObject.__init__(w_self, space, strategy, storage)
@@ -91,7 +95,8 @@
                     getitem_str delitem length \
                     clear w_keys values \
                     items iter setdefault \
-                    popitem listview_str listview_int".split()
+                    popitem listview_str listview_int \
+                    view_as_kwargs".split()
 
     def make_method(method):
         def f(self, *args):
@@ -165,6 +170,9 @@
     def listview_int(self, w_dict):
         return None
 
+    def view_as_kwargs(self, w_dict):
+        return (None, None)
+
 class EmptyDictStrategy(DictStrategy):
 
     erase, unerase = rerased.new_erasing_pair("empty")
@@ -254,6 +262,9 @@
     def popitem(self, w_dict):
         raise KeyError
 
+    def view_as_kwargs(self, w_dict):
+        return ([], [])
+
 registerimplementation(W_DictMultiObject)
 
 # DictImplementation lattice
diff --git a/pypy/objspace/std/kwargsdict.py b/pypy/objspace/std/kwargsdict.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/kwargsdict.py
@@ -0,0 +1,165 @@
+## ----------------------------------------------------------------------------
+## dict strategy (see dictmultiobject.py)
+
+from pypy.rlib import rerased, jit
+from pypy.objspace.std.dictmultiobject import (DictStrategy,
+                                               IteratorImplementation,
+                                               ObjectDictStrategy,
+                                               StringDictStrategy)
+
+
+class KwargsDictStrategy(DictStrategy):
+    erase, unerase = rerased.new_erasing_pair("kwargsdict")
+    erase = staticmethod(erase)
+    unerase = staticmethod(unerase)
+
+    def wrap(self, key):
+        return self.space.wrap(key)
+
+    def unwrap(self, wrapped):
+        return self.space.str_w(wrapped)
+
+    def get_empty_storage(self):
+        d = ([], [])
+        return self.erase(d)
+
+    def is_correct_type(self, w_obj):
+        space = self.space
+        return space.is_w(space.type(w_obj), space.w_str)
+
+    def _never_equal_to(self, w_lookup_type):
+        return False
+
+    def iter(self, w_dict):
+        return KwargsDictIterator(self.space, self, w_dict)
+
+    def w_keys(self, w_dict):
+        return self.space.newlist([self.space.wrap(key) for key in self.unerase(w_dict.dstorage)[0]])
+
+    def setitem(self, w_dict, w_key, w_value):
+        space = self.space
+        if self.is_correct_type(w_key):
+            self.setitem_str(w_dict, self.unwrap(w_key), w_value)
+            return
+        else:
+            self.switch_to_object_strategy(w_dict)
+            w_dict.setitem(w_key, w_value)
+
+    def setitem_str(self, w_dict, key, w_value):
+        self._setitem_str_indirection(w_dict, key, w_value)
+
+    @jit.look_inside_iff(lambda self, w_dict, key, w_value:
+            jit.isconstant(self.length(w_dict)) and jit.isconstant(key))
+    def _setitem_str_indirection(self, w_dict, key, w_value):
+        keys, values_w = self.unerase(w_dict.dstorage)
+        result = []
+        for i in range(len(keys)):
+            if keys[i] == key:
+                values_w[i] = w_value
+                break
+        else:
+            # limit the size so that the linear searches don't become too long
+            if len(keys) >= 16:
+                self.switch_to_string_strategy(w_dict)
+                w_dict.setitem_str(key, w_value)
+            else:
+                keys.append(key)
+                values_w.append(w_value)
+
+    def setdefault(self, w_dict, w_key, w_default):
+        # XXX could do better, but is it worth it?
+        self.switch_to_object_strategy(w_dict)
+        return w_dict.setdefault(w_key, w_default)
+
+    def delitem(self, w_dict, w_key):
+        # XXX could do better, but is it worth it?
+        self.switch_to_object_strategy(w_dict)
+        return w_dict.delitem(w_key)
+
+    def length(self, w_dict):
+        return len(self.unerase(w_dict.dstorage)[0])
+
+    def getitem_str(self, w_dict, key):
+        return self._getitem_str_indirection(w_dict, key)
+
+    @jit.look_inside_iff(lambda self, w_dict, key: jit.isconstant(self.length(w_dict)) and jit.isconstant(key))
+    def _getitem_str_indirection(self, w_dict, key):
+        keys, values_w = self.unerase(w_dict.dstorage)
+        result = []
+        for i in range(len(keys)):
+            if keys[i] == key:
+                return values_w[i]
+        return None
+
+    def getitem(self, w_dict, w_key):
+        space = self.space
+        if self.is_correct_type(w_key):
+            return self.getitem_str(w_dict, self.unwrap(w_key))
+        elif self._never_equal_to(space.type(w_key)):
+            return None
+        else:
+            self.switch_to_object_strategy(w_dict)
+            return w_dict.getitem(w_key)
+
+    def w_keys(self, w_dict):
+        l = self.unerase(w_dict.dstorage)[0]
+        return self.space.newlist_str(l[:])
+
+    def values(self, w_dict):
+        return self.unerase(w_dict.dstorage)[1][:] # to make non-resizable
+
+    def items(self, w_dict):
+        space = self.space
+        keys, values_w = self.unerase(w_dict.dstorage)
+        result = []
+        for i in range(len(keys)):
+            result.append(space.newtuple([self.wrap(keys[i]), values_w[i]]))
+        return result
+
+    def popitem(self, w_dict):
+        keys, values_w = self.unerase(w_dict.dstorage)
+        key = keys.pop()
+        w_value = values_w.pop()
+        return (self.wrap(key), w_value)
+
+    def clear(self, w_dict):
+        w_dict.dstorage = self.get_empty_storage()
+
+    def switch_to_object_strategy(self, w_dict):
+        strategy = self.space.fromcache(ObjectDictStrategy)
+        keys, values_w = self.unerase(w_dict.dstorage)
+        d_new = strategy.unerase(strategy.get_empty_storage())
+        for i in range(len(keys)):
+            d_new[self.wrap(keys[i])] = values_w[i]
+        w_dict.strategy = strategy
+        w_dict.dstorage = strategy.erase(d_new)
+
+    def switch_to_string_strategy(self, w_dict):
+        strategy = self.space.fromcache(StringDictStrategy)
+        keys, values_w = self.unerase(w_dict.dstorage)
+        storage = strategy.get_empty_storage()
+        d_new = strategy.unerase(storage)
+        for i in range(len(keys)):
+            d_new[keys[i]] = values_w[i]
+        w_dict.strategy = strategy
+        w_dict.dstorage = storage
+
+    def view_as_kwargs(self, w_dict):
+        return self.unerase(w_dict.dstorage)
+
+
+class KwargsDictIterator(IteratorImplementation):
+    def __init__(self, space, strategy, dictimplementation):
+        IteratorImplementation.__init__(self, space, strategy, dictimplementation)
+        keys, values_w = strategy.unerase(self.dictimplementation.dstorage)
+        self.iterator = iter(range(len(keys)))
+        # XXX this potentially leaks
+        self.keys = keys
+        self.values_w = values_w
+
+    def next_entry(self):
+        # note that this 'for' loop only runs once, at most
+        for i in self.iterator:
+            return self.space.wrap(self.keys[i]), self.values_w[i]
+        else:
+            return None, None
diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py
--- a/pypy/objspace/std/model.py
+++ b/pypy/objspace/std/model.py
@@ -378,7 +378,10 @@
     __slots__ = ()
 
     def __repr__(self):
-        s = '%s(%s)' % (self.__class__.__name__, getattr(self, 'name', ''))
+        name = getattr(self, 'name', '')
+        if not isinstance(name, str):
+            name = ''
+        s = '%s(%s)' % (self.__class__.__name__, name)
         w_cls = getattr(self, 'w__class__', None)
         if w_cls is not None and w_cls is not self:
             s += ' instance of %s' % self.w__class__
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -313,11 +313,11 @@
     def newlist_str(self, list_s):
         return W_ListObject.newlist_str(self, list_s)
 
-    def newdict(self, module=False, instance=False,
+    def newdict(self, module=False, instance=False, kwargs=False,
                 strdict=False):
         return W_DictMultiObject.allocate_and_init_instance(
                 self, module=module, instance=instance,
-                strdict=strdict)
+                strdict=strdict, kwargs=kwargs)
 
     def newset(self):
         from pypy.objspace.std.setobject import newset
@@ -472,6 +472,11 @@
             return w_obj.getitems_int()
         return None
 
+    def view_as_kwargs(self, w_dict):
+        if type(w_dict) is W_DictMultiObject:
+            return w_dict.view_as_kwargs()
+        return (None, None)
+
     def _uses_list_iter(self, w_obj):
         from pypy.objspace.descroperation import list_iter
         return self.lookup(w_obj, '__iter__') is list_iter(self)
diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -14,6 +14,7 @@
 from pypy.objspace.std.tupleobject import W_TupleObject
 from pypy.rlib.rstring import StringBuilder, split
 from pypy.interpreter.buffer import StringBuffer
+from pypy.rlib import jit
 
 from pypy.objspace.std.stringtype import sliced, wrapstr, wrapchar, \
      stringendswith, stringstartswith, joined2
@@ -398,6 +399,8 @@
 
     return _str_join_many_items(space, w_self, list_w, size)
 
+ at jit.look_inside_iff(lambda space, w_self, list_w, size:
+                     jit.loop_unrolling_heuristic(list_w, size))
 def _str_join_many_items(space, w_self, list_w, size):
     self = w_self._value
     reslen = len(self) * (size - 1)
diff --git a/pypy/objspace/std/test/test_kwargsdict.py b/pypy/objspace/std/test/test_kwargsdict.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/test/test_kwargsdict.py
@@ -0,0 +1,120 @@
+import py
+from pypy.conftest import gettestobjspace, option
+from pypy.objspace.std.test.test_dictmultiobject import FakeSpace, W_DictMultiObject
+from pypy.objspace.std.kwargsdict import *
+
+space = FakeSpace()
+strategy = KwargsDictStrategy(space)
+
+def test_create():
+    keys = ["a", "b", "c"]
+    values = [1, 2, 3]
+    storage = strategy.erase((keys, values))
+    d = W_DictMultiObject(space, strategy, storage)
+    assert d.getitem_str("a") == 1
+    assert d.getitem_str("b") == 2
+    assert d.getitem_str("c") == 3
+    assert d.getitem(space.wrap("a")) == 1
+    assert d.getitem(space.wrap("b")) == 2
+    assert d.getitem(space.wrap("c")) == 3
+    assert d.w_keys() == keys
+    assert d.values() == values
+
+def test_set_existing():
+    keys = ["a", "b", "c"]
+    values = [1, 2, 3]
+    storage = strategy.erase((keys, values))
+    d = W_DictMultiObject(space, strategy, storage)
+    assert d.getitem_str("a") == 1
+    assert d.getitem_str("b") == 2
+    assert d.getitem_str("c") == 3
+    assert d.setitem_str("a", 4) is None
+    assert d.getitem_str("a") == 4
+    assert d.getitem_str("b") == 2
+    assert d.getitem_str("c") == 3
+    assert d.setitem_str("b", 5) is None
+    assert d.getitem_str("a") == 4
+    assert d.getitem_str("b") == 5
+    assert d.getitem_str("c") == 3
+    assert d.setitem_str("c", 6) is None
+    assert d.getitem_str("a") == 4
+    assert d.getitem_str("b") == 5
+    assert d.getitem_str("c") == 6
+    assert d.getitem(space.wrap("a")) == 4
+    assert d.getitem(space.wrap("b")) == 5
+    assert d.getitem(space.wrap("c")) == 6
+    assert d.w_keys() == keys
+    assert d.values() == values
+    assert keys == ["a", "b", "c"]
+    assert values == [4, 5, 6]
+
+
+def test_set_new():
+    keys = ["a", "b", "c"]
+    values = [1, 2, 3]
+    storage = strategy.erase((keys, values))
+    d = W_DictMultiObject(space, strategy, storage)
+    assert d.getitem_str("a") == 1
+    assert d.getitem_str("b") == 2
+    assert d.getitem_str("c") == 3
+    assert d.getitem_str("d") is None
+    assert d.setitem_str("d", 4) is None
+    assert d.getitem_str("a") == 1
+    assert d.getitem_str("b") == 2
+    assert d.getitem_str("c") == 3
+    assert d.getitem_str("d") == 4
+    assert d.w_keys() == keys
+    assert d.values() == values
+    assert keys == ["a", "b", "c", "d"]
+    assert values == [1, 2, 3, 4]
+
+def test_limit_size():
+    storage = strategy.get_empty_storage()
+    d = W_DictMultiObject(space, strategy, storage)
+    for i in range(100):
+        assert d.setitem_str("d%s" % i, 4) is None
+    assert d.strategy is not strategy
+    assert "StringDictStrategy" == d.strategy.__class__.__name__
+
+def test_keys_doesnt_wrap():
+    space = FakeSpace()
+    space.newlist = None
+    strategy = KwargsDictStrategy(space)
+    keys = ["a", "b", "c"]
+    values = [1, 2, 3]
+    storage = strategy.erase((keys, values))
+    d = W_DictMultiObject(space, strategy, storage)
+    w_l = d.w_keys() # does not crash
+
+
+from pypy.objspace.std.test.test_dictmultiobject import BaseTestRDictImplementation, BaseTestDevolvedDictImplementation
+def get_impl(self):
+    storage = strategy.erase(([], []))
+    return W_DictMultiObject(space, strategy, storage)
+class TestKwargsDictImplementation(BaseTestRDictImplementation):
+    StrategyClass = KwargsDictStrategy
+    get_impl = get_impl
+    def test_delitem(self):
+        pass # delitem devolves for now
+
+class TestDevolvedKwargsDictImplementation(BaseTestDevolvedDictImplementation):
+    get_impl = get_impl
+    StrategyClass = KwargsDictStrategy
+
+
+class AppTestKwargsDictStrategy(object):
+    def setup_class(cls):
+        if option.runappdirect:
+            py.test.skip("__repr__ doesn't work on appdirect")
+
+    def w_get_strategy(self, obj):
+        import __pypy__
+        r = __pypy__.internal_repr(obj)
+        return r[r.find("(") + 1: r.find(")")]
+
+    def test_create(self):
+        def f(**args):
+            return args
+        d = f(a=1)
+        assert "KwargsDictStrategy" in self.get_strategy(d)
+
diff --git a/pypy/objspace/std/test/test_methodcache.py b/pypy/objspace/std/test/test_methodcache.py
--- a/pypy/objspace/std/test/test_methodcache.py
+++ b/pypy/objspace/std/test/test_methodcache.py
@@ -63,8 +63,31 @@
             assert a.f() == 42 + i
             A.f = eval("lambda self: %s" % (42 + i + 1, ))
         cache_counter = __pypy__.method_cache_counter("f")
-        # the cache hits come from A.f = ..., which first does a lookup on A as
-        # well
+        #
+        # a bit of explanation about what's going on.  (1) is the line "a.f()"
+        # and (2) is "A.f = ...".
+        #
+        # at line (1) we do the lookup on type(a).f
+        #
+        # at line (2) we do a setattr on A. However, descr_setattr does also a
+        # lookup of type(A).f i.e. type.f, to check if by chance 'f' is a data
+        # descriptor.
+        #
+        # At the first iteration:
+        # (1) is a miss because it's the first lookup of A.f. The result is cached
+        #
+        # (2) is a miss because it is the first lookup of type.f. The
+        # (non-existant) result is cached. The version of A changes, and 'f'
+        # is changed to be a cell object, so that subsequest assignments won't
+        # change the version of A
+        #
+        # At the second iteration:
+        # (1) is a miss because the version of A changed just before
+        # (2) is a hit, because type.f is cached. The version of A no longer changes
+        #
+        # At the third and subsequent iterations:
+        # (1) is a hit, because the version of A did not change
+        # (2) is a hit, see above
         assert cache_counter == (17, 3)
 
     def test_subclasses(self):
diff --git a/pypy/objspace/std/test/test_stringformat.py b/pypy/objspace/std/test/test_stringformat.py
--- a/pypy/objspace/std/test/test_stringformat.py
+++ b/pypy/objspace/std/test/test_stringformat.py
@@ -295,12 +295,11 @@
         assert u'%x' % ten == 'a'
 
     def test_long_no_overflow(self):
-        big = 100000000000L
-        assert "%x" % big == "174876e800"
+        big = 0x1234567890987654321
+        assert "%x" % big == "1234567890987654321"
 
     def test_missing_cases(self):
-        big = -123456789012345678901234567890L
-        print '%032d' % big
+        big = -123456789012345678901234567890
         assert '%032d' % big == '-0123456789012345678901234567890'
 
     def test_invalid_char(self):
diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py
--- a/pypy/objspace/std/unicodeobject.py
+++ b/pypy/objspace/std/unicodeobject.py
@@ -16,6 +16,7 @@
 from pypy.rlib.runicode import unicode_encode_unicode_escape
 from pypy.module.unicodedata import unicodedb
 from pypy.tool.sourcetools import func_with_new_name
+from pypy.rlib import jit
 
 from pypy.objspace.std.formatting import mod_format
 from pypy.objspace.std.stringtype import stringstartswith, stringendswith
@@ -214,6 +215,8 @@
 
     return _unicode_join_many_items(space, w_self, list_w, size)
 
+ at jit.look_inside_iff(lambda space, w_self, list_w, size:
+                     jit.loop_unrolling_heuristic(list_w, size))
 def _unicode_join_many_items(space, w_self, list_w, size):
     self = w_self._value
     prealloc_size = len(self) * (size - 1)
diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py
--- a/pypy/objspace/test/test_descroperation.py
+++ b/pypy/objspace/test/test_descroperation.py
@@ -694,5 +694,31 @@
         l = len(X(X(2)))
         assert l == 2 and type(l) is int
 
+    def test_bool___contains__(self):
+        class X(object):
+            def __contains__(self, item):
+                if item == 'foo':
+                    return 42
+                else:
+                    return 'hello world'
+        x = X()
+        res = 'foo' in x
+        assert res is True
+        res = 'bar' in x
+        assert res is True
+        #
+        class MyError(Exception):
+            pass
+        class CannotConvertToBool(object):
+            def __nonzero__(self):
+                raise MyError
+        class X(object):
+            def __contains__(self, item):
+                return CannotConvertToBool()
+        x = X()
+        raises(MyError, "'foo' in x")
+        
+            
+
 class AppTestWithBuiltinShortcut(AppTest_Descroperation):
     OPTIONS = {'objspace.std.builtinshortcut': True}
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -204,6 +204,14 @@
     return NonConstant(False)
 isvirtual._annspecialcase_ = "specialize:call_location"
 
+LIST_CUTOFF = 2
+
+ at specialize.call_location()
+def loop_unrolling_heuristic(lst, size):
+    """ In which cases iterating over items of lst can be unrolled
+    """
+    return isvirtual(lst) or (isconstant(size) and size <= LIST_CUTOFF)
+
 class Entry(ExtRegistryEntry):
     _about_ = hint
 
diff --git a/pypy/rlib/parsing/test/test_ebnfparse.py b/pypy/rlib/parsing/test/test_ebnfparse.py
--- a/pypy/rlib/parsing/test/test_ebnfparse.py
+++ b/pypy/rlib/parsing/test/test_ebnfparse.py
@@ -103,6 +103,7 @@
 """)
     parse = make_parse_function(regexs, rules)
     tree = parse("prefix(\n\tlonger(and_nested(term(X))), Xya, _, X0, _).")
+    assert tree.children[0].children[0].children[2].children[0].getsourcepos().lineno == 1
     assert tree is not None
     tree = parse("""
 foo(X, Y) :- bar(Y, X), bar(Y, X) ; foobar(X, Y, 1234, atom).""")
diff --git a/pypy/rlib/parsing/tree.py b/pypy/rlib/parsing/tree.py
--- a/pypy/rlib/parsing/tree.py
+++ b/pypy/rlib/parsing/tree.py
@@ -23,6 +23,9 @@
         self.symbol = symbol
         self.additional_info = additional_info
         self.token = token
+
+    def getsourcepos(self):
+        return self.token.source_pos
     
     def __repr__(self):
         return "Symbol(%r, %r)" % (self.symbol, self.additional_info)
@@ -49,6 +52,9 @@
         self.children = children
         self.symbol = symbol
 
+    def getsourcepos(self):
+        return self.children[0].getsourcepos()
+
     def __str__(self):
         return "%s(%s)" % (self.symbol, ", ".join([str(c) for c in self.children]))
 
diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -40,7 +40,7 @@
 # In that case, do 5 bits at a time.  The potential drawback is that
 # a table of 2**5 intermediate results is computed.
 
-## FIVEARY_CUTOFF = 8   disabled for now
+FIVEARY_CUTOFF = 8
 
 
 def _mask_digit(x):
@@ -456,7 +456,7 @@
 
         # python adaptation: moved macros REDUCE(X) and MULT(X, Y, result)
         # into helper function result = _help_mult(x, y, c)
-        if 1:   ## b.numdigits() <= FIVEARY_CUTOFF:
+        if b.numdigits() <= FIVEARY_CUTOFF:
             # Left-to-right binary exponentiation (HAC Algorithm 14.79)
             # http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf
             i = b.numdigits() - 1
@@ -469,30 +469,51 @@
                         z = _help_mult(z, a, c)
                     j >>= 1
                 i -= 1
-##        else:
-##            This code is disabled for now, because it assumes that
-##            SHIFT is a multiple of 5.  It could be fixed but it looks
-##            like it's more troubles than benefits...
-##
-##            # Left-to-right 5-ary exponentiation (HAC Algorithm 14.82)
-##            # This is only useful in the case where c != None.
-##            # z still holds 1L
-##            table = [z] * 32
-##            table[0] = z
-##            for i in range(1, 32):
-##                table[i] = _help_mult(table[i-1], a, c)
-##            i = b.numdigits() - 1
-##            while i >= 0:
-##                bi = b.digit(i)
-##                j = SHIFT - 5
-##                while j >= 0:
-##                    index = (bi >> j) & 0x1f
-##                    for k in range(5):
-##                        z = _help_mult(z, z, c)
-##                    if index:
-##                        z = _help_mult(z, table[index], c)
-##                    j -= 5
-##                i -= 1
+        else:
+            # Left-to-right 5-ary exponentiation (HAC Algorithm 14.82)
+            # This is only useful in the case where c != None.
+            # z still holds 1L
+            table = [z] * 32
+            table[0] = z
+            for i in range(1, 32):
+                table[i] = _help_mult(table[i-1], a, c)
+            i = b.numdigits()
+            # Note that here SHIFT is not a multiple of 5.  The difficulty
+            # is to extract 5 bits at a time from 'b', starting from the
+            # most significant digits, so that at the end of the algorithm
+            # it falls exactly to zero.
+            # m  = max number of bits = i * SHIFT
+            # m+ = m rounded up to the next multiple of 5
+            # j  = (m+) % SHIFT = (m+) - (i * SHIFT)
+            # (computed without doing "i * SHIFT", which might overflow)
+            j = i % 5
+            if j != 0:
+                j = 5 - j
+            if not we_are_translated():
+                assert j == (i*SHIFT+4)//5*5 - i*SHIFT
+            #
+            accum = r_uint(0)
+            while True:
+                j -= 5
+                if j >= 0:
+                    index = (accum >> j) & 0x1f
+                else:
+                    # 'accum' does not have enough digit.
+                    # must get the next digit from 'b' in order to complete
+                    i -= 1
+                    if i < 0:
+                        break    # done
+                    bi = b.udigit(i)
+                    index = ((accum << (-j)) | (bi >> (j+SHIFT))) & 0x1f
+                    accum = bi
+                    j += SHIFT
+                #
+                for k in range(5):
+                    z = _help_mult(z, z, c)
+                if index:
+                    z = _help_mult(z, table[index], c)
+            #
+            assert j == -5
 
         if negativeOutput and z.sign != 0:
             z = z.sub(c)
diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py
--- a/pypy/rlib/ropenssl.py
+++ b/pypy/rlib/ropenssl.py
@@ -3,8 +3,10 @@
 from pypy.translator.platform import platform
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
-import sys
+import sys, os
 
+link_files = []
+testonly_libraries = []
 if sys.platform == 'win32' and platform.name != 'mingw32':
     libraries = ['libeay32', 'ssleay32',
                  'user32', 'advapi32', 'gdi32', 'msvcrt', 'ws2_32']
@@ -17,8 +19,18 @@
         # so that openssl/ssl.h can repair this nonsense.
         'wincrypt.h']
 else:
-    libraries = ['ssl', 'crypto']
+    libraries = ['z']
     includes = []
+    if (sys.platform.startswith('linux') and
+        os.path.exists('/usr/lib/libssl.a') and
+        os.path.exists('/usr/lib/libcrypto.a')):
+        # use static linking to avoid the infinite
+        # amount of troubles due to symbol versions
+        # and 0.9.8/1.0.0
+        link_files += ['/usr/lib/libssl.a', '/usr/lib/libcrypto.a']
+        testonly_libraries += ['ssl', 'crypto']
+    else:
+        libraries += ['ssl', 'crypto']
 
 includes += [
     'openssl/ssl.h', 
@@ -30,6 +42,8 @@
 
 eci = ExternalCompilationInfo(
     libraries = libraries,
+    link_files = link_files,
+    testonly_libraries = testonly_libraries,
     includes = includes,
     export_symbols = [],
     post_include_bits = [
diff --git a/pypy/rlib/rweakref.py b/pypy/rlib/rweakref.py
--- a/pypy/rlib/rweakref.py
+++ b/pypy/rlib/rweakref.py
@@ -9,6 +9,9 @@
 
 ref = weakref.ref    # basic regular weakrefs are supported in RPython
 
+def has_weakref_support():
+    return True      # returns False if --no-translation-rweakref
+
 
 class RWeakValueDictionary(object):
     """A dictionary containing weak values."""
@@ -68,6 +71,20 @@
 from pypy.annotation.bookkeeper import getbookkeeper
 from pypy.tool.pairtype import pairtype
 
+class Entry(extregistry.ExtRegistryEntry):
+    _about_ = has_weakref_support
+
+    def compute_result_annotation(self):
+        translator = self.bookkeeper.annotator.translator
+        res = translator.config.translation.rweakref
+        return self.bookkeeper.immutablevalue(res)
+
+    def specialize_call(self, hop):
+        from pypy.rpython.lltypesystem import lltype
+        hop.exception_cannot_occur()
+        return hop.inputconst(lltype.Bool, hop.s_result.const)
+
+
 class SomeWeakValueDict(annmodel.SomeObject):
     knowntype = RWeakValueDictionary
 
diff --git a/pypy/rlib/test/test_rbigint.py b/pypy/rlib/test/test_rbigint.py
--- a/pypy/rlib/test/test_rbigint.py
+++ b/pypy/rlib/test/test_rbigint.py
@@ -379,6 +379,18 @@
         for n, expected in [(37, 9), (1291, 931), (67889, 39464)]:
             v = two.pow(t, rbigint.fromint(n))
             assert v.toint() == expected
+        #
+        # more tests, comparing against CPython's answer
+        enabled = sample(range(5*32), 10)
+        for i in range(5*32):
+            t = t.mul(two)      # add one random bit
+            if random() >= 0.5:
+                t = t.add(rbigint.fromint(1))
+            if i not in enabled:
+                continue    # don't take forever
+            n = randint(1, sys.maxint)
+            v = two.pow(t, rbigint.fromint(n))
+            assert v.toint() == pow(2, t.tolong(), n)
 
     def test_pow_lln(self):
         x = 10L
diff --git a/pypy/rlib/test/test_rweakref.py b/pypy/rlib/test/test_rweakref.py
new file mode 100644
--- /dev/null
+++ b/pypy/rlib/test/test_rweakref.py
@@ -0,0 +1,14 @@
+from pypy.rlib.rweakref import has_weakref_support
+from pypy.rpython.test.test_llinterp import interpret
+
+
+def test_has_weakref_support():
+    assert has_weakref_support()
+
+    res = interpret(lambda: has_weakref_support(), [],
+                    **{'translation.rweakref': True})
+    assert res == True
+
+    res = interpret(lambda: has_weakref_support(), [],
+                    **{'translation.rweakref': False})
+    assert res == False
diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -1072,7 +1072,7 @@
     try:
         eci = _eci_cache[old_eci]
     except KeyError:
-        eci = old_eci.compile_shared_lib()
+        eci = old_eci.compile_shared_lib(ignore_a_files=True)
         _eci_cache[old_eci] = eci
 
     libraries = eci.testonly_libraries + eci.libraries + eci.frameworks
diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py
--- a/pypy/rpython/lltypesystem/rstr.py
+++ b/pypy/rpython/lltypesystem/rstr.py
@@ -709,7 +709,8 @@
         return count
 
     @enforceargs(int, None)
-    @jit.look_inside_iff(lambda length, items: jit.isconstant(length) and length <= 2)
+    @jit.look_inside_iff(lambda length, items: jit.loop_unrolling_heuristic(
+        items, length))
     def ll_join_strs(length, items):
         # Special case for length 1 items, helps both the JIT and other code
         if length == 1:
diff --git a/pypy/rpython/module/ll_os.py b/pypy/rpython/module/ll_os.py
--- a/pypy/rpython/module/ll_os.py
+++ b/pypy/rpython/module/ll_os.py
@@ -1168,8 +1168,11 @@
             DIRENTP = lltype.Ptr(DIRENT)
             os_opendir = self.llexternal('opendir', [rffi.CCHARP], DIRP,
                                          compilation_info=compilation_info)
+            # XXX macro=True is hack to make sure we get the correct kind of
+            # dirent struct (which depends on defines)
             os_readdir = self.llexternal('readdir', [DIRP], DIRENTP,
-                                         compilation_info=compilation_info)
+                                         compilation_info=compilation_info,
+                                         macro=True)
             os_closedir = self.llexternal('closedir', [DIRP], rffi.INT,
                                           compilation_info=compilation_info)
 
diff --git a/pypy/rpython/module/test/test_ll_os.py b/pypy/rpython/module/test/test_ll_os.py
--- a/pypy/rpython/module/test/test_ll_os.py
+++ b/pypy/rpython/module/test/test_ll_os.py
@@ -4,6 +4,7 @@
 import pypy
 from pypy.tool.udir import udir
 from pypy.translator.c.test.test_genc import compile
+from pypy.rpython.module import ll_os #has side effect of registering functions
 
 from pypy.rpython import extregistry
 import errno
diff --git a/pypy/tool/clean_old_branches.py b/pypy/tool/clean_old_branches.py
--- a/pypy/tool/clean_old_branches.py
+++ b/pypy/tool/clean_old_branches.py
@@ -4,30 +4,28 @@
 called 'closed-branch'.  It reduces the number of heads.
 """
 
-import os, sys
+import os
+import sys
+import commands
 
-if not os.listdir('.hg'):
+if not os.path.isdir('.hg'):
     print 'Must run this script from the top-level directory.'
     sys.exit(1)
 
-def heads(args):
-    g = os.popen(r"hg heads --topo %s --template '{node|short}:{branches}\n'"
-                 % args, 'r')
-    result = g.read()
-    g.close()
+def heads():
+    result = commands.getoutput(
+        "hg heads --topo --closed --template '{node|short}:{branches}:{extras}\n'")
     result = result.splitlines(False)
+    result = [s.split(':', 2) for s in result]
     for line in result:
-        if len(line.split(':', 1)) != 2:
+        if len(line) != 3:
             raise ValueError("'result' contains: %r" % line)
-    result = [s.split(':', 1) for s in result]
-    result = [(head, branch) for (head, branch) in result
-                if branch not in ['', 'closed-branches']]
+    result = [(head, branch) for (head, branch, extra) in result
+                if branch not in ['', 'closed-branches'] and 'close' in extra]
     return result
 
-all_heads = heads("--closed")
-opened_heads = heads("")
 
-closed_heads = [s for s in all_heads if s not in opened_heads]
+closed_heads = heads()
 
 if not closed_heads:
     print >> sys.stderr, 'no dangling closed heads.'
@@ -56,16 +54,14 @@
         print '*** error %r' % (err,)
         sys.exit(1)
 
+print '*** switching to closed branches *** '
+do("hg up --clean closed-branches")
+do("hg --config extensions.purge= purge --all")
+
 for head, branch in closed_heads:
     print
     print '***** %s ***** %s *****' % (branch, head)
-    do("hg up --clean closed-branches")
-    do("hg --config extensions.purge= purge --all")
-    do("hg merge -y %s" % head)
-    for fn in os.listdir('.'):
-        if fn.lower() != '.hg':
-            do("rm -fr -- '%s'" % fn)
-            do("hg rm --after -- '%s' || true" % fn)
+    do("hg debugsetparents closed-branches %s" % head)
     do("hg ci -m'Merge closed head %s on branch %s'" % (head, branch))
 
 print
diff --git a/pypy/tool/test/test_udir.py b/pypy/tool/test/test_udir.py
--- a/pypy/tool/test/test_udir.py
+++ b/pypy/tool/test/test_udir.py
@@ -13,6 +13,8 @@
 def test_make_udir_with_basename():
     root = str(udir.udir.ensure('make_udir2', dir=1))
     p1 = udir.make_udir(dir=root, basename='foobar')
+    def assert_relto(path, root, expected):
+        assert path.relto(root) == expected, path.relto(root)
     assert p1.relto(root) == 'usession-foobar-0'
     p1 = udir.make_udir(dir=root, basename='-foobar')
     assert p1.relto(root) == 'usession-foobar-1'
@@ -24,3 +26,5 @@
     assert p1.relto(root) == 'usession-0'
     p1 = udir.make_udir(dir=root, basename='-')
     assert p1.relto(root) == 'usession-1'
+    p1 = udir.make_udir(dir=root, basename='fun/bar')
+    assert p1.relto(root) == 'usession-fun--bar-0'
diff --git a/pypy/tool/udir.py b/pypy/tool/udir.py
--- a/pypy/tool/udir.py
+++ b/pypy/tool/udir.py
@@ -41,6 +41,7 @@
                 basename = basename.encode(sys.getdefaultencoding())
         else:
             basename = ''
+    basename = basename.replace('/', '--')
     if not basename.startswith('-'):
         basename = '-' + basename
     if not basename.endswith('-'):
diff --git a/pypy/translator/c/extfunc.py b/pypy/translator/c/extfunc.py
--- a/pypy/translator/c/extfunc.py
+++ b/pypy/translator/c/extfunc.py
@@ -5,7 +5,6 @@
 from pypy.rpython.lltypesystem.rstr import STR, mallocstr
 from pypy.rpython.lltypesystem import rstr
 from pypy.rpython.lltypesystem import rlist
-from pypy.rpython.module import ll_time, ll_os
 
 # table of functions hand-written in src/ll_*.h
 # Note about *.im_func: The annotator and the rtyper expect direct
diff --git a/pypy/translator/c/src/exception.h b/pypy/translator/c/src/exception.h
--- a/pypy/translator/c/src/exception.h
+++ b/pypy/translator/c/src/exception.h
@@ -43,6 +43,16 @@
           filename, lineno, functionname);
 }
 #endif
+#else   /* !DO_LOG_EXC: define the function anyway, so that we can shut
+           off the prints of a debug_exc by remaking only testing_1.o */
+void RPyDebugReturnShowException(const char *msg, const char *filename,
+                                 long lineno, const char *functionname);
+#ifndef PYPY_NOT_MAIN_FILE
+void RPyDebugReturnShowException(const char *msg, const char *filename,
+                                 long lineno, const char *functionname)
+{
+}
+#endif
 #endif  /* DO_LOG_EXC */
 
 /* Hint: functions and macros not defined here, like RPyRaiseException,
diff --git a/pypy/translator/driver.py b/pypy/translator/driver.py
--- a/pypy/translator/driver.py
+++ b/pypy/translator/driver.py
@@ -115,12 +115,10 @@
         backend, ts = self.get_backend_and_type_system()
         for task in self.tasks:
             explicit_task = task
-            parts = task.split('_')
-            if len(parts) == 1:
-                if task in ('annotate',):
-                    expose_task(task)
+            if task == 'annotate':
+                expose_task(task)
             else:
-                task, postfix = parts
+                task, postfix = task.split('_')
                 if task in ('rtype', 'backendopt', 'llinterpret',
                             'pyjitpl'):
                     if ts:
diff --git a/pypy/translator/tool/cbuild.py b/pypy/translator/tool/cbuild.py
--- a/pypy/translator/tool/cbuild.py
+++ b/pypy/translator/tool/cbuild.py
@@ -267,9 +267,12 @@
         d['separate_module_files'] = ()
         return files, ExternalCompilationInfo(**d)
 
-    def compile_shared_lib(self, outputfilename=None):
+    def compile_shared_lib(self, outputfilename=None, ignore_a_files=False):
         self = self.convert_sources_to_files()
-        if not self.separate_module_files:
+        if ignore_a_files:
+            if not [fn for fn in self.link_files if fn.endswith('.a')]:
+                ignore_a_files = False    # there are none
+        if not self.separate_module_files and not ignore_a_files:
             if sys.platform != 'win32':
                 return self
             if not self.export_symbols:
@@ -288,6 +291,13 @@
                 num += 1
             basepath.ensure(dir=1)
             outputfilename = str(pth.dirpath().join(pth.purebasename))
+
+        if ignore_a_files:
+            d = self._copy_attributes()
+            d['link_files'] = [fn for fn in d['link_files']
+                                  if not fn.endswith('.a')]
+            self = ExternalCompilationInfo(**d)
+
         lib = str(host.compile([], self, outputfilename=outputfilename,
                                standalone=False))
         d = self._copy_attributes()


More information about the pypy-commit mailing list