Commits

Tyler Wade committed 317c58d Merge

Merge pypy/pypy default

Comments (0)

Files changed (150)

lib-python/2.7/distutils/sysconfig.py

-"""Provide access to Python's configuration information.  The specific
-configuration variables available depend heavily on the platform and
-configuration.  The values may be retrieved using
-get_config_var(name), and the list of variables is available via
-get_config_vars().keys().  Additional convenience functions are also
-available.
-
-Written by:   Fred L. Drake, Jr.
-Email:        <fdrake@acm.org>
-"""
-
-__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $"
-
-import sys
-
 
 # The content of this file is redirected from
 # sysconfig_cpython or sysconfig_pypy.
+# All underscore names are imported too, because
+# people like to use undocumented sysconfig._xxx
+# directly.
 
+import sys
 if '__pypy__' in sys.builtin_module_names:
-    from distutils.sysconfig_pypy import *
-    from distutils.sysconfig_pypy import _config_vars # needed by setuptools
-    from distutils.sysconfig_pypy import _variable_rx # read_setup_file()
+    from distutils import sysconfig_pypy as _sysconfig_module
 else:
-    from distutils.sysconfig_cpython import *
-    from distutils.sysconfig_cpython import _config_vars # needed by setuptools
-    from distutils.sysconfig_cpython import _variable_rx # read_setup_file()
+    from distutils import sysconfig_cpython as _sysconfig_module
+globals().update(_sysconfig_module.__dict__)
 
 _USE_CLANG = None
 

lib-python/2.7/distutils/sysconfig_cpython.py

 Email:        <fdrake@acm.org>
 """
 
-__revision__ = "$Id$"
+__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $"
 
 import os
 import re

lib-python/2.7/distutils/sysconfig_pypy.py

-"""PyPy's minimal configuration information.
+"""Provide access to Python's configuration information.
+This is actually PyPy's minimal configuration information.
+
+The specific configuration variables available depend heavily on the
+platform and configuration.  The values may be retrieved using
+get_config_var(name), and the list of variables is available via
+get_config_vars().keys().  Additional convenience functions are also
+available.
 """
 
+__revision__ = "$Id: sysconfig.py 85358 2010-10-10 09:54:59Z antoine.pitrou $"
+
 import sys
 import os
 import imp
     optional C speedup components.
     """
     if compiler.compiler_type == "unix":
-        compiler.compiler_so.extend(['-fPIC', '-Wimplicit'])
+        compiler.compiler_so.extend(['-O2', '-fPIC', '-Wimplicit'])
         compiler.shared_lib_extension = get_config_var('SO')
         if "CFLAGS" in os.environ:
             cflags = os.environ["CFLAGS"].split()

lib-python/2.7/socket.py

                 if self._close:
                     self._sock.close()
                 else:
-                    self._sock._decref_socketios()
+                    try:
+                        self._sock._decref_socketios()
+                    except AttributeError:
+                        pass  # bah, someone built a _fileobject manually
+                              # with some unexpected replacement of the
+                              # _socketobject class
             self._sock = None
 
     def __del__(self):

lib-python/2.7/test/test_codecs.py

 import unittest
 import codecs
 import locale
-import sys, StringIO, _testcapi
+import sys, StringIO
+try:
+    import _testcapi
+except ImportError:
+    _testcapi = None
 
 class Queue(object):
     """
                     decodedresult += reader.read()
                 self.assertEqual(decodedresult, s, "%r != %r (encoding=%r)" % (decodedresult, s, encoding))
 
-            if encoding not in broken_incremental_coders:
+            if encoding not in broken_incremental_coders and _testcapi:
                 # check incremental decoder/encoder (fetched via the Python
                 # and C API) and iterencode()/iterdecode()
                 try:

lib-python/2.7/test/test_descr.py

File contents unchanged.

lib-python/2.7/test/test_sysconfig.py

 import subprocess
 from copy import copy, deepcopy
 
-from test.test_support import run_unittest, TESTFN, unlink, get_attribute
+from test.test_support import (run_unittest, TESTFN, unlink, get_attribute,
+                               import_module)
 
 import sysconfig
 from sysconfig import (get_paths, get_platform, get_config_vars,
 
     def test_get_config_h_filename(self):
         config_h = sysconfig.get_config_h_filename()
-        self.assertTrue(os.path.isfile(config_h), config_h)
+        # import_module skips the test when the CPython C Extension API
+        # appears to not be supported
+        self.assertTrue(os.path.isfile(config_h) or
+                        not import_module('_testcapi'), config_h)
 
     def test_get_scheme_names(self):
         wanted = ('nt', 'nt_user', 'os2', 'os2_home', 'osx_framework_user',

lib-python/2.7/test/test_traceback.py

 """Test cases for traceback module"""
 
-from _testcapi import traceback_print
+try:
+    from _testcapi import traceback_print
+except ImportError:
+    traceback_print = None
 from StringIO import StringIO
 import sys
 import unittest
 class TracebackFormatTests(unittest.TestCase):
 
     def test_traceback_format(self):
+        if traceback_print is None:
+            raise unittest.SkipTest('Requires _testcapi')
         try:
             raise KeyError('blah')
         except KeyError:

lib-python/2.7/test/test_unicode.py

         self.assertEqual("{}".format(u), '__unicode__ overridden')
 
     def test_encode_decimal(self):
-        from _testcapi import unicode_encodedecimal
+        try:
+            from _testcapi import unicode_encodedecimal
+        except ImportError:
+            raise unittest.SkipTest('Requires _testcapi')
         self.assertEqual(unicode_encodedecimal(u'123'),
                          b'123')
         self.assertEqual(unicode_encodedecimal(u'\u0663.\u0661\u0664'),

lib-python/conftest.py

     RegrTest('test_bz2.py', usemodules='bz2'),
     RegrTest('test_calendar.py'),
     RegrTest('test_call.py', core=True),
-    RegrTest('test_capi.py'),
+    RegrTest('test_capi.py', usemodules='cpyext'),
     RegrTest('test_cd.py'),
     RegrTest('test_cfgparser.py'),
     RegrTest('test_cgi.py'),
     RegrTest('test_cprofile.py'),
     RegrTest('test_crypt.py', usemodules='crypt'),
     RegrTest('test_csv.py', usemodules='_csv'),
-    RegrTest('test_ctypes.py', usemodules="_rawffi thread"),
+    RegrTest('test_ctypes.py', usemodules="_rawffi thread cpyext"),
     RegrTest('test_curses.py'),
     RegrTest('test_datetime.py', usemodules='binascii struct'),
     RegrTest('test_dbm.py'),

lib_pypy/_testcapi.py

     fp, filename, description = imp.find_module('_testcapi', path=[output_dir])
     imp.load_module('_testcapi', fp, filename, description)
 
-compile_shared()
+try:
+    import cpyext
+except ImportError:
+    raise ImportError("No module named '_testcapi'")
+else:
+    compile_shared()

pypy/config/pypyoption.py

      "rctime" , "select", "zipimport", "_lsprof",
      "crypt", "signal", "_rawffi", "termios", "zlib", "bz2",
      "struct", "_hashlib", "_md5", "_sha", "_minimal_curses", "cStringIO",
-     "thread", "itertools", "pyexpat", "_ssl", "cpyext", "array",
+     "thread", "itertools", "pyexpat", "_ssl", "array",
      "binascii", "_multiprocessing", '_warnings',
      "_collections", "_multibytecodec", "micronumpy", "_ffi",
-     "_continuation", "_cffi_backend", "_csv", "cppyy"]
+     "_continuation", "_cffi_backend", "_csv"] # "cpyext", "cppyy"]
+# disabled until problems are fixed
 ))
 
 translation_modules = default_modules.copy()
                     __import__(name)
             except (ImportError, CompilationError, py.test.skip.Exception), e:
                 errcls = e.__class__.__name__
-                config.add_warning(
+                raise Exception(
                     "The module %r is disabled\n" % (modname,) +
                     "because importing %s raised %s\n" % (name, errcls) +
                     str(e))
-                raise ConflictConfigError("--withmod-%s: %s" % (modname,
-                                                                errcls))
         return validator
     else:
         return None
     # ignore names from 'essential_modules', notably 'exceptions', which
     # may not be present in config.objspace.usemodules at all
     modules = [name for name in modules if name not in essential_modules]
+
     config.objspace.usemodules.suggest(**dict.fromkeys(modules, True))
 
 def enable_translationmodules(config):

pypy/doc/coding-guide.rst

 
 + methods and other class attributes do not change after startup
 + single inheritance is fully supported
-+ simple mixins work too, but the mixed in class needs a ``_mixin_ = True``
-  class attribute
++ simple mixins somewhat work too, but the mixed in class needs a
+  ``_mixin_ = True`` class attribute. isinstance checks against the
+  mixin type will fail when translated.
 
 + classes are first-class objects too
 
 # The short X.Y version.
 version = '2.0'
 # The full version, including alpha/beta/rc tags.
-release = '2.0.0'
+release = '2.0.2'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.

pypy/doc/how-to-contribute.rst

 Layers
 ------
 
-PyPy has layers. Those layers help us keep the respective parts separated enough
+PyPy has layers. Just like Ogres or onions.
+Those layers help us keep the respective parts separated enough
 to be worked on independently and make the complexity manageable. This is,
 again, just a sanity requirement for such a complex project. For example writing
 a new optimization for the JIT usually does **not** involve touching a Python

pypy/doc/how-to-release.rst

   will capture the revision number of this change for the release;
   some of the next updates may be done before or after branching; make
   sure things are ported back to the trunk and to the branch as
-  necessary
+  necessary; also update the version number in pypy/doc/conf.py,
+  and in pypy/doc/index.rst
 * update pypy/doc/contributor.rst (and possibly LICENSE)
 * rename pypy/doc/whatsnew_head.rst to whatsnew_VERSION.rst
   and create a fresh whatsnew_head.rst after the release

pypy/doc/index.rst

 
 * `FAQ`_: some frequently asked questions.
 
-* `Release 2.0`_: the latest official release
+* `Release 2.0.2`_: the latest official release
 
 * `PyPy Blog`_: news and status info about PyPy 
 
 .. _`Getting Started`: getting-started.html
 .. _`Papers`: extradoc.html
 .. _`Videos`: video-index.html
-.. _`Release 2.0`: http://pypy.org/download.html
+.. _`Release 2.0.2`: http://pypy.org/download.html
 .. _`speed.pypy.org`: http://speed.pypy.org
 .. _`RPython toolchain`: translation.html
 .. _`potential project ideas`: project-ideas.html

pypy/doc/release-2.0.1.rst

+==============================
+PyPy 2.0.1 - Bohr Smørrebrød
+==============================
+
+We're pleased to announce PyPy 2.0.1.  This is a stable bugfix release
+over `2.0`_.  You can download it here:
+  
+    http://pypy.org/download.html
+
+The fixes are mainly about fatal errors or crashes in our stdlib.  See
+below for more details.
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 64 or
+Windows 32.  Support for ARM is progressing but not bug-free yet.
+
+.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org
+
+Highlights
+==========
+
+- fix an occasional crash in the JIT that ends in `RPython Fatal error:
+  NotImplementedError`__.
+
+- `id(x)` is now always a positive number (except on int/float/long/complex).
+  This fixes an issue in ``_sqlite.py`` (mostly for 32-bit Linux).
+
+- fix crashes of callback-from-C-functions (with cffi) when used together
+  with Stackless features, on asmgcc (i.e. Linux only).  Now `gevent should
+  work better`__.
+
+- work around an eventlet issue with `socket._decref_socketios()`__.
+
+.. __: https://bugs.pypy.org/issue1482
+.. __: http://mail.python.org/pipermail/pypy-dev/2013-May/011362.html
+.. __: https://bugs.pypy.org/issue1468
+.. _2.0: release-2.0.0.html
+
+Cheers,
+arigo et. al. for the PyPy team

pypy/doc/release-2.0.2.rst

+=========================
+PyPy 2.0.2 - Fermi Panini
+=========================
+
+We're pleased to announce PyPy 2.0.2.  This is a stable bugfix release
+over `2.0`_ and `2.0.1`_.  You can download it here:
+
+    http://pypy.org/download.html
+
+It fixes a crash in the JIT when calling external C functions (with
+ctypes/cffi) in a multithreaded context.
+
+.. _2.0: release-2.0.0.html
+.. _2.0.1: release-2.0.1.html
+
+What is PyPy?
+=============
+
+PyPy is a very compliant Python interpreter, almost a drop-in replacement for
+CPython 2.7. It's fast (`pypy 2.0 and cpython 2.7.3`_ performance comparison)
+due to its integrated tracing JIT compiler.
+
+This release supports x86 machines running Linux 32/64, Mac OS X 64 or
+Windows 32.  Support for ARM is progressing but not bug-free yet.
+
+.. _`pypy 2.0 and cpython 2.7.3`: http://speed.pypy.org
+
+Highlights
+==========
+
+This release contains only the fix described above.  A crash (or wrong
+results) used to occur if all these conditions were true:
+
+- your program is multithreaded;
+
+- it runs on a single-core machine or a heavily-loaded multi-core one;
+
+- it uses ctypes or cffi to issue external calls to C functions.
+
+This was fixed in the branch `emit-call-x86`__ (see the example file
+``bug1.py``).
+
+.. __: https://bitbucket.org/pypy/pypy/commits/7c80121abbf4
+
+Cheers,
+arigo et. al. for the PyPy team

pypy/doc/test/test_whatsnew.py

     branches.discard('default')
     return startrev, branches
 
-def get_merged_branches(path, startrev, endrev):
-    if getstatusoutput('hg root')[0]:
+def get_merged_branches(path, startrev, endrev, current_branch=None):
+    errcode, wc_branch = getstatusoutput('hg branch')
+    if errcode != 0:
         py.test.skip('no Mercurial repo')
+    if current_branch is None:
+        current_branch = wc_branch
 
     # X = take all the merges which are descendants of startrev and are on default
     # revset = all the parents of X which are not on default
     # ===>
     # revset contains all the branches which have been merged to default since
     # startrev
-    revset = 'parents(%s::%s and \
+    revset = "parents(%s::%s and \
                       merge() and \
-                      branch(default)) and \
-              not branch(default)' % (startrev, endrev)
+                      branch('%s')) and \
+              not branch('%s')" % (startrev, endrev,
+                                   current_branch, current_branch)
     cmd = r'hg log -R "%s" -r "%s" --template "{branches}\n"' % (path, revset)
     out = getoutput(cmd)
     branches = set(map(str.strip, out.splitlines()))
-    return branches
+    branches.discard("default")
+    return branches, current_branch
 
 
 def test_parse_doc():
     assert branches == set(['foobar', 'hello'])
 
 def test_get_merged_branches():
-    branches = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93')
+    branches, _ = get_merged_branches(ROOT, 'f34f0c11299f', '79770e0c2f93',
+                                      'default')
     assert branches == set(['numpy-indexing-by-arrays-bool',
                             'better-jit-hooks-2',
                             'numpypy-ufuncs'])
     whatsnew_list.sort()
     last_whatsnew = whatsnew_list[-1].read()
     startrev, documented = parse_doc(last_whatsnew)
-    merged = get_merged_branches(ROOT, startrev, '')
+    merged, branch = get_merged_branches(ROOT, startrev, '')
+    merged.discard('default')
+    merged.discard('')
     not_documented = merged.difference(documented)
     not_merged = documented.difference(merged)
     print 'Branches merged but not documented:'
     print 'Branches documented but not merged:'
     print '\n'.join(not_merged)
     print
-    assert not not_documented and not not_merged
+    assert not not_documented
+    if branch == 'default':
+        assert not not_merged

pypy/doc/whatsnew-head.rst

 
 .. branch: numpy-pickle
 Pickling of numpy arrays and dtypes (including record dtypes)
+
+.. branch: remove-array-smm
+Remove multimethods in the arraymodule
+
+.. branch: callback-stacklet
+Fixed bug when switching stacklets from a C callback
+
+.. branch: remove-set-smm
+Remove multi-methods on sets
+
+.. branch: numpy-subarrays
+Implement subarrays for numpy
+
+.. branch: remove-dict-smm
+Remove multi-methods on dict
+
+.. branch: remove-list-smm-2
+Remove remaining multi-methods on list
+
+.. branch: arm-stacklet
+Stacklet support for ARM, enables _continuation support

pypy/goal/getnightly.py

     arch = 'linux'
     cmd = 'wget "%s"'
     tar = "tar -x -v --wildcards --strip-components=2 -f %s '*/bin/pypy'"
-if sys.platform.startswith('darwin'):
+    if os.uname()[-1].startswith('arm'):
+        arch += '-armhf-raspbian'
+elif sys.platform.startswith('darwin'):
     arch = 'osx'
     cmd = 'curl -O "%s"'
     tar = "tar -x -v --strip-components=2 -f %s '*/bin/pypy'"

pypy/goal/targetpypystandalone.py

 
 import os, sys
 
+import pypy
 from pypy.interpreter import gateway
 from pypy.interpreter.error import OperationError
 from pypy.tool.ann_override import PyPyAnnotatorPolicy
 from rpython.config.config import ConflictConfigError
 from pypy.tool.option import make_objspace
 from pypy.conftest import pypydir
+from rpython.rlib import rthread
+from pypy.module.thread import os_thread
 
 thisdir = py.path.local(__file__).dirpath()
 
     # should be used as sparsely as possible, just to register callbacks
 
     from rpython.rlib.entrypoint import entrypoint
-    from rpython.rtyper.lltypesystem import rffi
+    from rpython.rtyper.lltypesystem import rffi, lltype
+
+    w_pathsetter = space.appexec([], """():
+    def f(path):
+        import sys
+        sys.path[:] = path
+    return f
+    """)
+
+    @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_setup_home')
+    def pypy_setup_home(ll_home, verbose):
+        from pypy.module.sys.initpath import pypy_find_stdlib
+        if ll_home:
+            home = rffi.charp2str(ll_home)
+        else:
+            home = pypydir
+        w_path = pypy_find_stdlib(space, home)
+        if space.is_none(w_path):
+            if verbose:
+                debug("Failed to find library based on pypy_find_stdlib")
+            return 1
+        space.startup()
+        space.call_function(w_pathsetter, w_path)
+        # import site
+        try:
+            import_ = space.getattr(space.getbuiltinmodule('__builtin__'),
+                                    space.wrap('__import__'))
+            space.call_function(import_, space.wrap('site'))
+            return 0
+        except OperationError, e:
+            if verbose:
+                debug("OperationError:")
+                debug(" operror-type: " + e.w_type.getname(space))
+                debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space))))
+            return 1
 
     @entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source')
     def pypy_execute_source(ll_source):
         source = rffi.charp2str(ll_source)
         return _pypy_execute_source(source)
 
+    @entrypoint('main', [], c_name='pypy_init_threads')
+    def pypy_init_threads():
+        if space.config.objspace.usemodules.thread:
+            os_thread.setup_threads(space)
+            rffi.aroundstate.before()
+
+    @entrypoint('main', [], c_name='pypy_thread_attach')
+    def pypy_thread_attach():
+        if space.config.objspace.usemodules.thread:
+            rthread.gc_thread_start()
+
     w_globals = space.newdict()
     space.setitem(w_globals, space.wrap('__builtins__'),
                   space.builtin_modules['__builtin__'])
             return 1
         return 0
 
-    return entry_point, _pypy_execute_source # for tests
+    return entry_point, {'pypy_execute_source': pypy_execute_source,
+                         'pypy_init_threads': pypy_init_threads,
+                         'pypy_thread_attach': pypy_thread_attach,
+                         'pypy_setup_home': pypy_setup_home}
 
 def call_finish(space):
     space.finish()

pypy/interpreter/astcompiler/codegen.py

             self.emit_jump(ops.JUMP_IF_FALSE_OR_POP, cleanup, True)
             if i < (ops_count - 1):
                 comp.comparators[i].walkabout(self)
-        comp.comparators[-1].walkabout(self)
-        last_kind = compare_operations(comp.ops[-1])
-        self.emit_op_arg(ops.COMPARE_OP, last_kind)
+        last_op, last_comparator = comp.ops[-1], comp.comparators[-1]
+        if not self._optimize_comparator(last_op, last_comparator):
+            last_comparator.walkabout(self)
+        self.emit_op_arg(ops.COMPARE_OP, compare_operations(last_op))
         if ops_count > 1:
             end = self.new_block()
             self.emit_jump(ops.JUMP_FORWARD, end)
             self.emit_op(ops.POP_TOP)
             self.use_next_block(end)
 
+    def _optimize_comparator(self, op, node):
+        """Fold lists/sets of constants in the context of "in"/"not in".
+
+        lists are folded into tuples, sets into frozensets, otherwise
+        returns False
+        """
+        if op in (ast.In, ast.NotIn):
+            is_list = isinstance(node, ast.List)
+            if is_list or isinstance(node, ast.Set):
+                w_const = self._tuple_of_consts(node.elts)
+                if w_const is not None:
+                    if not is_list:
+                        from pypy.objspace.std.setobject import (
+                            W_FrozensetObject)
+                        w_const = W_FrozensetObject(self.space, w_const)
+                    self.load_const(w_const)
+                    return True
+        return False
+
+    def _tuple_of_consts(self, elts):
+        """Return a tuple of consts from elts if possible, or None"""
+        count = len(elts) if elts is not None else 0
+        consts_w = [None] * count
+        for i in range(count):
+            w_value = elts[i].as_constant()
+            if w_value is None:
+                # Not all constants
+                return None
+            consts_w[i] = w_value
+        return self.space.newtuple(consts_w)
+
     def visit_IfExp(self, ifexp):
         self.update_position(ifexp.lineno)
         end = self.new_block()

pypy/interpreter/astcompiler/test/test_compiler.py

         counts = self.count_instructions(source3)
         assert counts[ops.BUILD_LIST] == 1
         assert ops.BUILD_LIST_FROM_ARG not in counts
+
+    def test_folding_of_list_constants(self):
+        for source in (
+            # in/not in constants with BUILD_LIST should be folded to a tuple:
+            'a in [1,2,3]',
+            'a not in ["a","b","c"]',
+            'a in [None, 1, None]',
+            'a not in [(1, 2), 3, 4]',
+            ):
+            source = 'def f(): %s' % source
+            counts = self.count_instructions(source)
+            assert ops.BUILD_LIST not in counts
+            assert ops.LOAD_CONST in counts
+
+    def test_folding_of_set_constants(self):
+        for source in (
+            # in/not in constants with BUILD_SET should be folded to a frozenset:
+            'a in {1,2,3}',
+            'a not in {"a","b","c"}',
+            'a in {None, 1, None}',
+            'a not in {(1, 2), 3, 4}',
+            'a in {1, 2, 3, 3, 2, 1}',
+            ):
+            source = 'def f(): %s' % source
+            counts = self.count_instructions(source)
+            assert ops.BUILD_SET not in counts
+            assert ops.LOAD_CONST in counts

pypy/interpreter/baseobjspace.py

     def __spacebind__(self, space):
         return self
 
+    def unwrap(self, space):
+        """NOT_RPYTHON"""
+        # _____ this code is here to support testing only _____
+        return self
+
 
 class W_InterpIterable(W_Root):
     def __init__(self, space, w_iterable):
     def id(self, w_obj):
         w_result = w_obj.immutable_unique_id(self)
         if w_result is None:
-            w_result = self.wrap(compute_unique_id(w_obj))
+            # in the common case, returns an unsigned value
+            w_result = self.wrap(r_uint(compute_unique_id(w_obj)))
         return w_result
 
     def hash_w(self, w_obj):

pypy/interpreter/gateway.py

     args = inspect.getargs(func.func_code)
     if args.varargs or args.keywords:
         raise TypeError("Varargs and keywords not supported in unwrap_spec")
-    assert not func.func_defaults
     argspec = ', '.join([arg for arg in args.args[1:]])
     func_code = py.code.Source("""
     def f(w_obj, %(args)s):
     d = {}
     exec func_code.compile() in d
     f = d['f']
+    f.func_defaults = unbound_meth.func_defaults
+    f.func_doc = unbound_meth.func_doc
     f.__module__ = func.__module__
     # necessary for unique identifiers for pickling
     f.func_name = func.func_name
     if unwrap_spec is None:
-        unwrap_spec = {}
+        unwrap_spec = getattr(unbound_meth, 'unwrap_spec', {})
     else:
         assert isinstance(unwrap_spec, dict)
         unwrap_spec = unwrap_spec.copy()

pypy/interpreter/test/test_app_main.py

         expected_path = [str(prefix.join(subdir).ensure(dir=1))
                          for subdir in ('lib_pypy',
                                         'lib-python/%s' % cpy_ver)]
+        # an empty directory from where we can't find the stdlib
+        tmp_dir = str(udir.join('tmp').ensure(dir=1))
 
         self.w_goal_dir = self.space.wrap(goal_dir)
         self.w_fake_exe = self.space.wrap(str(fake_exe))
         self.w_expected_path = self.space.wrap(expected_path)
         self.w_trunkdir = self.space.wrap(os.path.dirname(pypydir))
 
+        self.w_tmp_dir = self.space.wrap(tmp_dir)
+
         foo_py = prefix.join('foo.py').write("pass")
         self.w_foo_py = self.space.wrap(str(foo_py))
 
     def test_setup_bootstrap_path(self):
-        import sys
+        # Check how sys.path is handled depending on if we can find a copy of
+        # the stdlib in setup_bootstrap_path.
+        import sys, os
         old_sys_path = sys.path[:]
+        old_cwd = os.getcwd()
+
         sys.path.append(self.goal_dir)
+        # make sure cwd does not contain a stdlib
+        os.chdir(self.tmp_dir)
+        tmp_pypy_c = os.path.join(self.tmp_dir, 'pypy-c')
         try:
             import app_main
-            app_main.setup_bootstrap_path('/tmp/pypy-c') # stdlib not found
+            app_main.setup_bootstrap_path(tmp_pypy_c)  # stdlib not found
             assert sys.executable == ''
             assert sys.path == old_sys_path + [self.goal_dir]
 
             assert newpath[:len(self.expected_path)] == self.expected_path
         finally:
             sys.path[:] = old_sys_path
+            os.chdir(old_cwd)
 
     def test_trunk_can_be_prefix(self):
         import sys

pypy/interpreter/test/test_compiler.py

         output = s.getvalue()
         assert "LOAD_GLOBAL" not in output
 
+    def test_folding_of_list_constants(self):
+        source = 'a in [1, 2, 3]'
+        co = compile(source, '', 'exec')
+        i = co.co_consts.index((1, 2, 3))
+        assert i > -1
+        assert isinstance(co.co_consts[i], tuple)
+
+    def test_folding_of_set_constants(self):
+        source = 'a in {1, 2, 3}'
+        co = compile(source, '', 'exec')
+        i = co.co_consts.index(set([1, 2, 3]))
+        assert i > -1
+        assert isinstance(co.co_consts[i], frozenset)
+
+
 class AppTestCallMethod(object):
     spaceconfig = {'objspace.opcodes.CALL_METHOD': True}
         

pypy/interpreter/test/test_gateway.py

 
     def test_interpindirect2app(self):
         space = self.space
+
         class BaseA(W_Root):
             def method(self, space, x):
+                "This is a method"
+                pass
+
+            def method_with_default(self, space, x=5):
+                pass
+
+            @gateway.unwrap_spec(x=int)
+            def method_with_unwrap_spec(self, space, x):
                 pass
 
         class A(BaseA):
             def method(self, space, x):
                 return space.wrap(x + 2)
 
+            def method_with_default(self, space, x):
+                return space.wrap(x + 2)
+
+            def method_with_unwrap_spec(self, space, x):
+                return space.wrap(x + 2)
+
         class B(BaseA):
             def method(self, space, x):
                 return space.wrap(x + 1)
 
+            def method_with_default(self, space, x):
+                return space.wrap(x + 1)
+
+            def method_with_unwrap_spec(self, space, x):
+                return space.wrap(x + 1)
+
         class FakeTypeDef(object):
             rawdict = {}
             bases = {}
         assert space.int_w(space.call_function(w_c, w_a, space.wrap(1))) == 1 + 2
         assert space.int_w(space.call_function(w_c, w_b, space.wrap(-10))) == -10 + 1
 
+        doc = space.str_w(space.getattr(w_c, space.wrap('__doc__')))
+        assert doc == "This is a method"
+
+        meth_with_default = gateway.interpindirect2app(
+            BaseA.method_with_default, {'x': int})
+        w_d = space.wrap(meth_with_default)
+
+        assert space.int_w(space.call_function(w_d, w_a, space.wrap(4))) == 4 + 2
+        assert space.int_w(space.call_function(w_d, w_b, space.wrap(-10))) == -10 + 1
+        assert space.int_w(space.call_function(w_d, w_a)) == 5 + 2
+        assert space.int_w(space.call_function(w_d, w_b)) == 5 + 1
+
+        meth_with_unwrap_spec = gateway.interpindirect2app(
+            BaseA.method_with_unwrap_spec)
+        w_e = space.wrap(meth_with_unwrap_spec)
+        assert space.int_w(space.call_function(w_e, w_a, space.wrap(4))) == 4 + 2
+
     def test_interp2app_unwrap_spec(self):
         space = self.space
         w = space.wrap

pypy/interpreter/test/test_targetpypy.py

 from pypy.goal.targetpypystandalone import get_entry_point, create_entry_point
 from pypy.config.pypyoption import get_pypy_config
+from rpython.rtyper.lltypesystem import rffi, lltype
 
 class TestTargetPyPy(object):
     def test_run(self):
         entry_point(['pypy-c' , '-S', '-c', 'print 3'])
 
 def test_exeucte_source(space):
-    _, execute_source = create_entry_point(space, None)
-    execute_source("import sys; sys.modules['xyz'] = 3")
+    _, d = create_entry_point(space, None)
+    execute_source = d['pypy_execute_source']
+    lls = rffi.str2charp("import sys; sys.modules['xyz'] = 3")
+    execute_source(lls)
+    lltype.free(lls, flavor='raw')
     x = space.int_w(space.getitem(space.getattr(space.builtin_modules['sys'],
                                                 space.wrap('modules')),
                                                 space.wrap('xyz')))
     assert x == 3
-    execute_source("sys")
+    lls = rffi.str2charp("sys")
+    execute_source(lls)
+    lltype.free(lls, flavor='raw')
     # did not crash - the same globals
+    pypy_setup_home = d['pypy_setup_home']
+    lls = rffi.str2charp(__file__)
+    pypy_setup_home(lls, 1)
+    lltype.free(lls, flavor='raw')

pypy/module/__pypy__/__init__.py

         'validate_fd'               : 'interp_magic.validate_fd',
         'resizelist_hint'           : 'interp_magic.resizelist_hint',
         'newlist_hint'              : 'interp_magic.newlist_hint',
+        'add_memory_pressure'       : 'interp_magic.add_memory_pressure',
         'newdict'                   : 'interp_dict.newdict',
         'dictstrategy'              : 'interp_dict.dictstrategy',
         'set_debug'                 : 'interp_magic.set_debug',

pypy/module/__pypy__/interp_magic.py

-from pypy.interpreter.baseobjspace import ObjSpace, W_Root
 from pypy.interpreter.error import OperationError, wrap_oserror
 from pypy.interpreter.gateway import unwrap_spec
 from rpython.rlib.objectmodel import we_are_translated
 from pypy.objspace.std.listobject import W_ListObject
 from pypy.objspace.std.typeobject import MethodCache
 from pypy.objspace.std.mapdict import IndexCache
-from rpython.rlib import rposix
+from rpython.rlib import rposix, rgc
 
 
 def internal_repr(space, w_object):
     bltn = BuiltinFunction(func)
     return space.wrap(bltn)
 
-@unwrap_spec(ObjSpace, W_Root, str)
+@unwrap_spec(meth=str)
 def lookup_special(space, w_obj, meth):
     """Lookup up a special method on an object."""
     if space.is_oldstyle_instance(w_obj):
     space.setitem(space.builtin.w_dict,
                   space.wrap('__debug__'),
                   space.wrap(debug))
+
+@unwrap_spec(estimate=int)
+def add_memory_pressure(estimate):
+    rgc.add_memory_pressure(estimate)

pypy/module/_cffi_backend/cdataobj.py

     ge = _make_comparison('ge')
 
     def hash(self):
-        h = (objectmodel.compute_identity_hash(self.ctype) ^
-             rffi.cast(lltype.Signed, self._cdata))
+        h = rffi.cast(lltype.Signed, self._cdata)
+        # To hash pointers in dictionaries.  Assumes that h shows some
+        # alignment (to 4, 8, maybe 16 bytes), so we use the following
+        # formula to avoid the trailing bits being always 0.
+        h = h ^ (h >> 4)
         return self.space.wrap(h)
 
     def getitem(self, w_index):

pypy/module/_cffi_backend/test/_backend_test_c.py

     BInt = new_primitive_type("int")
     BFloat = new_primitive_type("float")
     for i in range(1, 20):
-        if (hash(cast(BChar, chr(i))) !=
-            hash(cast(BInt, i))):
+        x1 = cast(BChar, chr(i))
+        x2 = cast(BInt, i)
+        if hash(x1) != hash(x2):
             break
     else:
         raise AssertionError("hashes are equal")
     assert x.__name__ == '<cdata>'
     assert hasattr(x, '__doc__')
 
+def test_different_types_of_ptr_equality():
+    BVoidP = new_pointer_type(new_void_type())
+    BIntP = new_pointer_type(new_primitive_type("int"))
+    x = cast(BVoidP, 12345)
+    assert x == cast(BIntP, 12345)
+    assert x != cast(BIntP, 12344)
+    assert hash(x) == hash(cast(BIntP, 12345))
+
 def test_version():
     # this test is here mostly for PyPy
     assert __version__ == "0.6"

pypy/module/_ffi/test/test_funcptr.py

         from _ffi import CDLL, types
         # this should return *all* loaded libs, dlopen(NULL)
         dll = CDLL(None)
-        # Assume CPython, or PyPy compiled with cpyext
-        res = dll.getfunc('Py_IsInitialized', [], types.slong)()
-        assert res == 1
+        # libm should be loaded
+        res = dll.getfunc('sqrt', [types.double], types.double)(1.0)
+        assert res == 1.0
 
     def test_callfunc(self):
         from _ffi import CDLL, types
 
     def test_pointer_args(self):
         """
-            extern int dummy; // defined in test_void_result 
+            extern int dummy; // defined in test_void_result
             DLLEXPORT int* get_dummy_ptr() { return &dummy; }
             DLLEXPORT void set_val_to_ptr(int* ptr, int val) { *ptr = val; }
         """
 
     def test_convert_pointer_args(self):
         """
-            extern int dummy; // defined in test_void_result 
+            extern int dummy; // defined in test_void_result
             DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args
             DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto
         """
             def _as_ffi_pointer_(self, ffitype):
                 assert ffitype is types.void_p
                 return self.value
-        
+
         libfoo = CDLL(self.libfoo_name)
         get_dummy = libfoo.getfunc('get_dummy', [], types.sint)
         get_dummy_ptr = libfoo.getfunc('get_dummy_ptr', [], types.void_p)
 
     def test_typed_pointer_args(self):
         """
-            extern int dummy; // defined in test_void_result 
+            extern int dummy; // defined in test_void_result
             DLLEXPORT int* get_dummy_ptr(); // defined in test_pointer_args
             DLLEXPORT void set_val_to_ptr(int* ptr, int val); // ditto
         """
         from _ffi import CDLL, types
         libfoo = CDLL(self.libfoo_name)
         raises(TypeError, "libfoo.getfunc('sum_xy', [types.void], types.sint)")
-        
+
     def test_OSError_loading(self):
         from _ffi import CDLL, types
         raises(OSError, "CDLL('I do not exist')")
         from _rawffi import FUNCFLAG_STDCALL
         libm = CDLL(self.libm_name)
         pow_addr = libm.getaddressindll('pow')
-        wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow', 
+        wrong_pow = FuncPtr.fromaddr(pow_addr, 'pow',
                 [types.double, types.double], types.double, FUNCFLAG_STDCALL)
         try:
             wrong_pow(2, 3) == 8
         from _rawffi import FUNCFLAG_STDCALL
         kernel = WinDLL('Kernel32.dll')
         sleep_addr = kernel.getaddressindll('Sleep')
-        sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint], 
+        sleep = FuncPtr.fromaddr(sleep_addr, 'sleep', [types.uint],
                             types.void, FUNCFLAG_STDCALL)
         sleep(10)
 

pypy/module/_rawffi/test/test__rawffi.py

         import _rawffi
         # this should return *all* loaded libs, dlopen(NULL)
         dll = _rawffi.CDLL(None)
-        # Assume CPython, or PyPy compiled with cpyext
-        res = dll.ptr('Py_IsInitialized', [], 'l')()
-        assert res[0] == 1
+        func = dll.ptr('rand', [], 'i')
+        res = func()
+        assert res[0] != 0
 
     def test_libc_load(self):
         import _rawffi

pypy/module/array/__init__.py

 from pypy.interpreter.mixedmodule import MixedModule
 
-from pypy.module.array.interp_array import types
-from pypy.objspace.std.model import registerimplementation
-
-for mytype in types.values():
-    registerimplementation(mytype.w_class)
-
-
 class Module(MixedModule):
     interpleveldefs = {
         'array': 'interp_array.W_ArrayBase',

pypy/module/array/interp_array.py

 
 from pypy.interpreter.buffer import RWBuffer
 from pypy.interpreter.error import OperationError
-from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr
+from pypy.interpreter.gateway import interp2app, unwrap_spec, interpindirect2app
+from pypy.interpreter.typedef import GetSetProperty, make_weakref_descr, TypeDef
+from pypy.interpreter.baseobjspace import W_Root
 from pypy.module._file.interp_file import W_File
-from pypy.objspace.std.model import W_Object
-from pypy.objspace.std.multimethod import FailedToImplement
-from pypy.objspace.std.stdtypedef import SMM, StdTypeDef
-from pypy.objspace.std.register_all import register_all
 from rpython.rlib import jit
 from rpython.rlib.rarithmetic import ovfcheck, widen
 from rpython.rlib.unroll import unrolling_iterable
-from rpython.rlib.objectmodel import specialize, keepalive_until_here
+from rpython.rlib.objectmodel import keepalive_until_here
 from rpython.rtyper.lltypesystem import lltype, rffi
 
 
             if len(__args__.arguments_w) > 0:
                 w_initializer = __args__.arguments_w[0]
                 if space.type(w_initializer) is space.w_str:
-                    a.fromstring(space.str_w(w_initializer))
+                    a.descr_fromstring(space, space.str_w(w_initializer))
                 elif space.type(w_initializer) is space.w_list:
-                    a.fromlist(w_initializer)
+                    a.descr_fromlist(space, w_initializer)
                 else:
                     a.extend(w_initializer, True)
             break
     return a
 
 
-array_append = SMM('append', 2)
-array_extend = SMM('extend', 2)
-
-array_count = SMM('count', 2)
-array_index = SMM('index', 2)
-array_reverse = SMM('reverse', 1)
-array_remove = SMM('remove', 2)
-array_pop = SMM('pop', 2, defaults=(-1,))
-array_insert = SMM('insert', 3)
-
-array_tolist = SMM('tolist', 1)
-array_fromlist = SMM('fromlist', 2)
-array_tostring = SMM('tostring', 1)
-array_fromstring = SMM('fromstring', 2)
-array_tounicode = SMM('tounicode', 1)
-array_fromunicode = SMM('fromunicode', 2)
-array_tofile = SMM('tofile', 2)
-array_fromfile = SMM('fromfile', 3)
-
-array_buffer_info = SMM('buffer_info', 1)
-array_reduce = SMM('__reduce__', 1)
-array_copy = SMM('__copy__', 1)
-array_byteswap = SMM('byteswap', 1)
-
-
 def descr_itemsize(space, self):
     return space.wrap(self.itemsize)
 
 def descr_typecode(space, self):
     return space.wrap(self.typecode)
 
+arr_eq_driver = jit.JitDriver(greens = ['comp_func'], reds = 'auto')
+EQ, NE, LT, LE, GT, GE = range(6)
 
-class W_ArrayBase(W_Object):
-    @staticmethod
-    def register(typeorder):
-        typeorder[W_ArrayBase] = []
+def compare_arrays(space, arr1, arr2, comp_op, comp_func):
+    if (not isinstance(arr1, W_ArrayBase) or
+        not isinstance(arr2, W_ArrayBase)):
+        return space.w_NotImplemented
+    if comp_op == EQ and arr1.len != arr2.len:
+        return space.w_False
+    if comp_op == NE and arr1.len != arr2.len:
+        return space.w_True
+    lgt = min(arr1.len, arr2.len)
+    for i in range(lgt):
+        arr_eq_driver.jit_merge_point(comp_func=comp_func)
+        w_elem1 = arr1.w_getitem(space, i)
+        w_elem2 = arr2.w_getitem(space, i)
+        res = space.is_true(comp_func(w_elem1, w_elem2))
+        if comp_op == EQ:
+            if not res:
+                return space.w_False
+        elif comp_op == NE:
+            if res:
+                return space.w_True
+        elif comp_op == LT or comp_op == GT:
+            if res:
+                return space.w_True
+            elif not space.is_true(space.eq(w_elem1, w_elem2)):
+                return space.w_False
+        else:
+            if not res:
+                return space.w_False
+            elif not space.is_true(space.eq(w_elem1, w_elem2)):
+                return space.w_True
+    # we have some leftovers
+    if comp_op == EQ:
+        return space.w_True
+    elif comp_op == NE:
+        return space.w_False
+    if arr1.len == arr2.len:
+        if comp_op == LT or comp_op == GT:
+            return space.w_False
+        return space.w_True
+    if comp_op == LT or comp_op == LE:
+        if arr1.len < arr2.len:
+            return space.w_True
+        return space.w_False
+    if arr1.len > arr2.len:
+        return space.w_True
+    return space.w_False
 
-W_ArrayBase.typedef = StdTypeDef(
+UNICODE_ARRAY = lltype.Ptr(lltype.Array(lltype.UniChar,
+                                        hints={'nolength': True}))
+
+class W_ArrayBase(W_Root):
+    _attrs_ = ('space', 'len', 'allocated', '_lifeline_') # no buffer
+
+    def __init__(self, space):
+        self.space = space
+        self.len = 0
+        self.allocated = 0
+
+    def descr_append(self, space, w_x):
+        """ append(x)
+
+        Append new value x to the end of the array.
+        """
+        raise NotImplementedError
+
+    def descr_extend(self, space, w_x):
+        """ extend(array or iterable)
+
+        Append items to the end of the array.
+        """
+        self.extend(w_x)
+
+    def descr_count(self, space, w_val):
+        """ count(x)
+
+        Return number of occurrences of x in the array.
+        """
+        raise NotImplementedError
+
+    def descr_index(self, space, w_x):
+        """ index(x)
+
+        Return index of first occurrence of x in the array.
+        """
+        raise NotImplementedError
+
+    def descr_reverse(self, space):
+        """ reverse()
+
+        Reverse the order of the items in the array.
+        """
+        raise NotImplementedError
+
+    def descr_remove(self, space, w_val):
+        """ remove(x)
+
+        Remove the first occurrence of x in the array.
+        """
+        raise NotImplementedError
+
+    @unwrap_spec(i=int)
+    def descr_pop(self, space, i=-1):
+        """ pop([i])
+
+        Return the i-th element and delete it from the array. i defaults to -1.
+        """
+        raise NotImplementedError
+
+    @unwrap_spec(idx=int)
+    def descr_insert(self, space, idx, w_val):
+        """ insert(i,x)
+
+        Insert a new item x into the array before position i.
+        """
+        raise NotImplementedError
+
+    def descr_tolist(self, space):
+        """ tolist() -> list
+
+        Convert array to an ordinary list with the same items.
+        """
+        w_l = space.newlist([])
+        for i in range(self.len):
+            w_l.append(self.w_getitem(space, i))
+        return w_l
+
+    def descr_fromlist(self, space, w_lst):
+        """ fromlist(list)
+
+        Append items to array from list.
+        """
+        if not space.isinstance_w(w_lst, space.w_list):
+            raise OperationError(space.w_TypeError,
+                                 space.wrap("arg must be list"))
+        s = self.len
+        try:
+            self.fromsequence(w_lst)
+        except OperationError:
+            self.setlen(s)
+            raise
+
+    def descr_tostring(self, space):
+        """ tostring() -> string
+
+        Convert the array to an array of machine values and return the string
+        representation.
+        """
+        cbuf = self._charbuf_start()
+        s = rffi.charpsize2str(cbuf, self.len * self.itemsize)
+        self._charbuf_stop()
+        return self.space.wrap(s)
+
+    @unwrap_spec(s=str)
+    def descr_fromstring(self, space, s):
+        """ fromstring(string)
+
+        Appends items from the string, interpreting it as an array of machine
+        values,as if it had been read from a file using the fromfile() method).
+        """
+        if len(s) % self.itemsize != 0:
+            msg = 'string length not a multiple of item size'
+            raise OperationError(self.space.w_ValueError, self.space.wrap(msg))
+        oldlen = self.len
+        new = len(s) / self.itemsize
+        self.setlen(oldlen + new)
+        cbuf = self._charbuf_start()
+        for i in range(len(s)):
+            cbuf[oldlen * self.itemsize + i] = s[i]
+        self._charbuf_stop()
+
+    @unwrap_spec(w_f=W_File, n=int)
+    def descr_fromfile(self, space, w_f, n):
+        """ fromfile(f, n)
+
+        Read n objects from the file object f and append them to the end of the
+        array.  Also called as read.
+        """
+        try:
+            size = ovfcheck(self.itemsize * n)
+        except OverflowError:
+            raise MemoryError
+        w_item = space.call_method(w_f, 'read', space.wrap(size))
+        item = space.str_w(w_item)
+        if len(item) < size:
+            n = len(item) % self.itemsize
+            elems = max(0, len(item) - (len(item) % self.itemsize))
+            if n != 0:
+                item = item[0:elems]
+            self.descr_fromstring(space, item)
+            msg = "not enough items in file"
+            raise OperationError(space.w_EOFError, space.wrap(msg))
+        self.descr_fromstring(space, item)
+
+    @unwrap_spec(w_f=W_File)
+    def descr_tofile(self, space, w_f):
+        """ tofile(f)
+
+        Write all items (as machine values) to the file object f.  Also called as
+        write.
+        """
+        w_s = self.descr_tostring(space)
+        space.call_method(w_f, 'write', w_s)
+
+    def descr_fromunicode(self, space, w_ustr):
+        """ fromunicode(ustr)
+
+        Extends this array with data from the unicode string ustr.
+        The array must be a type 'u' array; otherwise a ValueError
+        is raised.  Use array.fromstring(ustr.decode(...)) to
+        append Unicode data to an array of some other type.
+        """
+        # XXX the following probable bug is not emulated:
+        # CPython accepts a non-unicode string or a buffer, and then
+        # behaves just like fromstring(), except that it strangely truncate
+        # string arguments at multiples of the unicode byte size.
+        # Let's only accept unicode arguments for now.
+        if self.typecode == 'u':
+            self.fromsequence(w_ustr)
+        else:
+            msg = "fromunicode() may only be called on type 'u' arrays"
+            raise OperationError(space.w_ValueError, space.wrap(msg))
+
+    def descr_tounicode(self, space):
+        """ tounicode() -> unicode
+
+        Convert the array to a unicode string.  The array must be
+        a type 'u' array; otherwise a ValueError is raised.  Use
+        array.tostring().decode() to obtain a unicode string from
+        an array of some other type.
+        """
+        if self.typecode == 'u':
+            buf = rffi.cast(UNICODE_ARRAY, self._buffer_as_unsigned())
+            return space.wrap(rffi.wcharpsize2unicode(buf, self.len))
+        else:
+            msg = "tounicode() may only be called on type 'u' arrays"
+            raise OperationError(space.w_ValueError, space.wrap(msg))
+
+    def descr_buffer_info(self, space):
+        """ buffer_info() -> (address, length)
+
+        Return a tuple (address, length) giving the current memory address and
+        the length in items of the buffer used to hold array's contents
+        The length should be multiplied by the itemsize attribute to calculate
+        the buffer length in bytes.
+        """
+        w_ptr = space.wrap(self._buffer_as_unsigned())
+        w_len = space.wrap(self.len)
+        return space.newtuple([w_ptr, w_len])
+
+    def descr_reduce(self, space):
+        """ Return state information for pickling.
+        """
+        if self.len > 0:
+            w_s = self.descr_tostring(space)
+            args = [space.wrap(self.typecode), w_s]
+        else:
+            args = [space.wrap(self.typecode)]
+        try:
+            dct = space.getattr(self, space.wrap('__dict__'))
+        except OperationError:
+            dct = space.w_None
+        return space.newtuple([space.type(self), space.newtuple(args), dct])
+
+    def descr_copy(self, space):
+        """ copy(array)
+
+        Return a copy of the array.
+        """
+        w_a = self.constructor(self.space)
+        w_a.setlen(self.len, overallocate=False)
+        rffi.c_memcpy(
+            rffi.cast(rffi.VOIDP, w_a._buffer_as_unsigned()),
+            rffi.cast(rffi.VOIDP, self._buffer_as_unsigned()),
+            self.len * self.itemsize
+        )
+        return w_a
+
+    def descr_byteswap(self, space):
+        """ byteswap()
+
+        Byteswap all items of the array.  If the items in the array are not 1, 2,
+        4, or 8 bytes in size, RuntimeError is raised.
+        """
+        if self.itemsize not in [1, 2, 4, 8]:
+            msg = "byteswap not supported for this array"
+            raise OperationError(space.w_RuntimeError, space.wrap(msg))
+        if self.len == 0:
+            return
+        bytes = self._charbuf_start()
+        tmp = [bytes[0]] * self.itemsize
+        for start in range(0, self.len * self.itemsize, self.itemsize):
+            stop = start + self.itemsize - 1
+            for i in range(self.itemsize):
+                tmp[i] = bytes[start + i]
+            for i in range(self.itemsize):
+                bytes[stop - i] = tmp[i]
+        self._charbuf_stop()
+
+    def descr_len(self, space):
+        return space.wrap(self.len)
+
+    def descr_eq(self, space, w_arr2):
+        "x.__eq__(y) <==> x==y"
+        return compare_arrays(space, self, w_arr2, EQ, space.eq)
+
+    def descr_ne(self, space, w_arr2):
+        "x.__ne__(y) <==> x!=y"
+        return compare_arrays(space, self, w_arr2, NE, space.ne)
+
+    def descr_lt(self, space, w_arr2):
+        "x.__lt__(y) <==> x<y"
+        return compare_arrays(space, self, w_arr2, LT, space.lt)
+
+    def descr_le(self, space, w_arr2):
+        "x.__le__(y) <==> x<=y"
+        return compare_arrays(space, self, w_arr2, LE, space.le)
+
+    def descr_gt(self, space, w_arr2):
+        "x.__gt__(y) <==> x>y"
+        return compare_arrays(space, self, w_arr2, GT, space.gt)
+
+    def descr_ge(self, space, w_arr2):
+        "x.__ge__(y) <==> x>=y"
+        return compare_arrays(space, self, w_arr2, GE, space.ge)
+
+    # Basic get/set/append/extend methods
+
+    def descr_getitem(self, space, w_idx):
+        "x.__getitem__(y) <==> x[y]"
+        if not space.isinstance_w(w_idx, space.w_slice):
+            idx, stop, step = space.decode_index(w_idx, self.len)
+            assert step == 0
+            return self.w_getitem(space, idx)
+        else:
+            return self.getitem_slice(space, w_idx)
+
+    def descr_getslice(self, space, w_i, w_j):
+        return space.getitem(self, space.newslice(w_i, w_j, space.w_None))
+
+
+    def descr_setitem(self, space, w_idx, w_item):
+        "x.__setitem__(i, y) <==> x[i]=y"
+        if space.isinstance_w(w_idx, space.w_slice):
+            self.setitem_slice(space, w_idx, w_item)
+        else:
+            self.setitem(space, w_idx, w_item)
+
+    def descr_setslice(self, space, w_start, w_stop, w_item):
+        self.setitem_slice(space,
+                           space.newslice(w_start, w_stop, space.w_None),
+                           w_item)
+
+    def descr_delitem(self, space, w_idx):
+        start, stop, step, size = self.space.decode_index4(w_idx, self.len)
+        if step != 1:
+            # I don't care about efficiency of that so far
+            w_lst = self.descr_tolist(space)
+            space.delitem(w_lst, w_idx)
+            self.setlen(0)
+            self.fromsequence(w_lst)
+            return
+        return self.delitem(space, start, stop)
+
+    def descr_delslice(self, space, w_start, w_stop):
+        self.descr_delitem(space, space.newslice(w_start, w_stop, space.w_None))
+
+    def descr_add(self, space, w_other):
+        raise NotImplementedError
+
+    def descr_inplace_add(self, space, w_other):
+        raise NotImplementedError
+
+    def descr_mul(self, space, w_repeat):
+        raise NotImplementedError
+
+    def descr_inplace_mul(self, space, w_repeat):
+        raise NotImplementedError
+
+    def descr_radd(self, space, w_other):
+        return self.descr_add(space, w_other)
+
+    def descr_rmul(self, space, w_repeat):
+        return self.descr_mul(space, w_repeat)
+
+    # Misc methods
+
+    def descr_buffer(self, space):
+        return space.wrap(ArrayBuffer(self))
+
+    def descr_repr(self, space):
+        if self.len == 0:
+            return space.wrap("array('%s')" % self.typecode)
+        elif self.typecode == "c":
+            r = space.repr(self.descr_tostring(space))
+            s = "array('%s', %s)" % (self.typecode, space.str_w(r))
+            return space.wrap(s)
+        elif self.typecode == "u":
+            r = space.repr(self.descr_tounicode(space))
+            s = "array('%s', %s)" % (self.typecode, space.str_w(r))
+            return space.wrap(s)
+        else:
+            r = space.repr(self.descr_tolist(space))
+            s = "array('%s', %s)" % (self.typecode, space.str_w(r))
+            return space.wrap(s)
+
+W_ArrayBase.typedef = TypeDef(
     'array',
     __new__ = interp2app(w_array),
     __module__   = 'array',
+
+    __len__ = interp2app(W_ArrayBase.descr_len),
+    __eq__ = interp2app(W_ArrayBase.descr_eq),
+    __ne__ = interp2app(W_ArrayBase.descr_ne),
+    __lt__ = interp2app(W_ArrayBase.descr_lt),
+    __le__ = interp2app(W_ArrayBase.descr_le),
+    __gt__ = interp2app(W_ArrayBase.descr_gt),
+    __ge__ = interp2app(W_ArrayBase.descr_ge),
+
+    __getitem__ = interp2app(W_ArrayBase.descr_getitem),
+    __getslice__ = interp2app(W_ArrayBase.descr_getslice),
+    __setitem__ = interp2app(W_ArrayBase.descr_setitem),
+    __setslice__ = interp2app(W_ArrayBase.descr_setslice),
+    __delitem__ = interp2app(W_ArrayBase.descr_delitem),
+    __delslice__ = interp2app(W_ArrayBase.descr_delslice),
+
+    __add__ = interpindirect2app(W_ArrayBase.descr_add),
+    __iadd__ = interpindirect2app(W_ArrayBase.descr_inplace_add),
+    __mul__ = interpindirect2app(W_ArrayBase.descr_mul),
+    __imul__ = interpindirect2app(W_ArrayBase.descr_inplace_mul),
+    __radd__ = interp2app(W_ArrayBase.descr_radd),
+    __rmul__ = interp2app(W_ArrayBase.descr_rmul),
+
+    __buffer__ = interp2app(W_ArrayBase.descr_buffer),
+    __repr__ = interp2app(W_ArrayBase.descr_repr),
+
     itemsize = GetSetProperty(descr_itemsize),
     typecode = GetSetProperty(descr_typecode),
     __weakref__ = make_weakref_descr(W_ArrayBase),
+    append = interpindirect2app(W_ArrayBase.descr_append),
+    extend = interp2app(W_ArrayBase.descr_extend),
+    count = interpindirect2app(W_ArrayBase.descr_count),
+    index = interpindirect2app(W_ArrayBase.descr_index),
+    reverse = interpindirect2app(W_ArrayBase.descr_reverse),
+    remove = interpindirect2app(W_ArrayBase.descr_remove),
+    pop = interpindirect2app(W_ArrayBase.descr_pop),
+    insert = interpindirect2app(W_ArrayBase.descr_insert),
+
+    tolist = interp2app(W_ArrayBase.descr_tolist),
+    fromlist = interp2app(W_ArrayBase.descr_fromlist),
+    tostring = interp2app(W_ArrayBase.descr_tostring),
+    fromstring = interp2app(W_ArrayBase.descr_fromstring),
+    tofile = interp2app(W_ArrayBase.descr_tofile),
+    fromfile = interp2app(W_ArrayBase.descr_fromfile),
+    fromunicode = interp2app(W_ArrayBase.descr_fromunicode),
+    tounicode = interp2app(W_ArrayBase.descr_tounicode),
+
+    buffer_info = interp2app(W_ArrayBase.descr_buffer_info),
+    __copy__ = interp2app(W_ArrayBase.descr_copy),
+    __reduce__ = interp2app(W_ArrayBase.descr_reduce),
+    byteswap = interp2app(W_ArrayBase.descr_byteswap),
 )
-W_ArrayBase.typedef.registermethods(globals())
 
 
 class TypeCode(object):
     def __init__(self, itemtype, unwrap, canoverflow=False, signed=False):
         self.itemtype = itemtype
         self.bytes = rffi.sizeof(itemtype)
-        #self.arraytype = lltype.GcArray(itemtype)
         self.arraytype = lltype.Array(itemtype, hints={'nolength': True})
         self.unwrap = unwrap
         self.signed = signed
         itemsize = mytype.bytes
         typecode = mytype.typecode
 
-        @staticmethod
-        def register(typeorder):
-            typeorder[W_Array] = [(W_ArrayBase, None)]
+        _attrs_ = ('space', 'len', 'allocated', '_lifeline_', 'buffer')
 
         def __init__(self, space):
-            self.space = space
-            self.len = 0
-            self.allocated = 0
+            W_ArrayBase.__init__(self, space)
             self.buffer = lltype.nullptr(mytype.arraytype)
 
         def item_w(self, w_item):
                 raise
             self.setlen(oldlen + i)
 
-        def fromstring(self, s):
-            if len(s) % self.itemsize != 0:
-                msg = 'string length not a multiple of item size'
-                raise OperationError(self.space.w_ValueError, self.space.wrap(msg))
-            oldlen = self.len
-            new = len(s) / mytype.bytes
-            self.setlen(oldlen + new)
-            cbuf = self._charbuf_start()
-            for i in range(len(s)):
-                cbuf[oldlen * mytype.bytes + i] = s[i]
-            self._charbuf_stop()
-
-        def fromlist(self, w_lst):
-            s = self.len
-            try:
-                self.fromsequence(w_lst)
-            except OperationError:
-                self.setlen(s)
-                raise
-
         def extend(self, w_iterable, accept_different_array=False):
             space = self.space
             if isinstance(w_iterable, W_Array):
         def _charbuf_start(self):
             return rffi.cast(rffi.CCHARP, self.buffer)
 
+        def _buffer_as_unsigned(self):
+            return rffi.cast(lltype.Unsigned, self.buffer)
+
         def _charbuf_stop(self):
             keepalive_until_here(self)
 
                 item = float(item)
             return space.wrap(item)
 
-    # Basic get/set/append/extend methods
+        # interface
 
-    def len__Array(space, self):
-        return space.wrap(self.len)
+        def descr_append(self, space, w_x):
+            x = self.item_w(w_x)
+            self.setlen(self.len + 1)
+            self.buffer[self.len - 1] = x
 
-    def getitem__Array_ANY(space, self, w_idx):
-        idx, stop, step = space.decode_index(w_idx, self.len)
-        assert step == 0
-        return self.w_getitem(space, idx)
+        # List interface
+        def descr_count(self, space, w_val):
+            cnt = 0
+            for i in range(self.len):
+                # XXX jitdriver
+                w_item = self.w_getitem(space, i)
+                if space.is_true(space.eq(w_item, w_val)):
+                    cnt += 1
+            return space.wrap(cnt)
 
-    def getitem__Array_Slice(space, self, w_slice):
-        start, stop, step, size = space.decode_index4(w_slice, self.len)
-        w_a = mytype.w_class(self.space)
-        w_a.setlen(size, overallocate=False)
-        assert step != 0
-        j = 0
-        for i in range(start, stop, step):
-            w_a.buffer[j] = self.buffer[i]
-            j += 1
-        return w_a
+        def descr_index(self, space, w_val):
+            for i in range(self.len):
+                w_item = self.w_getitem(space, i)
+                if space.is_true(space.eq(w_item, w_val)):
+                    return space.wrap(i)
+            msg = 'array.index(x): x not in list'
+            raise OperationError(space.w_ValueError, space.wrap(msg))
 
-    def getslice__Array_ANY_ANY(space, self, w_i, w_j):
-        return space.getitem(self, space.newslice(w_i, w_j, space.w_None))
+        def descr_reverse(self, space):
+            b = self.buffer
+            for i in range(self.len / 2):
+                b[i], b[self.len - i - 1] = b[self.len - i - 1], b[i]
 
-    def setitem__Array_ANY_ANY(space, self, w_idx, w_item):
-        idx, stop, step = space.decode_index(w_idx, self.len)
-        if step != 0:
-            msg = 'can only assign array to array slice'
-            raise OperationError(self.space.w_TypeError, self.space.wrap(msg))
-        item = self.item_w(w_item)
-        self.buffer[idx] = item
+        def descr_pop(self, space, i):
+            if i < 0:
+                i += self.len
+            if i < 0 or i >= self.len:
+                msg = 'pop index out of range'
+                raise OperationError(space.w_IndexError, space.wrap(msg))
+            w_val = self.w_getitem(space, i)
+            while i < self.len - 1:
+                self.buffer[i] = self.buffer[i + 1]
+                i += 1
+            self.setlen(self.len - 1)
+            return w_val
 
-    def setitem__Array_Slice_Array(space, self, w_idx, w_item):
-        start, stop, step, size = self.space.decode_index4(w_idx, self.len)
-        assert step != 0
-        if w_item.len != size or self is w_item: