[pypy-commit] pypy stm-thread: hg merge default

arigo noreply at buildbot.pypy.org
Sun Jun 10 16:08:28 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: stm-thread
Changeset: r55543:251d3418ca05
Date: 2012-06-10 16:05 +0200
http://bitbucket.org/pypy/pypy/changeset/251d3418ca05/

Log:	hg merge default

diff --git a/lib-python/2.7/ctypes/__init__.py b/lib-python/2.7/ctypes/__init__.py
--- a/lib-python/2.7/ctypes/__init__.py
+++ b/lib-python/2.7/ctypes/__init__.py
@@ -351,7 +351,10 @@
         self._FuncPtr = _FuncPtr
 
         if handle is None:
-            self._handle = _ffi.CDLL(name, mode)
+            if flags & _FUNCFLAG_CDECL:
+                self._handle = _ffi.CDLL(name, mode)
+            else:
+                self._handle = _ffi.WinDLL(name, mode)
         else:
             self._handle = handle
 
diff --git a/lib-python/2.7/pickle.py b/lib-python/2.7/pickle.py
--- a/lib-python/2.7/pickle.py
+++ b/lib-python/2.7/pickle.py
@@ -638,7 +638,7 @@
             # else tmp is empty, and we're done
 
     def save_dict(self, obj):
-        modict_saver = self._pickle_moduledict(obj)
+        modict_saver = self._pickle_maybe_moduledict(obj)
         if modict_saver is not None:
             return self.save_reduce(*modict_saver)
 
@@ -691,26 +691,20 @@
                 write(SETITEM)
             # else tmp is empty, and we're done
 
-    def _pickle_moduledict(self, obj):
+    def _pickle_maybe_moduledict(self, obj):
         # save module dictionary as "getattr(module, '__dict__')"
+        try:
+            name = obj['__name__']
+            if type(name) is not str:
+                return None
+            themodule = sys.modules[name]
+            if type(themodule) is not ModuleType:
+                return None
+            if themodule.__dict__ is not obj:
+                return None
+        except (AttributeError, KeyError, TypeError):
+            return None
 
-        # build index of module dictionaries
-        try:
-            modict = self.module_dict_ids
-        except AttributeError:
-            modict = {}
-            from sys import modules
-            for mod in modules.values():
-                if isinstance(mod, ModuleType):
-                    modict[id(mod.__dict__)] = mod
-            self.module_dict_ids = modict
-
-        thisid = id(obj)
-        try:
-            themodule = modict[thisid]
-        except KeyError:
-            return None
-        from __builtin__ import getattr
         return getattr, (themodule, '__dict__')
 
 
diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -391,7 +391,7 @@
         address = self._get_address()
         ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
         ffires = restype.get_ffi_argtype()
-        return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires)
+        return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires, self._flags_)
 
     def _getfuncptr(self, argtypes, restype, thisarg=None):
         if self._ptr is not None and (argtypes is self._argtypes_ or argtypes == self._argtypes_):
@@ -412,7 +412,7 @@
             ptr = thisarg[0][self._com_index - 0x1000]
             ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
             ffires = restype.get_ffi_argtype()
-            return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires)
+            return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires, self._flags_)
         
         cdll = self.dll._handle
         try:
diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -99,7 +99,8 @@
                  requires={
                      "shadowstack": [("translation.gctransformer", "framework")],
                      "asmgcc": [("translation.gctransformer", "framework"),
-                                ("translation.backend", "c")],
+                                ("translation.backend", "c"),
+                                ("translation.shared", False)],
                     }),
 
     # other noticeable options
diff --git a/pypy/doc/coding-guide.rst b/pypy/doc/coding-guide.rst
--- a/pypy/doc/coding-guide.rst
+++ b/pypy/doc/coding-guide.rst
@@ -610,10 +610,6 @@
     >>>> cPickle.__file__
     '/home/hpk/pypy-dist/lib_pypy/cPickle..py'
 
-    >>>> import opcode
-    >>>> opcode.__file__
-    '/home/hpk/pypy-dist/lib-python/modified-2.7/opcode.py'
-
     >>>> import os
     >>>> os.__file__
     '/home/hpk/pypy-dist/lib-python/2.7/os.py'
@@ -639,13 +635,9 @@
 
     contains pure Python reimplementation of modules.
 
-*lib-python/modified-2.7/*
-
-    The files and tests that we have modified from the CPython library.
-
 *lib-python/2.7/*
 
-    The unmodified CPython library. **Never ever check anything in there**.
+    The modified CPython library.
 
 .. _`modify modules`:
 
@@ -658,16 +650,9 @@
 by default and CPython has a number of places where it relies
 on some classes being old-style.
 
-If you want to change a module or test contained in ``lib-python/2.7``
-then make sure that you copy the file to our ``lib-python/modified-2.7``
-directory first.  In mercurial commandline terms this reads::
-
-    $ hg cp lib-python/2.7/somemodule.py lib-python/modified-2.7/
-
-and subsequently you edit and commit
-``lib-python/modified-2.7/somemodule.py``.  This copying operation is
-important because it keeps the original CPython tree clean and makes it
-obvious what we had to change.
+We just maintain those changes in place,
+to see what is changed we have a branch called `vendot/stdlib`
+wich contains the unmodified cpython stdlib
 
 .. _`mixed module mechanism`:
 .. _`mixed modules`:
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -45,9 +45,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '1.8'
+version = '1.9'
 # The full version, including alpha/beta/rc tags.
-release = '1.8'
+release = '1.9'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
--- a/pypy/doc/cppyy.rst
+++ b/pypy/doc/cppyy.rst
@@ -71,10 +71,14 @@
 .. _`recent snapshot`: http://cern.ch/wlav/reflex-2012-05-02.tar.bz2
 .. _`gccxml`: http://www.gccxml.org
 
-Next, get the `PyPy sources`_, select the reflex-support branch, and build
-pypy-c.
+Next, get the `PyPy sources`_, select the reflex-support branch, and build.
 For the build to succeed, the ``$ROOTSYS`` environment variable must point to
-the location of your ROOT (or standalone Reflex) installation::
+the location of your ROOT (or standalone Reflex) installation, or the
+``root-config`` utility must be accessible through ``PATH`` (e.g. by adding
+``$ROOTSYS/bin`` to ``PATH``).
+In case of the former, include files are expected under ``$ROOTSYS/include``
+and libraries under ``$ROOTSYS/lib``.
+Then run the translation to build ``pypy-c``::
 
     $ hg clone https://bitbucket.org/pypy/pypy
     $ cd pypy
@@ -115,7 +119,7 @@
 code::
 
     $ genreflex MyClass.h
-    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o libMyClassDict.so
+    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o libMyClassDict.so -L$ROOTSYS/lib -lReflex
 
 Now you're ready to use the bindings.
 Since the bindings are designed to look pythonistic, it should be
@@ -139,6 +143,51 @@
 That's all there is to it!
 
 
+Automatic class loader
+======================
+There is one big problem in the code above, that prevents its use in a (large
+scale) production setting: the explicit loading of the reflection library.
+Clearly, if explicit load statements such as these show up in code downstream
+from the ``MyClass`` package, then that prevents the ``MyClass`` author from
+repackaging or even simply renaming the dictionary library.
+
+The solution is to make use of an automatic class loader, so that downstream
+code never has to call ``load_reflection_info()`` directly.
+The class loader makes use of so-called rootmap files, which ``genreflex``
+can produce.
+These files contain the list of available C++ classes and specify the library
+that needs to be loaded for their use.
+By convention, the rootmap files should be located next to the reflection info
+libraries, so that they can be found through the normal shared library search
+path.
+They can be concatenated together, or consist of a single rootmap file per
+library.
+For example::
+
+    $ genreflex MyClass.h --rootmap=libMyClassDict.rootmap --rootmap-lib=libMyClassDict.so
+    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyClass_rflx.cpp -o libMyClassDict.so -L$ROOTSYS/lib -lReflex
+
+where the first option (``--rootmap``) specifies the output file name, and the
+second option (``--rootmap-lib``) the name of the reflection library where
+``MyClass`` will live.
+It is necessary to provide that name explicitly, since it is only in the
+separate linking step where this name is fixed.
+If the second option is not given, the library is assumed to be libMyClass.so,
+a name that is derived from the name of the header file.
+
+With the rootmap file in place, the above example can be rerun without explicit
+loading of the reflection info library::
+
+    $ pypy-c
+    >>>> import cppyy
+    >>>> myinst = cppyy.gbl.MyClass(42)
+    >>>> print myinst.GetMyInt()
+    42
+    >>>> # etc. ...
+
+As a caveat, note that the class loader is currently limited to classes only.
+
+
 Advanced example
 ================
 The following snippet of C++ is very contrived, to allow showing that such
@@ -171,7 +220,7 @@
         std::string m_name;
     };
 
-    Base1* BaseFactory(const std::string& name, int i, double d) {
+    Base2* BaseFactory(const std::string& name, int i, double d) {
         return new Derived(name, i, d);
     }
 
@@ -213,7 +262,7 @@
 Now the reflection info can be generated and compiled::
 
     $ genreflex MyAdvanced.h --selection=MyAdvanced.xml
-    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyAdvanced_rflx.cpp -o libAdvExDict.so
+    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyAdvanced_rflx.cpp -o libAdvExDict.so -L$ROOTSYS/lib -lReflex
 
 and subsequently be used from PyPy::
 
@@ -237,7 +286,7 @@
 
 A couple of things to note, though.
 If you look back at the C++ definition of the ``BaseFactory`` function,
-you will see that it declares the return type to be a ``Base1``, yet the
+you will see that it declares the return type to be a ``Base2``, yet the
 bindings return an object of the actual type ``Derived``?
 This choice is made for a couple of reasons.
 First, it makes method dispatching easier: if bound objects are always their
@@ -361,6 +410,11 @@
   If a pointer is a global variable, the C++ side can replace the underlying
   object and the python side will immediately reflect that.
 
+* **PyObject***: Arguments and return types of ``PyObject*`` can be used, and
+  passed on to CPython API calls.
+  Since these CPython-like objects need to be created and tracked (this all
+  happens through ``cpyext``) this interface is not particularly fast.
+
 * **static data members**: Are represented as python property objects on the
   class and the meta-class.
   Both read and write access is as expected.
@@ -429,7 +483,9 @@
         int m_i;
     };
 
-    template class std::vector<MyClass>;
+    #ifdef __GCCXML__
+    template class std::vector<MyClass>;   // explicit instantiation
+    #endif
 
 If you know for certain that all symbols will be linked in from other sources,
 you can also declare the explicit template instantiation ``extern``.
@@ -440,8 +496,9 @@
 internal namespace, rather than in the iterator classes.
 One way to handle this, is to deal with this once in a macro, then reuse that
 macro for all ``vector`` classes.
-Thus, the header above needs this, instead of just the explicit instantiation
-of the ``vector<MyClass>``::
+Thus, the header above needs this (again protected with
+``#ifdef __GCCXML__``), instead of just the explicit instantiation of the
+``vector<MyClass>``::
 
     #define STLTYPES_EXPLICIT_INSTANTIATION_DECL(STLTYPE, TTYPE)                      \
     template class std::STLTYPE< TTYPE >;                                             \
@@ -462,11 +519,9 @@
     $ cat MyTemplate.xml
     <lcgdict>
         <class pattern="std::vector<*>" />
-        <class pattern="__gnu_cxx::__normal_iterator<*>" />
-        <class pattern="__gnu_cxx::new_allocator<*>" />
+        <class pattern="std::vector<*>::iterator" />
         <class pattern="std::_Vector_base<*>" />
         <class pattern="std::_Vector_base<*>::_Vector_impl" />
-        <class pattern="std::allocator<*>" />
         <function name="__gnu_cxx::operator=="/>
         <function name="__gnu_cxx::operator!="/>
 
@@ -475,8 +530,8 @@
 
 Run the normal ``genreflex`` and compilation steps::
 
-    $ genreflex MyTemplate.h --selection=MyTemplate.xm
-    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyTemplate_rflx.cpp -o libTemplateDict.so
+    $ genreflex MyTemplate.h --selection=MyTemplate.xml
+    $ g++ -fPIC -rdynamic -O2 -shared -I$ROOTSYS/include MyTemplate_rflx.cpp -o libTemplateDict.so -L$ROOTSYS/lib -lReflex
 
 Note: this is a dirty corner that clearly could do with some automation,
 even if the macro already helps.
@@ -550,7 +605,9 @@
 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``.
+called ``loadDictionary`` rather than ``load_reflection_info`` (it has the
+same rootmap-based class loader functionality, though, making this point
+somewhat moot).
 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,
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
@@ -85,13 +85,6 @@
 
     _winreg
 
-  Note that only some of these modules are built-in in a typical
-  CPython installation, and the rest is from non built-in extension
-  modules.  This means that e.g. ``import parser`` will, on CPython,
-  find a local file ``parser.py``, while ``import sys`` will not find a
-  local file ``sys.py``.  In PyPy the difference does not exist: all
-  these modules are built-in.
-
 * Supported by being rewritten in pure Python (possibly using ``ctypes``):
   see the `lib_pypy/`_ directory.  Examples of modules that we
   support this way: ``ctypes``, ``cPickle``, ``cmath``, ``dbm``, ``datetime``...
@@ -324,5 +317,10 @@
   type and vice versa. For builtin types, a dictionary will be returned that
   cannot be changed (but still looks and behaves like a normal dictionary).
 
+* the ``__len__`` or ``__length_hint__`` special methods are sometimes
+  called by CPython to get a length estimate to preallocate internal arrays.
+  So far, PyPy never calls ``__len__`` for this purpose, and never calls
+  ``__length_hint__`` at all.
+
 
 .. include:: _ref.txt
diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst
--- a/pypy/doc/getting-started-python.rst
+++ b/pypy/doc/getting-started-python.rst
@@ -103,10 +103,12 @@
 executable. The executable behaves mostly like a normal Python interpreter::
 
     $ ./pypy-c
-    Python 2.7.2 (0e28b379d8b3, Feb 09 2012, 19:41:03)
-    [PyPy 1.8.0 with GCC 4.4.3] on linux2
+    Python 2.7.2 (341e1e3821ff, Jun 07 2012, 15:40:31)
+    [PyPy 1.9.0 with GCC 4.4.3] on linux2
     Type "help", "copyright", "credits" or "license" for more information.
-    And now for something completely different: ``this sentence is false''
+    And now for something completely different: ``RPython magically makes you rich
+    and famous (says so on the tin)''
+
     >>>> 46 - 4
     42
     >>>> from test import pystone
@@ -220,7 +222,6 @@
    ./include/
    ./lib_pypy/
    ./lib-python/2.7
-   ./lib-python/modified-2.7
    ./site-packages/
 
 The hierarchy shown above is relative to a PREFIX directory.  PREFIX is
diff --git a/pypy/doc/getting-started.rst b/pypy/doc/getting-started.rst
--- a/pypy/doc/getting-started.rst
+++ b/pypy/doc/getting-started.rst
@@ -53,10 +53,10 @@
 PyPy is ready to be executed as soon as you unpack the tarball or the zip
 file, with no need to install it in any specific location::
 
-    $ tar xf pypy-1.8-linux.tar.bz2
-    $ ./pypy-1.8/bin/pypy
-    Python 2.7.2 (0e28b379d8b3, Feb 09 2012, 19:41:03)
-    [PyPy 1.8.0 with GCC 4.4.3] on linux2
+    $ tar xf pypy-1.9-linux.tar.bz2
+    $ ./pypy-1.9/bin/pypy
+    Python 2.7.2 (341e1e3821ff, Jun 07 2012, 15:40:31)
+    [PyPy 1.9.0 with GCC 4.4.3] on linux2
     Type "help", "copyright", "credits" or "license" for more information.
     And now for something completely different: ``it seems to me that once you
     settle on an execution / object model and / or bytecode format, you've already
@@ -76,14 +76,14 @@
 
     $ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py
 
-    $ ./pypy-1.8/bin/pypy distribute_setup.py
+    $ ./pypy-1.9/bin/pypy distribute_setup.py
 
-    $ ./pypy-1.8/bin/pypy get-pip.py
+    $ ./pypy-1.9/bin/pypy get-pip.py
 
-    $ ./pypy-1.8/bin/pip install pygments  # for example
+    $ ./pypy-1.9/bin/pip install pygments  # for example
 
-3rd party libraries will be installed in ``pypy-1.8/site-packages``, and
-the scripts in ``pypy-1.8/bin``.
+3rd party libraries will be installed in ``pypy-1.9/site-packages``, and
+the scripts in ``pypy-1.9/bin``.
 
 Installing using virtualenv
 ---------------------------
diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst
--- a/pypy/doc/index.rst
+++ b/pypy/doc/index.rst
@@ -15,7 +15,7 @@
 
 * `FAQ`_: some frequently asked questions.
 
-* `Release 1.8`_: the latest official release
+* `Release 1.9`_: the latest official release
 
 * `PyPy Blog`_: news and status info about PyPy 
 
@@ -75,7 +75,7 @@
 .. _`Getting Started`: getting-started.html
 .. _`Papers`: extradoc.html
 .. _`Videos`: video-index.html
-.. _`Release 1.8`: http://pypy.org/download.html
+.. _`Release 1.9`: http://pypy.org/download.html
 .. _`speed.pypy.org`: http://speed.pypy.org
 .. _`RPython toolchain`: translation.html
 .. _`potential project ideas`: project-ideas.html
@@ -120,9 +120,9 @@
 Windows, on top of .NET, and on top of Java.
 To dig into PyPy it is recommended to try out the current
 Mercurial default branch, which is always working or mostly working,
-instead of the latest release, which is `1.8`__.
+instead of the latest release, which is `1.9`__.
 
-.. __: release-1.8.0.html
+.. __: release-1.9.0.html
 
 PyPy is mainly developed on Linux and Mac OS X.  Windows is supported,
 but platform-specific bugs tend to take longer before we notice and fix
diff --git a/pypy/doc/release-1.9.0.rst b/pypy/doc/release-1.9.0.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/release-1.9.0.rst
@@ -0,0 +1,111 @@
+====================
+PyPy 1.9 - Yard Wolf
+====================
+
+We're pleased to announce the 1.9 release of PyPy. This release brings mostly
+bugfixes, performance improvements, other small improvements and overall
+progress on the `numpypy`_ effort.
+It also brings an improved situation on Windows and OS X.
+
+You can download the PyPy 1.9 release here:
+
+    http://pypy.org/download.html 
+
+.. _`numpypy`: http://pypy.org/numpydonate.html
+
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 1.9 and cpython 2.7.2`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 64 or
+Windows 32.  Windows 64 work is still stalling, we would welcome a volunteer
+to handle that.
+
+.. _`pypy 1.9 and cpython 2.7.2`: http://speed.pypy.org
+
+
+Thanks to our donors
+====================
+
+But first of all, we would like to say thank you to all people who
+donated some money to one of our four calls:
+
+  * `NumPy in PyPy`_ (got so far $44502 out of $60000, 74%)
+
+  * `Py3k (Python 3)`_ (got so far $43563 out of $105000, 41%)
+
+  * `Software Transactional Memory`_ (got so far $21791 of $50400, 43%)
+
+  * as well as our general PyPy pot.
+
+Thank you all for proving that it is indeed possible for a small team of
+programmers to get funded like that, at least for some
+time.  We want to include this thank you in the present release
+announcement even though most of the work is not finished yet.  More
+precisely, neither Py3k nor STM are ready to make it in an official release
+yet: people interested in them need to grab and (attempt to) translate
+PyPy from the corresponding branches (respectively ``py3k`` and
+``stm-thread``).
+
+.. _`NumPy in PyPy`: http://pypy.org/numpydonate.html
+.. _`Py3k (Python 3)`: http://pypy.org/py3donate.html
+.. _`Software Transactional Memory`: http://pypy.org/tmdonate.html
+
+Highlights
+==========
+
+* This release still implements Python 2.7.2.
+
+* Many bugs were corrected for Windows 32 bit.  This includes new
+  functionality to test the validity of file descriptors; and
+  correct handling of the calling convensions for ctypes.  (Still not
+  much progress on Win64.) A lot of work on this has been done by Matti Picus
+  and Amaury Forgeot d'Arc.
+
+* Improvements in ``cpyext``, our emulator for CPython C extension modules.
+  For example PyOpenSSL should now work.  We thank various people for help.
+
+* Sets now have strategies just like dictionaries. This means for example
+  that a set containing only ints will be more compact (and faster).
+
+* A lot of progress on various aspects of ``numpypy``. See the `numpy-status`_
+  page for the automatic report.
+
+* It is now possible to create and manipulate C-like structures using the
+  PyPy-only ``_ffi`` module.  The advantage over using e.g. ``ctypes`` is that
+  ``_ffi`` is very JIT-friendly, and getting/setting of fields is translated
+  to few assembler instructions by the JIT. However, this is mostly intended
+  as a low-level backend to be used by more user-friendly FFI packages, and
+  the API might change in the future. Use it at your own risk.
+
+* The non-x86 backends for the JIT are progressing but are still not
+  merged (ARMv7 and PPC64).
+
+* JIT hooks for inspecting the created assembler code have been improved.
+  See `JIT hooks documentation`_ for details.
+
+* ``select.kqueue`` has been added (BSD).
+
+* Handling of keyword arguments has been drastically improved in the best-case
+  scenario: proxy functions which simply forwards ``*args`` and ``**kwargs``
+  to another function now performs much better with the JIT.
+
+* List comprehension has been improved.
+
+.. _`numpy-status`: http://buildbot.pypy.org/numpy-status/latest.html
+.. _`JIT hooks documentation`: http://doc.pypy.org/en/latest/jit-hooks.html
+
+JitViewer
+=========
+
+There is a corresponding 1.9 release of JitViewer which is guaranteed to work
+with PyPy 1.9. See the `JitViewer docs`_ for details.
+
+.. _`JitViewer docs`: http://bitbucket.org/pypy/jitviewer
+
+Cheers,
+The PyPy Team
diff --git a/pypy/doc/whatsnew-1.9.rst b/pypy/doc/whatsnew-1.9.rst
--- a/pypy/doc/whatsnew-1.9.rst
+++ b/pypy/doc/whatsnew-1.9.rst
@@ -84,6 +84,8 @@
 _invalid_parameter_handler
 .. branch: win32-kill
 Add os.kill to windows even if translating python does not have os.kill
+.. branch: win_ffi
+Handle calling conventions for the _ffi and ctypes modules
 .. branch: win64-stage1
 .. branch: zlib-mem-pressure
 Memory "leaks" associated with zlib are fixed.
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -1110,6 +1110,79 @@
     def test_virtual_ref_finish(self):
         pass   # VIRTUAL_REF_FINISH must not reach the backend nowadays
 
+    def test_arguments_to_execute_token(self):
+        # this test checks that execute_token() can be called with any
+        # variant of ints and floats as arguments
+        if self.cpu.supports_floats:
+            numkinds = 2
+        else:
+            numkinds = 1
+        seed = random.randrange(0, 10000)
+        print 'Seed is', seed    # or choose it by changing the previous line
+        r = random.Random()
+        r.seed(seed)
+        for nb_args in range(50):
+            print 'Passing %d arguments to execute_token...' % nb_args
+            #
+            inputargs = []
+            values = []
+            for k in range(nb_args):
+                kind = r.randrange(0, numkinds)
+                if kind == 0:
+                    inputargs.append(BoxInt())
+                    values.append(r.randrange(-100000, 100000))
+                else:
+                    inputargs.append(BoxFloat())
+                    values.append(longlong.getfloatstorage(r.random()))
+            #
+            looptoken = JitCellToken()
+            faildescr = BasicFailDescr(42)
+            operations = []
+            retboxes = []
+            retvalues = []
+            #
+            ks = range(nb_args)
+            random.shuffle(ks)
+            for k in ks:
+                if isinstance(inputargs[k], BoxInt):
+                    newbox = BoxInt()
+                    x = r.randrange(-100000, 100000)
+                    operations.append(
+                        ResOperation(rop.INT_ADD, [inputargs[k],
+                                                   ConstInt(x)], newbox)
+                        )
+                    y = values[k] + x
+                else:
+                    newbox = BoxFloat()
+                    x = r.random()
+                    operations.append(
+                        ResOperation(rop.FLOAT_ADD, [inputargs[k],
+                                                     constfloat(x)], newbox)
+                        )
+                    y = longlong.getrealfloat(values[k]) + x
+                    y = longlong.getfloatstorage(y)
+                kk = r.randrange(0, len(retboxes)+1)
+                retboxes.insert(kk, newbox)
+                retvalues.insert(kk, y)
+            #
+            operations.append(
+                ResOperation(rop.FINISH, retboxes, None, descr=faildescr)
+                )
+            print inputargs
+            for op in operations:
+                print op
+            self.cpu.compile_loop(inputargs, operations, looptoken)
+            #
+            fail = self.cpu.execute_token(looptoken, *values)
+            assert fail.identifier == 42
+            #
+            for k in range(len(retvalues)):
+                if isinstance(retboxes[k], BoxInt):
+                    got = self.cpu.get_latest_value_int(k)
+                else:
+                    got = self.cpu.get_latest_value_float(k)
+                assert got == retvalues[k]
+
     def test_jump(self):
         # this test generates small loops where the JUMP passes many
         # arguments of various types, shuffling them around.
diff --git a/pypy/jit/backend/x86/test/test_ztranslation.py b/pypy/jit/backend/x86/test/test_ztranslation.py
--- a/pypy/jit/backend/x86/test/test_ztranslation.py
+++ b/pypy/jit/backend/x86/test/test_ztranslation.py
@@ -69,7 +69,7 @@
         #
         from pypy.rpython.lltypesystem import lltype, rffi
         from pypy.rlib.libffi import types, CDLL, ArgChain
-        from pypy.rlib.test.test_libffi import get_libm_name
+        from pypy.rlib.test.test_clibffi import get_libm_name
         libm_name = get_libm_name(sys.platform)
         jitdriver2 = JitDriver(greens=[], reds = ['i', 'func', 'res', 'x'])
         def libffi_stuff(i, j):
diff --git a/pypy/jit/backend/x86/tool/viewcode.py b/pypy/jit/backend/x86/tool/viewcode.py
--- a/pypy/jit/backend/x86/tool/viewcode.py
+++ b/pypy/jit/backend/x86/tool/viewcode.py
@@ -253,7 +253,7 @@
                 self.logentries[addr] = pieces[3]
             elif line.startswith('SYS_EXECUTABLE '):
                 filename = line[len('SYS_EXECUTABLE '):].strip()
-                if filename != self.executable_name:
+                if filename != self.executable_name and filename != '??':
                     self.symbols.update(load_symbols(filename))
                     self.executable_name = filename
 
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -44,6 +44,8 @@
         'list_strategy'             : 'interp_magic.list_strategy',
         'validate_fd'               : 'interp_magic.validate_fd',
     }
+    if sys.platform == 'win32':
+        interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp'
 
     submodules = {
         "builders": BuildersModule,
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -88,3 +88,10 @@
         rposix.validate_fd(fd)
     except OSError, e:
         raise wrap_oserror(space, e)
+
+def get_console_cp(space):
+    from pypy.rlib import rwin32    # Windows only
+    return space.newtuple([
+        space.wrap('cp%d' % rwin32.GetConsoleCP()),
+        space.wrap('cp%d' % rwin32.GetConsoleOutputCP()),
+        ])
diff --git a/pypy/module/_ffi/__init__.py b/pypy/module/_ffi/__init__.py
--- a/pypy/module/_ffi/__init__.py
+++ b/pypy/module/_ffi/__init__.py
@@ -1,4 +1,5 @@
 from pypy.interpreter.mixedmodule import MixedModule
+import os
 
 class Module(MixedModule):
 
@@ -10,7 +11,8 @@
         '_StructDescr': 'interp_struct.W__StructDescr',
         'Field':     'interp_struct.W_Field',
     }
-
+    if os.name == 'nt':
+        interpleveldefs['WinDLL'] = 'interp_funcptr.W_WinDLL'
     appleveldefs = {
         'Structure': 'app_struct.Structure',
         }
diff --git a/pypy/module/_ffi/interp_funcptr.py b/pypy/module/_ffi/interp_funcptr.py
--- a/pypy/module/_ffi/interp_funcptr.py
+++ b/pypy/module/_ffi/interp_funcptr.py
@@ -9,6 +9,7 @@
 #
 from pypy.rlib import jit
 from pypy.rlib import libffi
+from pypy.rlib.clibffi import get_libc_name, StackCheckError
 from pypy.rlib.rdynload import DLOpenError
 from pypy.rlib.rarithmetic import intmask, r_uint
 from pypy.rlib.objectmodel import we_are_translated
@@ -59,7 +60,10 @@
         self = jit.promote(self)
         argchain = self.build_argchain(space, args_w)
         func_caller = CallFunctionConverter(space, self.func, argchain)
-        return func_caller.do_and_wrap(self.w_restype)
+        try:
+            return func_caller.do_and_wrap(self.w_restype)
+        except StackCheckError, e:
+            raise OperationError(space.w_ValueError, space.wrap(e.message))
         #return self._do_call(space, argchain)
 
     def free_temp_buffers(self, space):
@@ -230,13 +234,14 @@
     restype = unwrap_ffitype(space, w_restype, allow_void=True)
     return argtypes_w, argtypes, w_restype, restype
 
- at unwrap_spec(addr=r_uint, name=str)
-def descr_fromaddr(space, w_cls, addr, name, w_argtypes, w_restype):
+ at unwrap_spec(addr=r_uint, name=str, flags=int)
+def descr_fromaddr(space, w_cls, addr, name, w_argtypes, 
+                    w_restype, flags=libffi.FUNCFLAG_CDECL):
     argtypes_w, argtypes, w_restype, restype = unpack_argtypes(space,
                                                                w_argtypes,
                                                                w_restype)
     addr = rffi.cast(rffi.VOIDP, addr)
-    func = libffi.Func(name, argtypes, restype, addr)
+    func = libffi.Func(name, argtypes, restype, addr, flags)
     return W_FuncPtr(func, argtypes_w, w_restype)
 
 
@@ -254,6 +259,7 @@
 
 class W_CDLL(Wrappable):
     def __init__(self, space, name, mode):
+        self.flags = libffi.FUNCFLAG_CDECL
         self.space = space
         if name is None:
             self.name = "<None>"
@@ -271,7 +277,8 @@
                                                                    w_argtypes,
                                                                    w_restype)
         try:
-            func = self.cdll.getpointer(name, argtypes, restype)
+            func = self.cdll.getpointer(name, argtypes, restype, 
+                                            flags = self.flags)
         except KeyError:
             raise operationerrfmt(space.w_AttributeError,
                                   "No symbol %s found in library %s", name, self.name)
@@ -300,10 +307,26 @@
     getaddressindll = interp2app(W_CDLL.getaddressindll),
     )
 
+class W_WinDLL(W_CDLL):
+    def __init__(self, space, name, mode):
+        W_CDLL.__init__(self, space, name, mode)
+        self.flags = libffi.FUNCFLAG_STDCALL
+
+ at unwrap_spec(name='str_or_None', mode=int)
+def descr_new_windll(space, w_type, name, mode=-1):
+    return space.wrap(W_WinDLL(space, name, mode))
+
+
+W_WinDLL.typedef = TypeDef(
+    '_ffi.WinDLL',
+    __new__     = interp2app(descr_new_windll),
+    getfunc     = interp2app(W_WinDLL.getfunc),
+    getaddressindll = interp2app(W_WinDLL.getaddressindll),
+    )
+
 # ========================================================================
 
 def get_libc(space):
-    from pypy.rlib.clibffi import get_libc_name
     try:
         return space.wrap(W_CDLL(space, get_libc_name(), -1))
     except OSError, e:
diff --git a/pypy/module/_ffi/test/test_funcptr.py b/pypy/module/_ffi/test/test_funcptr.py
--- a/pypy/module/_ffi/test/test_funcptr.py
+++ b/pypy/module/_ffi/test/test_funcptr.py
@@ -1,11 +1,11 @@
 from pypy.conftest import gettestobjspace
-from pypy.translator.platform import platform
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.module._rawffi.interp_rawffi import TYPEMAP
-from pypy.module._rawffi.tracker import Tracker
-from pypy.translator.platform import platform
+from pypy.rpython.lltypesystem import rffi
+from pypy.rlib.clibffi import get_libc_name
+from pypy.rlib.libffi import types
+from pypy.rlib.libffi import CDLL
+from pypy.rlib.test.test_clibffi import get_libm_name
 
-import os, sys, py
+import sys, py
 
 class BaseAppTestFFI(object):
 
@@ -37,9 +37,6 @@
         return str(platform.compile([c_file], eci, 'x', standalone=False))
 
     def setup_class(cls):
-        from pypy.rpython.lltypesystem import rffi
-        from pypy.rlib.libffi import get_libc_name, CDLL, types
-        from pypy.rlib.test.test_libffi import get_libm_name
         space = gettestobjspace(usemodules=('_ffi', '_rawffi'))
         cls.space = space
         cls.w_iswin32 = space.wrap(sys.platform == 'win32')
@@ -96,7 +93,7 @@
 
     def test_getaddressindll(self):
         import sys
-        from _ffi import CDLL, types
+        from _ffi import CDLL
         libm = CDLL(self.libm_name)
         pow_addr = libm.getaddressindll('pow')
         fff = sys.maxint*2-1
@@ -105,7 +102,6 @@
         assert pow_addr == self.pow_addr & fff
 
     def test_func_fromaddr(self):
-        import sys
         from _ffi import CDLL, types, FuncPtr
         libm = CDLL(self.libm_name)
         pow_addr = libm.getaddressindll('pow')
@@ -569,3 +565,66 @@
             skip("unix specific")
         libnone = CDLL(None)
         raises(AttributeError, "libnone.getfunc('I_do_not_exist', [], types.void)")
+
+    def test_calling_convention1(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import WinDLL, types
+        libm = WinDLL(self.libm_name)
+        pow = libm.getfunc('pow', [types.double, types.double], types.double)
+        try:
+            pow(2, 3)
+        except ValueError, e:
+            assert e.message.startswith('Procedure called with')
+        else:
+            assert 0, 'test must assert, wrong calling convention'
+
+    def test_calling_convention2(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import WinDLL, types
+        kernel = WinDLL('Kernel32.dll')
+        sleep = kernel.getfunc('Sleep', [types.uint], types.void)
+        sleep(10)
+
+    def test_calling_convention3(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import CDLL, types
+        wrong_kernel = CDLL('Kernel32.dll')
+        wrong_sleep = wrong_kernel.getfunc('Sleep', [types.uint], types.void)
+        try:
+            wrong_sleep(10)
+        except ValueError, e:
+            assert e.message.startswith('Procedure called with')
+        else:
+            assert 0, 'test must assert, wrong calling convention'
+
+    def test_func_fromaddr2(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import CDLL, types, FuncPtr
+        from _rawffi import FUNCFLAG_STDCALL
+        libm = CDLL(self.libm_name)
+        pow_addr = libm.getaddressindll('pow')
+        wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow', 
+                [types.double, types.double], types.double, FUNCFLAG_STDCALL)
+        try:
+            wrong_pow(2, 3) == 8
+        except ValueError, e:
+            assert e.message.startswith('Procedure called with')
+        else:
+            assert 0, 'test must assert, wrong calling convention'
+
+    def test_func_fromaddr3(self):
+        if not self.iswin32:
+            skip("windows specific")
+        from _ffi import WinDLL, types, FuncPtr
+        from _rawffi import FUNCFLAG_STDCALL
+        kernel = WinDLL('Kernel32.dll')
+        sleep_addr = kernel.getaddressindll('Sleep')
+        sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint], 
+                            types.void, FUNCFLAG_STDCALL)
+        sleep(10)
+
+ 
diff --git a/pypy/module/_ffi/test/test_type_converter.py b/pypy/module/_ffi/test/test_type_converter.py
--- a/pypy/module/_ffi/test/test_type_converter.py
+++ b/pypy/module/_ffi/test/test_type_converter.py
@@ -144,6 +144,7 @@
     get_unichar_p = get_all
     get_float = get_all
     get_singlefloat = get_all
+    get_unsigned_which_fits_into_a_signed = get_all
     
     def convert(self, w_ffitype, val):
         self.val = val
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -36,7 +36,7 @@
 class AppTestApi:
     def setup_class(cls):
         cls.space = gettestobjspace(usemodules=['cpyext', 'thread', '_rawffi', 'array'])
-        from pypy.rlib.libffi import get_libc_name
+        from pypy.rlib.clibffi import get_libc_name
         cls.w_libc = cls.space.wrap(get_libc_name())
 
     def test_load_error(self):
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -263,7 +263,7 @@
                 w_mod = check_sys_modules_w(space, rel_modulename)
                 if w_mod is not None and space.is_w(w_mod, space.w_None):
                     # if we already find space.w_None, it means that we
-                    # already tried and failed and falled back to the
+                    # already tried and failed and fell back to the
                     # end of this function.
                     w_mod = None
                 else:
@@ -283,10 +283,16 @@
     return w_mod
 
 def absolute_import(space, modulename, baselevel, fromlist_w, tentative):
-    # Short path: check in sys.modules
-    w_mod = absolute_import_try(space, modulename, baselevel, fromlist_w)
-    if w_mod is not None and not space.is_w(w_mod, space.w_None):
-        return w_mod
+    # Short path: check in sys.modules, but only if there is no conflict
+    # on the import lock.  In the situation of 'import' statements
+    # inside tight loops, this should be true, and absolute_import_try()
+    # should be followed by the JIT and turned into not much code.  But
+    # if the import lock is currently held by another thread, then we
+    # have to wait, and so shouldn't use the fast path.
+    if not getimportlock(space).lock_held_by_someone_else():
+        w_mod = absolute_import_try(space, modulename, baselevel, fromlist_w)
+        if w_mod is not None and not space.is_w(w_mod, space.w_None):
+            return w_mod
     return absolute_import_with_lock(space, modulename, baselevel,
                                      fromlist_w, tentative)
 
@@ -741,6 +747,9 @@
         self.lockowner = None
         self.lockcounter = 0
 
+    def lock_held_by_someone_else(self):
+        return self.lockowner is not None and not self.lock_held()
+
     def lock_held(self):
         me = self.space.getexecutioncontext()   # used as thread ident
         return self.lockowner is me
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -1212,3 +1212,45 @@
         "objspace.usepycfiles": True,
         "objspace.lonepycfiles": True
     }
+
+
+class AppTestMultithreadedImp(object):
+    def setup_class(cls):
+        #if not conftest.option.runappdirect:
+        #    py.test.skip("meant as an -A test")
+        cls.space = gettestobjspace(usemodules=['thread', 'time'])
+        tmpfile = udir.join('test_multithreaded_imp.py')
+        tmpfile.write('''if 1:
+            x = 666
+            import time
+            for i in range(1000): time.sleep(0.001)
+            x = 42
+        ''')
+        cls.w_tmppath = cls.space.wrap(str(udir))
+
+    def test_multithreaded_import(self):
+        import sys, thread, time
+        oldpath = sys.path[:]
+        try:
+            sys.path.insert(0, self.tmppath)
+            got = []
+
+            def check():
+                import test_multithreaded_imp
+                got.append(getattr(test_multithreaded_imp, 'x', '?'))
+
+            for i in range(5):
+                thread.start_new_thread(check, ())
+
+            for n in range(100):
+                for i in range(105): time.sleep(0.001)
+                if len(got) == 5:
+                    break
+            else:
+                raise AssertionError("got %r so far but still waiting" %
+                                     (got,))
+
+            assert got == [42] * 5, got
+
+        finally:
+            sys.path[:] = oldpath
diff --git a/pypy/module/pypyjit/test_pypy_c/test__ffi.py b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test__ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test__ffi.py
@@ -1,11 +1,10 @@
-import py
 import sys
 from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
 
 class Test__ffi(BaseTestPyPyC):
 
     def test__ffi_call(self):
-        from pypy.rlib.test.test_libffi import get_libm_name
+        from pypy.rlib.test.test_clibffi import get_libm_name
         def main(libm_name):
             try:
                 from _ffi import CDLL, types
@@ -42,7 +41,7 @@
 
 
     def test__ffi_call_frame_does_not_escape(self):
-        from pypy.rlib.test.test_libffi import get_libm_name
+        from pypy.rlib.test.test_clibffi import get_libm_name
         def main(libm_name):
             try:
                 from _ffi import CDLL, types
@@ -75,15 +74,22 @@
         assert opnames.count('new_with_vtable') == 1
 
     def test__ffi_call_releases_gil(self):
-        from pypy.rlib.test.test_libffi import get_libc_name
+        from pypy.rlib.clibffi import get_libc_name
         def main(libc_name, n):
             import time
+            import os
             from threading import Thread
-            from _ffi import CDLL, types
             #
-            libc = CDLL(libc_name)
-            sleep = libc.getfunc('sleep', [types.uint], types.uint)
-            delays = [0]*n + [1]
+            if os.name == 'nt':
+                from _ffi import WinDLL, types
+                libc = WinDLL('Kernel32.dll')
+                sleep = libc.getfunc('Sleep', [types.uint], types.uint)
+                delays = [0]*n + [1000]
+            else:
+                from _ffi import CDLL, types
+                libc = CDLL(libc_name)
+                sleep = libc.getfunc('sleep', [types.uint], types.uint)
+                delays = [0]*n + [1]
             #
             def loop_of_sleeps(i, delays):
                 for delay in delays:
@@ -97,7 +103,6 @@
                 thread.join()
             end = time.time()
             return end - start
-        #
         log = self.run(main, [get_libc_name(), 200], threshold=150,
                        import_site=True)
         assert 1 <= log.result <= 1.5 # at most 0.5 seconds of overhead
@@ -106,7 +111,7 @@
 
 
     def test_ctypes_call(self):
-        from pypy.rlib.test.test_libffi import get_libm_name
+        from pypy.rlib.test.test_clibffi import get_libm_name
         def main(libm_name):
             import ctypes
             libm = ctypes.CDLL(libm_name)
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -1221,41 +1221,29 @@
         i += 1
     return space.w_True
 
-def lessthan_unwrappeditems(space, w_list1, w_list2):
-    # needs to be safe against eq_w() mutating the w_lists behind our back
-    # Search for the first index where items are different
-    i = 0
-    # XXX in theory, this can be implemented more efficiently as well. let's
-    # not care for now
-    while i < w_list1.length() and i < w_list2.length():
-        w_item1 = w_list1.getitem(i)
-        w_item2 = w_list2.getitem(i)
-        if not space.eq_w(w_item1, w_item2):
-            return space.lt(w_item1, w_item2)
-        i += 1
-    # No more items to compare -- compare sizes
-    return space.newbool(w_list1.length() < w_list2.length())
+def _make_list_comparison(name):
+    import operator
+    op = getattr(operator, name)
+    def compare_unwrappeditems(space, w_list1, w_list2):
+        # needs to be safe against eq_w() mutating the w_lists behind our back
+        # Search for the first index where items are different
+        i = 0
+        # XXX in theory, this can be implemented more efficiently as well.
+        # let's not care for now
+        while i < w_list1.length() and i < w_list2.length():
+            w_item1 = w_list1.getitem(i)
+            w_item2 = w_list2.getitem(i)
+            if not space.eq_w(w_item1, w_item2):
+                return getattr(space, name)(w_item1, w_item2)
+            i += 1
+        # No more items to compare -- compare sizes
+        return space.newbool(op(w_list1.length(), w_list2.length()))
+    return func_with_new_name(compare_unwrappeditems, name + '__List_List')
 
-def greaterthan_unwrappeditems(space, w_list1, w_list2):
-    # needs to be safe against eq_w() mutating the w_lists behind our back
-    # Search for the first index where items are different
-    i = 0
-    # XXX in theory, this can be implemented more efficiently as well. let's
-    # not care for now
-    while i < w_list1.length() and i < w_list2.length():
-        w_item1 = w_list1.getitem(i)
-        w_item2 = w_list2.getitem(i)
-        if not space.eq_w(w_item1, w_item2):
-            return space.gt(w_item1, w_item2)
-        i += 1
-    # No more items to compare -- compare sizes
-    return space.newbool(w_list1.length() > w_list2.length())
-
-def lt__List_List(space, w_list1, w_list2):
-    return lessthan_unwrappeditems(space, w_list1, w_list2)
-
-def gt__List_List(space, w_list1, w_list2):
-    return greaterthan_unwrappeditems(space, w_list1, w_list2)
+lt__List_List = _make_list_comparison('lt')
+le__List_List = _make_list_comparison('le')
+gt__List_List = _make_list_comparison('gt')
+ge__List_List = _make_list_comparison('ge')
 
 def delitem__List_ANY(space, w_list, w_idx):
     idx = get_list_index(space, w_idx)
diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -1204,6 +1204,57 @@
             s.update(Sub2(arg))
             assert s == set(base(arg))
 
+    def test_comparison(self):
+        assert ([] <  []) is False
+        assert ([] <= []) is True
+        assert ([] == []) is True
+        assert ([] != []) is False
+        assert ([] >  []) is False
+        assert ([] >= []) is True
+        assert ([5] <  []) is False
+        assert ([5] <= []) is False
+        assert ([5] == []) is False
+        assert ([5] != []) is True
+        assert ([5] >  []) is True
+        assert ([5] >= []) is True
+        assert ([] <  [5]) is True
+        assert ([] <= [5]) is True
+        assert ([] == [5]) is False
+        assert ([] != [5]) is True
+        assert ([] >  [5]) is False
+        assert ([] >= [5]) is False
+        assert ([4] <  [5]) is True
+        assert ([4] <= [5]) is True
+        assert ([4] == [5]) is False
+        assert ([4] != [5]) is True
+        assert ([4] >  [5]) is False
+        assert ([4] >= [5]) is False
+        assert ([5] <  [5]) is False
+        assert ([5] <= [5]) is True
+        assert ([5] == [5]) is True
+        assert ([5] != [5]) is False
+        assert ([5] >  [5]) is False
+        assert ([5] >= [5]) is True
+        assert ([6] <  [5]) is False
+        assert ([6] <= [5]) is False
+        assert ([6] == [5]) is False
+        assert ([6] != [5]) is True
+        assert ([6] >  [5]) is True
+        assert ([6] >= [5]) is True
+        N = float('nan')
+        assert ([N] <  [5]) is False
+        assert ([N] <= [5]) is False
+        assert ([N] == [5]) is False
+        assert ([N] != [5]) is True
+        assert ([N] >  [5]) is False
+        assert ([N] >= [5]) is False
+        assert ([5] <  [N]) is False
+        assert ([5] <= [N]) is False
+        assert ([5] == [N]) is False
+        assert ([5] != [N]) is True
+        assert ([5] >  [N]) is False
+        assert ([5] >= [N]) is False
+
 class AppTestForRangeLists(AppTestW_ListObject):
 
     def setup_class(cls):
diff --git a/pypy/objspace/std/test/test_tupleobject.py b/pypy/objspace/std/test/test_tupleobject.py
--- a/pypy/objspace/std/test/test_tupleobject.py
+++ b/pypy/objspace/std/test/test_tupleobject.py
@@ -348,3 +348,54 @@
         assert (4, 2, 3, 4).index(4, 1) == 3
         assert (4, 4, 4).index(4, 1, 2) == 1
         raises(ValueError, (1, 2, 3, 4).index, 4, 0, 2)
+
+    def test_comparison(self):
+        assert (() <  ()) is False
+        assert (() <= ()) is True
+        assert (() == ()) is True
+        assert (() != ()) is False
+        assert (() >  ()) is False
+        assert (() >= ()) is True
+        assert ((5,) <  ()) is False
+        assert ((5,) <= ()) is False
+        assert ((5,) == ()) is False
+        assert ((5,) != ()) is True
+        assert ((5,) >  ()) is True
+        assert ((5,) >= ()) is True
+        assert (() <  (5,)) is True
+        assert (() <= (5,)) is True
+        assert (() == (5,)) is False
+        assert (() != (5,)) is True
+        assert (() >  (5,)) is False
+        assert (() >= (5,)) is False
+        assert ((4,) <  (5,)) is True
+        assert ((4,) <= (5,)) is True
+        assert ((4,) == (5,)) is False
+        assert ((4,) != (5,)) is True
+        assert ((4,) >  (5,)) is False
+        assert ((4,) >= (5,)) is False
+        assert ((5,) <  (5,)) is False
+        assert ((5,) <= (5,)) is True
+        assert ((5,) == (5,)) is True
+        assert ((5,) != (5,)) is False
+        assert ((5,) >  (5,)) is False
+        assert ((5,) >= (5,)) is True
+        assert ((6,) <  (5,)) is False
+        assert ((6,) <= (5,)) is False
+        assert ((6,) == (5,)) is False
+        assert ((6,) != (5,)) is True
+        assert ((6,) >  (5,)) is True
+        assert ((6,) >= (5,)) is True
+        N = float('nan')
+        assert ((N,) <  (5,)) is False
+        assert ((N,) <= (5,)) is False
+        assert ((N,) == (5,)) is False
+        assert ((N,) != (5,)) is True
+        assert ((N,) >  (5,)) is False
+        assert ((N,) >= (5,)) is False
+        assert ((5,) <  (N,)) is False
+        assert ((5,) <= (N,)) is False
+        assert ((5,) == (N,)) is False
+        assert ((5,) != (N,)) is True
+        assert ((5,) >  (N,)) is False
+        assert ((5,) >= (N,)) is False
diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py
--- a/pypy/objspace/std/tupleobject.py
+++ b/pypy/objspace/std/tupleobject.py
@@ -8,6 +8,7 @@
 from pypy.objspace.std import slicetype
 from pypy.rlib.debug import make_sure_not_resized
 from pypy.rlib import jit
+from pypy.tool.sourcetools import func_with_new_name
 
 # Tuples of known length up to UNROLL_TUPLE_LIMIT have unrolled certain methods
 UNROLL_TUPLE_LIMIT = 10
@@ -138,29 +139,27 @@
             return space.w_False
     return space.w_True
 
- at jit.look_inside_iff(tuple_unroll_condition)
-def lt__Tuple_Tuple(space, w_tuple1, w_tuple2):
-    items1 = w_tuple1.wrappeditems
-    items2 = w_tuple2.wrappeditems
-    ncmp = min(len(items1), len(items2))
-    # Search for the first index where items are different
-    for p in range(ncmp):
-        if not space.eq_w(items1[p], items2[p]):
-            return space.lt(items1[p], items2[p])
-    # No more items to compare -- compare sizes
-    return space.newbool(len(items1) < len(items2))
+def _make_tuple_comparison(name):
+    import operator
+    op = getattr(operator, name)
+    #
+    @jit.look_inside_iff(tuple_unroll_condition)
+    def compare_tuples(space, w_tuple1, w_tuple2):
+        items1 = w_tuple1.wrappeditems
+        items2 = w_tuple2.wrappeditems
+        ncmp = min(len(items1), len(items2))
+        # Search for the first index where items are different
+        for p in range(ncmp):
+            if not space.eq_w(items1[p], items2[p]):
+                return getattr(space, name)(items1[p], items2[p])
+        # No more items to compare -- compare sizes
+        return space.newbool(op(len(items1), len(items2)))
+    return func_with_new_name(compare_tuples, name + '__Tuple_Tuple')
 
- at jit.look_inside_iff(tuple_unroll_condition)
-def gt__Tuple_Tuple(space, w_tuple1, w_tuple2):
-    items1 = w_tuple1.wrappeditems
-    items2 = w_tuple2.wrappeditems
-    ncmp = min(len(items1), len(items2))
-    # Search for the first index where items are different
-    for p in range(ncmp):
-        if not space.eq_w(items1[p], items2[p]):
-            return space.gt(items1[p], items2[p])
-    # No more items to compare -- compare sizes
-    return space.newbool(len(items1) > len(items2))
+lt__Tuple_Tuple = _make_tuple_comparison('lt')
+le__Tuple_Tuple = _make_tuple_comparison('le')
+gt__Tuple_Tuple = _make_tuple_comparison('gt')
+ge__Tuple_Tuple = _make_tuple_comparison('ge')
 
 def repr__Tuple(space, w_tuple):
     items = w_tuple.wrappeditems
diff --git a/pypy/rlib/libffi.py b/pypy/rlib/libffi.py
--- a/pypy/rlib/libffi.py
+++ b/pypy/rlib/libffi.py
@@ -1,15 +1,17 @@
 from __future__ import with_statement
 
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.rlib.objectmodel import specialize, enforceargs, we_are_translated
+from pypy.rlib.objectmodel import specialize, enforceargs
 from pypy.rlib.rarithmetic import intmask, r_uint, r_singlefloat, r_longlong
 from pypy.rlib import jit
 from pypy.rlib import clibffi
-from pypy.rlib.clibffi import get_libc_name, FUNCFLAG_CDECL, AbstractFuncPtr, \
-    push_arg_as_ffiptr, c_ffi_call, FFI_TYPE_STRUCT
+from pypy.rlib.clibffi import FUNCFLAG_CDECL, FUNCFLAG_STDCALL, \
+        AbstractFuncPtr, push_arg_as_ffiptr, c_ffi_call, FFI_TYPE_STRUCT
 from pypy.rlib.rdynload import dlopen, dlclose, dlsym, dlsym_byordinal
 from pypy.rlib.rdynload import DLLHANDLE
 
+import os
+
 class types(object):
     """
     This namespace contains the primitive types you can use to declare the
@@ -374,7 +376,7 @@
         else:
             res = None
         self._free_buffers(ll_result, ll_args)
-        #check_fficall_result(ffires, self.flags)
+        clibffi.check_fficall_result(ffires, self.flags)
         return res
 
     def _free_buffers(self, ll_result, ll_args):
@@ -416,6 +418,11 @@
     def getaddressindll(self, name):
         return dlsym(self.lib, name)
 
+if os.name == 'nt':
+    class WinDLL(CDLL):
+        def getpointer(self, name, argtypes, restype, flags=FUNCFLAG_STDCALL):
+            return Func(name, argtypes, restype, dlsym(self.lib, name),
+                        flags=flags, keepalive=self)
 # ======================================================================
 
 @jit.oopspec('libffi_struct_getfield(ffitype, addr, offset)')
diff --git a/pypy/rlib/rwin32.py b/pypy/rlib/rwin32.py
--- a/pypy/rlib/rwin32.py
+++ b/pypy/rlib/rwin32.py
@@ -367,6 +367,14 @@
         'GetCurrentProcessId', [], DWORD)
     def GetCurrentProcessId():
         return rffi.cast(lltype.Signed, _GetCurrentProcessId())
+
+    _GetConsoleCP = winexternal('GetConsoleCP', [], DWORD)
+    _GetConsoleOutputCP = winexternal('GetConsoleOutputCP', [], DWORD)
+    def GetConsoleCP():
+        return rffi.cast(lltype.Signed, _GetConsoleCP())
+    def GetConsoleOutputCP():
+        return rffi.cast(lltype.Signed, _GetConsoleOutputCP())
+
     def os_kill(pid, sig):
         if sig == CTRL_C_EVENT or sig == CTRL_BREAK_EVENT:
             if GenerateConsoleCtrlEvent(sig, pid) == 0:
diff --git a/pypy/rlib/test/test_libffi.py b/pypy/rlib/test/test_libffi.py
--- a/pypy/rlib/test/test_libffi.py
+++ b/pypy/rlib/test/test_libffi.py
@@ -1,12 +1,13 @@
-import sys
+import os
 
 import py
 
 from pypy.rlib.rarithmetic import r_singlefloat, r_longlong, r_ulonglong
-from pypy.rlib.test.test_clibffi import BaseFfiTest, get_libm_name, make_struct_ffitype_e
+from pypy.rlib.test.test_clibffi import BaseFfiTest, make_struct_ffitype_e
 from pypy.rpython.lltypesystem import rffi, lltype
 from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED
-from pypy.rlib.libffi import (CDLL, Func, get_libc_name, ArgChain, types,
+from pypy.rpython.llinterp import LLException
+from pypy.rlib.libffi import (CDLL, ArgChain, types,
                               IS_32_BIT, array_getitem, array_setitem)
 from pypy.rlib.libffi import (struct_getfield_int, struct_setfield_int,
                               struct_getfield_longlong, struct_setfield_longlong,
@@ -175,6 +176,15 @@
         #
         lltype.free(p, flavor='raw')
 
+    def test_windll(self):
+        if os.name != 'nt':
+            skip('Run only on windows')
+        from pypy.rlib.libffi import WinDLL
+        dll = WinDLL('Kernel32.dll')
+        sleep = dll.getpointer('Sleep',[types.uint], types.void)
+        chain = ArgChain()
+        chain.arg(10)
+        sleep.call(chain, lltype.Void, is_struct=False)
 
 class TestLibffiCall(BaseFfiTest):
     """
@@ -219,9 +229,16 @@
         eci = ExternalCompilationInfo(export_symbols=exports)
         cls.libfoo_name = str(platform.compile([c_file], eci, 'x',
                                                standalone=False))
+        cls.dll = cls.CDLL(cls.libfoo_name)
+
+    def teardown_class(cls):
+        if cls.dll:
+            cls.dll.__del__()
+            # Why doesn't this call cls.dll.__del__() ?
+            #del cls.dll
 
     def get_libfoo(self):
-        return self.CDLL(self.libfoo_name)
+        return self.dll    
 
     def call(self, funcspec, args, RESULT, is_struct=False, jitif=[]):
         """
@@ -536,4 +553,27 @@
         assert p[1] == 34
         lltype.free(p, flavor='raw')
         lltype.free(ffi_point_struct, flavor='raw')
+
+    if os.name == 'nt':
+        def test_stdcall_simple(self):
+            """
+                int __stdcall std_diff_xy(int x, Signed y)
+                {
+                    return x - y;
+                }
+            """
+            libfoo = self.get_libfoo()
+            func = (libfoo, 'std_diff_xy', [types.sint, types.signed], types.sint)
+            try:
+                self.call(func, [50, 8], lltype.Signed)
+            except ValueError, e:
+                assert e.message == 'Procedure called with not enough ' + \
+                     'arguments (8 bytes missing) or wrong calling convention'
+            except LLException, e:
+                #jitted code raises this
+                assert str(e) == "<LLException 'StackCheckError'>"
+            else:
+                assert 0, 'wrong calling convention should have raised'
+
+
         
diff --git a/pypy/rlib/test/test_rjvm.py b/pypy/rlib/test/test_rjvm.py
--- a/pypy/rlib/test/test_rjvm.py
+++ b/pypy/rlib/test/test_rjvm.py
@@ -1,4 +1,6 @@
 import py
+py.test.skip('this is outdated. Check the jvm-improvements branch')
+
 try:
     import jpype
 except ImportError:
diff --git a/pypy/test_all.py b/pypy/test_all.py
--- a/pypy/test_all.py
+++ b/pypy/test_all.py
@@ -3,9 +3,16 @@
 PyPy Test runner interface
 --------------------------
 
-Running test_all.py is equivalent to running py.test
-which you independently install, see
-http://pytest.org/getting-started.html
+Running pytest.py starts py.test, the testing tool
+we use in PyPy.  It is distributed along with PyPy,
+but you may get more information about it at
+http://pytest.org/.
+
+Note that it makes no sense to run all tests at once.
+You need to pick a particular subdirectory and run
+
+    cd pypy/.../test
+    ../../../pytest.py [options]
 
 For more information, use test_all.py -h.
 """
diff --git a/pypy/translator/c/funcgen.py b/pypy/translator/c/funcgen.py
--- a/pypy/translator/c/funcgen.py
+++ b/pypy/translator/c/funcgen.py
@@ -214,6 +214,10 @@
             myblocknum = self.blocknum[block]
             yield ''
             yield 'block%d:' % myblocknum
+            if block in self.innerloops:
+                for line in self.gen_while_loop_hack(block):
+                    yield line
+                continue
             for i, op in enumerate(block.operations):
                 for line in self.gen_op(op):
                     yield line
@@ -237,9 +241,6 @@
                 assert len(block.exits) == 1
                 for op in self.gen_link(block.exits[0]):
                     yield op
-            elif block in self.innerloops:
-                for line in self.gen_while_loop_hack(block):
-                    yield line
             else:
                 assert block.exitswitch != c_last_exception
                 # block ending in a switch on a value
@@ -342,11 +343,11 @@
         # decision is) we produce code like this:
         #
         #             headblock:
-        #               ...headblock operations...
-        #               while (cond) {
+        #               while (1) {
+        #                   ...headblock operations...
+        #                   if (!cond) break;
         #                   goto firstbodyblock;
-        #                 headblock_back:
-        #                   ...headblock operations...
+        #                 headblock_back: ;
         #               }
         #
         # The real body of the loop is not syntactically within the
@@ -367,19 +368,19 @@
         i = list(headblock.exits).index(enterlink)
         exitlink = headblock.exits[1 - i]
 
+        yield 'while (1) {'
+
+        for i, op in enumerate(headblock.operations):
+            for line in self.gen_op(op):
+                yield '\t' + line
+
         expr = self.expr(headblock.exitswitch)
-        if enterlink.exitcase == False:
+        if enterlink.exitcase == True:
             expr = '!' + expr
-        yield 'while (%s) {' % expr
+        yield '\tif (%s) break;' % expr
         for op in self.gen_link(enterlink):
             yield '\t' + op
-        # the semicolon after the colon is needed in case no operation
-        # produces any code after the label
-        yield '\t  block%d_back: ;' % self.blocknum[headblock]
-        if headblock.operations:
-            for i, op in enumerate(headblock.operations):
-                for line in self.gen_op(op):
-                    yield '\t' + line
+        yield '  block%d_back: ;' % self.blocknum[headblock]
         yield '}'
         for op in self.gen_link(exitlink):
             yield op
diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py
--- a/pypy/translator/c/gcc/trackgcroot.py
+++ b/pypy/translator/c/gcc/trackgcroot.py
@@ -483,8 +483,10 @@
         'inc', 'dec', 'not', 'neg', 'or', 'and', 'sbb', 'adc',
         'shl', 'shr', 'sal', 'sar', 'rol', 'ror', 'mul', 'imul', 'div', 'idiv',
         'bswap', 'bt', 'rdtsc',
-        'punpck', 'pshufd', 'pcmp', 'pand', 'psllw', 'pslld', 'psllq',
-        'paddq', 'pinsr', 'pmul', 'psrl',
+        'pabs', 'pack', 'padd', 'palign', 'pand', 'pavg', 'pcmp', 'pextr',
+        'phadd', 'phsub', 'pinsr', 'pmadd', 'pmax', 'pmin', 'pmovmsk',
+        'pmul', 'por', 'psadb', 'pshuf', 'psign', 'psll', 'psra', 'psrl',
+        'psub', 'punpck', 'pxor',
         # all vectors don't produce pointers
         'v',
         # sign-extending moves should not produce GC pointers
@@ -492,7 +494,7 @@
         # zero-extending moves should not produce GC pointers
         'movz', 
         # locked operations should not move GC pointers, at least so far
-        'lock',
+        'lock', 'pause',
         ])
 
     # a partial list is hopefully good enough for now; it's all to support
diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py
--- a/pypy/translator/goal/app_main.py
+++ b/pypy/translator/goal/app_main.py
@@ -288,7 +288,7 @@
             sys.path.append(dir)
             _seen[dir] = True
 
-def set_io_encoding(io_encoding):
+def set_io_encoding(io_encoding, io_encoding_output, errors, overridden):
     try:
         import _file
     except ImportError:
@@ -299,12 +299,11 @@
         set_file_encoding.argtypes = [ctypes.py_object, ctypes.c_char_p, ctypes.c_char_p]
     else:
         set_file_encoding = _file.set_file_encoding
-    if ":" in io_encoding:
-        encoding, errors = io_encoding.split(":", 1)
-    else:
-        encoding, errors = io_encoding, None
-    for f in [sys.stdin, sys.stdout, sys.stderr]:
-        set_file_encoding(f, encoding, errors)
+    for f, encoding in [(sys.stdin, io_encoding),
+                        (sys.stdout, io_encoding_output),
+                        (sys.stderr, io_encoding_output)]:
+        if isinstance(f, file) and (overridden or f.isatty()):
+            set_file_encoding(f, encoding, errors)
 
 # Order is significant!
 sys_flags = (
@@ -458,13 +457,13 @@
 
     if PYTHON26 and not options["ignore_environment"]:
         if os.getenv('PYTHONNOUSERSITE'):
-            options["no_user_site"] = True
+            options["no_user_site"] = 1
         if os.getenv('PYTHONDONTWRITEBYTECODE'):
-            options["dont_write_bytecode"] = True
+            options["dont_write_bytecode"] = 1
 
     if (options["interactive"] or
         (not options["ignore_environment"] and os.getenv('PYTHONINSPECT'))):
-        options["inspect"] = True
+        options["inspect"] = 1
 
     if PYTHON26 and we_are_translated():
         flags = [options[flag] for flag in sys_flags]
@@ -513,10 +512,20 @@
             print >> sys.stderr, "'import site' failed"
 
     readenv = not ignore_environment
-    io_encoding = ((readenv and os.getenv("PYTHONIOENCODING"))
-                   or sys.getfilesystemencoding())
+    io_encoding = readenv and os.getenv("PYTHONIOENCODING")
     if io_encoding:
-        set_io_encoding(io_encoding)
+        errors = None
+        if ":" in io_encoding:
+            io_encoding, errors = io_encoding.split(":", 1)
+        set_io_encoding(io_encoding, io_encoding, errors, True)
+    else:
+        if IS_WINDOWS:
+            import __pypy__
+            io_encoding, io_encoding_output = __pypy__.get_console_cp()
+        else:
+            io_encoding = io_encoding_output = sys.getfilesystemencoding()
+        if io_encoding:
+            set_io_encoding(io_encoding, io_encoding_output, None, False)
 
     pythonwarnings = readenv and os.getenv('PYTHONWARNINGS')
     if pythonwarnings:
diff --git a/pytest.py b/pytest.py
--- a/pytest.py
+++ b/pytest.py
@@ -1,6 +1,20 @@
 #!/usr/bin/env python
 """
-unit and functional testing with Python.
+PyPy Test runner interface
+--------------------------
+
+Running pytest.py starts py.test, the testing tool
+we use in PyPy.  It is distributed along with PyPy,
+but you may get more information about it at
+http://pytest.org/.
+
+Note that it makes no sense to run all tests at once.
+You need to pick a particular subdirectory and run
+
+    cd pypy/.../test
+    ../../../pytest.py [options]
+
+For more information, use pytest.py -h.
 """
 __all__ = ['main']
 
@@ -23,6 +37,11 @@
 from _pytest import __version__
 
 if __name__ == '__main__': # if run as a script or by 'python -m pytest'
+    import os
+    if len(sys.argv) == 1 and os.path.dirname(sys.argv[0]) in '.':
+        print >> sys.stderr, __doc__
+        sys.exit(2)
+
     #XXX: sync to upstream later
     import pytest_cov
     raise SystemExit(main(plugins=[pytest_cov]))


More information about the pypy-commit mailing list