Author: Remi Meier <remi.me...@gmail.com>
Branch: stmgc-c8
Changeset: r82417:3522d0e0b4ac
Date: 2016-02-22 23:49 +0100
http://bitbucket.org/pypy/pypy/changeset/3522d0e0b4ac/

Log:    Next merge with default

diff too long, truncating to 2000 out of 5350 lines

diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -29,4 +29,4 @@
 release/
 !pypy/tool/release/
 rpython/_cache/
-__pycache__/
+.cache/
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -28,7 +28,7 @@
     DEALINGS IN THE SOFTWARE.
 
 
-PyPy Copyright holders 2003-2015
+PyPy Copyright holders 2003-2016
 ----------------------------------- 
 
 Except when otherwise stated (look for LICENSE files or information at
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
@@ -1376,6 +1376,7 @@
 
 def decode_long(data):
     r"""Decode a long from a two's complement little-endian binary string.
+    This is overriden on PyPy by a RPython version that has linear complexity.
 
     >>> decode_long('')
     0L
@@ -1402,6 +1403,11 @@
         n -= 1L << (nbytes * 8)
     return n
 
+try:
+    from __pypy__ import decode_long
+except ImportError:
+    pass
+
 # Shorthands
 
 try:
diff --git a/lib_pypy/cffi.egg-info/PKG-INFO b/lib_pypy/cffi.egg-info/PKG-INFO
--- a/lib_pypy/cffi.egg-info/PKG-INFO
+++ b/lib_pypy/cffi.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: cffi
-Version: 1.4.0
+Version: 1.4.2
 Summary: Foreign Function Interface for Python calling C code.
 Home-page: http://cffi.readthedocs.org
 Author: Armin Rigo, Maciej Fijalkowski
diff --git a/lib_pypy/cffi/__init__.py b/lib_pypy/cffi/__init__.py
--- a/lib_pypy/cffi/__init__.py
+++ b/lib_pypy/cffi/__init__.py
@@ -4,8 +4,8 @@
 from .api import FFI, CDefError, FFIError
 from .ffiplatform import VerificationError, VerificationMissing
 
-__version__ = "1.4.0"
-__version_info__ = (1, 4, 0)
+__version__ = "1.4.2"
+__version_info__ = (1, 4, 2)
 
 # The verifier module file names are based on the CRC32 of a string that
 # contains the following version number.  It may be older than __version__
diff --git a/pypy/doc/embedding.rst b/pypy/doc/embedding.rst
--- a/pypy/doc/embedding.rst
+++ b/pypy/doc/embedding.rst
@@ -130,8 +130,13 @@
 More complete example
 ---------------------
 
-.. note:: This example depends on pypy_execute_source_ptr which is not 
available
-          in PyPy <= 2.2.1.
+.. note:: Note that we do not make use of ``extern "Python"``, the new
+   way to do callbacks in CFFI 1.4: this is because these examples use
+   the ABI mode, not the API mode, and with the ABI mode you still have
+   to use ``ffi.callback()``.  It is work in progress to integrate
+   ``extern "Python"`` with the idea of embedding (and it is expected
+   to ultimately lead to a better way to do embedding than the one
+   described here, and that would work equally well on CPython and PyPy).
 
 Typically we need something more to do than simply execute source. The 
following
 is a fully fledged example, please consult cffi documentation for details.
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -5,6 +5,8 @@
 .. this is a revision shortly after release-4.0.1
 .. startrev: 4b5c840d0da2
 
+Fixed ``_PyLong_FromByteArray()``, which was buggy.
+
 .. branch: numpy-1.10
 
 Fix tests to run cleanly with -A and start to fix micronumpy for upstream numpy
@@ -44,6 +46,9 @@
 
 .. branch: fix-setslice-can-resize
 
+Make rlist's ll_listsetslice() able to resize the target list to help
+simplify objspace/std/listobject.py. Was issue #2196.
+
 .. branch: anntype2
 
 A somewhat random bunch of changes and fixes following up on branch 'anntype'. 
Highlights:
@@ -77,3 +82,24 @@
 .. branch: always-enable-gil
 
 Simplify a bit the GIL handling in non-jitted code.  Fixes issue #2205.
+
+.. branch: flowspace-cleanups
+
+Trivial cleanups in flowspace.operation : fix comment & duplicated method
+
+.. branch: test-AF_NETLINK
+
+Add a test for pre-existing AF_NETLINK support. Was part of issue #1942.
+
+.. branch: small-cleanups-misc
+
+Trivial misc cleanups: typo, whitespace, obsolete comments
+
+.. branch: cpyext-slotdefs
+.. branch: fix-missing-canraise
+.. branch: whatsnew
+
+.. branch: fix-2211
+
+Fix the cryptic exception message when attempting to use extended slicing
+in rpython. Was issue #2211.
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
@@ -89,6 +89,7 @@
         'set_code_callback'         : 'interp_magic.set_code_callback',
         'save_module_content_for_future_reload':
                           'interp_magic.save_module_content_for_future_reload',
+        'decode_long'               : 'interp_magic.decode_long',
     }
     if sys.platform == 'win32':
         interpleveldefs['get_console_cp'] = 'interp_magic.get_console_cp'
diff --git a/pypy/module/__pypy__/interp_magic.py 
b/pypy/module/__pypy__/interp_magic.py
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -1,4 +1,4 @@
-from pypy.interpreter.error import OperationError, wrap_oserror
+from pypy.interpreter.error import OperationError, oefmt, wrap_oserror
 from pypy.interpreter.gateway import unwrap_spec
 from pypy.interpreter.pycode import CodeHookCache
 from pypy.interpreter.pyframe import PyFrame
@@ -158,4 +158,13 @@
     if space.is_none(w_callable):
         cache._code_hook = None
     else:
-        cache._code_hook = w_callable
\ No newline at end of file
+        cache._code_hook = w_callable
+
+@unwrap_spec(string=str, byteorder=str, signed=int)
+def decode_long(space, string, byteorder='little', signed=1):
+    from rpython.rlib.rbigint import rbigint, InvalidEndiannessError
+    try:
+        result = rbigint.frombytes(string, byteorder, bool(signed))
+    except InvalidEndiannessError:
+        raise oefmt(space.w_ValueError, "invalid byteorder argument")
+    return space.newlong_from_rbigint(result)
diff --git a/pypy/module/__pypy__/test/test_magic.py 
b/pypy/module/__pypy__/test/test_magic.py
--- a/pypy/module/__pypy__/test/test_magic.py
+++ b/pypy/module/__pypy__/test/test_magic.py
@@ -30,4 +30,20 @@
 """ in d
         finally:
             __pypy__.set_code_callback(None)
-        assert d['f'].__code__ in l
\ No newline at end of file
+        assert d['f'].__code__ in l
+
+    def test_decode_long(self):
+        from __pypy__ import decode_long
+        assert decode_long('') == 0
+        assert decode_long('\xff\x00') == 255
+        assert decode_long('\xff\x7f') == 32767
+        assert decode_long('\x00\xff') == -256
+        assert decode_long('\x00\x80') == -32768
+        assert decode_long('\x80') == -128
+        assert decode_long('\x7f') == 127
+        assert decode_long('\x55' * 97) == (1 << (97 * 8)) // 3
+        assert decode_long('\x00\x80', 'big') == 128
+        assert decode_long('\xff\x7f', 'little', False) == 32767
+        assert decode_long('\x00\x80', 'little', False) == 32768
+        assert decode_long('\x00\x80', 'little', True) == -32768
+        raises(ValueError, decode_long, '', 'foo')
diff --git a/pypy/module/_cffi_backend/__init__.py 
b/pypy/module/_cffi_backend/__init__.py
--- a/pypy/module/_cffi_backend/__init__.py
+++ b/pypy/module/_cffi_backend/__init__.py
@@ -2,7 +2,7 @@
 from pypy.interpreter.mixedmodule import MixedModule
 from rpython.rlib import rdynload, clibffi
 
-VERSION = "1.4.0"
+VERSION = "1.4.2"
 
 FFI_DEFAULT_ABI = clibffi.FFI_DEFAULT_ABI
 try:
diff --git a/pypy/module/_cffi_backend/cglob.py 
b/pypy/module/_cffi_backend/cglob.py
--- a/pypy/module/_cffi_backend/cglob.py
+++ b/pypy/module/_cffi_backend/cglob.py
@@ -3,6 +3,7 @@
 from pypy.interpreter.typedef import TypeDef
 from pypy.module._cffi_backend.cdataobj import W_CData
 from pypy.module._cffi_backend import newtype
+from rpython.rlib import rgil
 from rpython.rlib.objectmodel import we_are_translated
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
@@ -26,7 +27,9 @@
             if not we_are_translated():
                 FNPTR = rffi.CCallback([], rffi.VOIDP)
                 fetch_addr = rffi.cast(FNPTR, self.fetch_addr)
+                rgil.release()
                 result = fetch_addr()
+                rgil.acquire()
             else:
                 # careful in translated versions: we need to call fetch_addr,
                 # but in a GIL-releasing way.  The easiest is to invoke a
diff --git a/pypy/module/_cffi_backend/ctypefunc.py 
b/pypy/module/_cffi_backend/ctypefunc.py
--- a/pypy/module/_cffi_backend/ctypefunc.py
+++ b/pypy/module/_cffi_backend/ctypefunc.py
@@ -423,7 +423,9 @@
             exchange_offset += rffi.getintfield(self.atypes[i], 'c_size')
 
         # store the exchange data size
-        cif_descr.exchange_size = exchange_offset
+        # we also align it to the next multiple of 8, in an attempt to
+        # work around bugs(?) of libffi (see cffi issue #241)
+        cif_descr.exchange_size = self.align_arg(exchange_offset)
 
     def fb_extra_fields(self, cif_descr):
         cif_descr.abi = self.fabi
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py 
b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -1,7 +1,7 @@
 # ____________________________________________________________
 
 import sys
-assert __version__ == "1.4.0", ("This test_c.py file is for testing a version"
+assert __version__ == "1.4.2", ("This test_c.py file is for testing a version"
                                 " of cffi that differs from the one that we"
                                 " get from 'import _cffi_backend'")
 if sys.version_info < (3,):
diff --git a/pypy/module/_file/test/test_large_file.py 
b/pypy/module/_file/test/test_large_file.py
--- a/pypy/module/_file/test/test_large_file.py
+++ b/pypy/module/_file/test/test_large_file.py
@@ -1,4 +1,4 @@
-import py
+import py, sys
 
 from pypy.module._file.test.test_file import getfile
 
@@ -13,6 +13,12 @@
     def setup_method(self, meth):
         if getattr(meth, 'need_sparse_files', False):
             from rpython.translator.c.test.test_extfunc import 
need_sparse_files
+            if sys.maxsize < 2**32 and not self.runappdirect:
+                # this fails because it uses ll2ctypes to call the posix
+                # functions like 'open' and 'lseek', whereas a real compiled
+                # C program would macro-define them to their longlong versions
+                py.test.skip("emulation of files can't use "
+                             "larger-than-long offsets")
             need_sparse_files()
 
     def test_large_seek_offsets(self):
diff --git a/pypy/module/_socket/test/test_sock_app.py 
b/pypy/module/_socket/test/test_sock_app.py
--- a/pypy/module/_socket/test/test_sock_app.py
+++ b/pypy/module/_socket/test/test_sock_app.py
@@ -251,7 +251,7 @@
     from pypy.module._socket.interp_socket import addr_as_object
     if not hasattr(rsocket._c, 'sockaddr_ll'):
         py.test.skip("posix specific test")
-    # HACK: To get the correct interface numer of lo, which in most cases is 1,
+    # HACK: To get the correct interface number of lo, which in most cases is 
1,
     # but can be anything (i.e. 39), we need to call the libc function
     # if_nametoindex to get the correct index
     import ctypes
@@ -513,7 +513,7 @@
     def test_getsetsockopt(self):
         import _socket as socket
         import struct
-        # A socket sould start with reuse == 0
+        # A socket should start with reuse == 0
         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
         reuse = s.getsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR)
         assert reuse == 0
@@ -627,6 +627,26 @@
         self.foo = _socket.socket()
 
 
+class AppTestNetlink:
+    def setup_class(cls):
+        if not hasattr(os, 'getpid'):
+            py.test.skip("AF_NETLINK needs os.getpid()")
+        w_ok = space.appexec([], "(): import _socket; " +
+                                 "return hasattr(_socket, 'AF_NETLINK')")
+        if not space.is_true(w_ok):
+            py.test.skip("no AF_NETLINK on this platform")
+        cls.space = space
+
+    def test_connect_to_kernel_netlink_routing_socket(self):
+        import _socket, os
+        s = _socket.socket(_socket.AF_NETLINK, _socket.SOCK_DGRAM, 
_socket.NETLINK_ROUTE)
+        assert s.getsockname() == (0L, 0L)
+        s.bind((0, 0))
+        a, b = s.getsockname()
+        assert a == os.getpid()
+        assert b == 0
+ 
+
 class AppTestPacket:
     def setup_class(cls):
         if not hasattr(os, 'getuid') or os.getuid() != 0:
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -124,7 +124,7 @@
 METH_COEXIST METH_STATIC METH_CLASS
 METH_NOARGS METH_VARARGS METH_KEYWORDS METH_O
 Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS
-Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE
+Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_TPFLAGS_CHECKTYPES
 """.split()
 for name in constant_names:
     setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
diff --git a/pypy/module/cpyext/longobject.py b/pypy/module/cpyext/longobject.py
--- a/pypy/module/cpyext/longobject.py
+++ b/pypy/module/cpyext/longobject.py
@@ -228,26 +228,11 @@
 def _PyLong_FromByteArray(space, bytes, n, little_endian, signed):
     little_endian = rffi.cast(lltype.Signed, little_endian)
     signed = rffi.cast(lltype.Signed, signed)
-
-    result = rbigint()
-    negative = False
-
-    for i in range(0, n):
-        if little_endian:
-            c = intmask(bytes[i])
-        else:
-            c = intmask(bytes[n - i - 1])
-        if i == 0 and signed and c & 0x80:
-            negative = True
-        if negative:
-            c = c ^ 0xFF
-        digit = rbigint.fromint(c)
-
-        result = result.lshift(8)
-        result = result.add(digit)
-
-    if negative:
-        result = result.neg()
-
+    s = rffi.charpsize2str(rffi.cast(rffi.CCHARP, bytes),
+                           rffi.cast(lltype.Signed, n))
+    if little_endian:
+        byteorder = 'little'
+    else:
+        byteorder = 'big'
+    result = rbigint.frombytes(s, byteorder, signed != 0)
     return space.newlong_from_rbigint(result)
-
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -4,14 +4,14 @@
 
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (
-    cpython_api, generic_cpy_call, PyObject, Py_ssize_t)
+    cpython_api, generic_cpy_call, PyObject, Py_ssize_t, Py_TPFLAGS_CHECKTYPES)
 from pypy.module.cpyext.typeobjectdefs import (
     unaryfunc, wrapperfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc,
     getattrfunc, getattrofunc, setattrofunc, lenfunc, ssizeargfunc, inquiry,
     ssizessizeargfunc, ssizeobjargproc, iternextfunc, initproc, richcmpfunc,
     cmpfunc, hashfunc, descrgetfunc, descrsetfunc, objobjproc, objobjargproc,
     readbufferproc)
-from pypy.module.cpyext.pyobject import from_ref
+from pypy.module.cpyext.pyobject import from_ref, make_ref, Py_DecRef
 from pypy.module.cpyext.pyerrors import PyErr_Occurred
 from pypy.module.cpyext.state import State
 from pypy.interpreter.error import OperationError, oefmt
@@ -65,22 +65,24 @@
     func_binary = rffi.cast(binaryfunc, func)
     check_num_args(space, w_args, 1)
     args_w = space.fixedview(w_args)
-
-    if not space.is_true(space.issubtype(space.type(args_w[0]),
-                                         space.type(w_self))):
+    ref = make_ref(space, w_self)
+    if (not ref.c_ob_type.c_tp_flags & Py_TPFLAGS_CHECKTYPES and
+        not space.is_true(space.issubtype(space.type(args_w[0]),
+                                         space.type(w_self)))):
         return space.w_NotImplemented
- 
+    Py_DecRef(space, ref)
     return generic_cpy_call(space, func_binary, w_self, args_w[0])
 
 def wrap_binaryfunc_r(space, w_self, w_args, func):
     func_binary = rffi.cast(binaryfunc, func)
     check_num_args(space, w_args, 1)
     args_w = space.fixedview(w_args)
-
-    if not space.is_true(space.issubtype(space.type(args_w[0]),
-                                         space.type(w_self))):
+    ref = make_ref(space, w_self)
+    if (not ref.c_ob_type.c_tp_flags & Py_TPFLAGS_CHECKTYPES and
+        not space.is_true(space.issubtype(space.type(args_w[0]),
+                                         space.type(w_self)))):
         return space.w_NotImplemented
-
+    Py_DecRef(space, ref)
     return generic_cpy_call(space, func_binary, args_w[0], w_self)
 
 def wrap_inquirypred(space, w_self, w_args, func):
@@ -378,6 +380,17 @@
                 space.call_function(delattr_fn, w_self, w_name)
             return 0
         api_func = slot_tp_setattro.api_func
+    elif name == 'tp_getattro':
+        getattr_fn = w_type.getdictvalue(space, '__getattribute__')
+        if getattr_fn is None:
+            return
+
+        @cpython_api([PyObject, PyObject], PyObject,
+                     external=True)
+        @func_renamer("cpyext_tp_getattro_%s" % (typedef.name,))
+        def slot_tp_getattro(space, w_self, w_name):
+            return space.call_function(getattr_fn, w_self, w_name)
+        api_func = slot_tp_getattro.api_func
     else:
         return
 
diff --git a/pypy/module/cpyext/test/test_longobject.py 
b/pypy/module/cpyext/test/test_longobject.py
--- a/pypy/module/cpyext/test/test_longobject.py
+++ b/pypy/module/cpyext/test/test_longobject.py
@@ -175,10 +175,26 @@
                                               little_endian, is_signed);
              """),
             ])
-        assert module.from_bytearray(True, False) == 0x9ABC
-        assert module.from_bytearray(True, True) == -0x6543
-        assert module.from_bytearray(False, False) == 0xBC9A
-        assert module.from_bytearray(False, True) == -0x4365
+        assert module.from_bytearray(True, False) == 0xBC9A
+        assert module.from_bytearray(True, True) == -0x4366
+        assert module.from_bytearray(False, False) == 0x9ABC
+        assert module.from_bytearray(False, True) == -0x6544
+
+    def test_frombytearray_2(self):
+        module = self.import_extension('foo', [
+            ("from_bytearray", "METH_VARARGS",
+             """
+                 int little_endian, is_signed;
+                 if (!PyArg_ParseTuple(args, "ii", &little_endian, &is_signed))
+                     return NULL;
+                 return _PyLong_FromByteArray("\x9A\xBC\x41", 3,
+                                              little_endian, is_signed);
+             """),
+            ])
+        assert module.from_bytearray(True, False) == 0x41BC9A
+        assert module.from_bytearray(True, True) == 0x41BC9A
+        assert module.from_bytearray(False, False) == 0x9ABC41
+        assert module.from_bytearray(False, True) == -0x6543BF
 
     def test_fromunicode(self):
         module = self.import_extension('foo', [
diff --git a/pypy/module/cpyext/test/test_typeobject.py 
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -385,12 +385,64 @@
                      PyErr_SetString(PyExc_ValueError, "recursive 
tp_setattro");
                      return NULL;
                  }
+                 if (!args->ob_type->tp_getattro)
+                 {
+                     PyErr_SetString(PyExc_ValueError, "missing tp_getattro");
+                     return NULL;
+                 }
+                 if (args->ob_type->tp_getattro ==
+                     args->ob_type->tp_base->tp_getattro)
+                 {
+                     PyErr_SetString(PyExc_ValueError, "recursive 
tp_getattro");
+                     return NULL;
+                 }
                  Py_RETURN_TRUE;
              '''
              )
             ])
         assert module.test_type(type(None))
 
+    def test_tp_getattro(self):
+        module = self.import_extension('foo', [
+            ("test_tp_getattro", "METH_VARARGS",
+             '''
+                 PyObject *obj = PyTuple_GET_ITEM(args, 0);
+                 PyIntObject *value = PyTuple_GET_ITEM(args, 1);
+                 if (!obj->ob_type->tp_getattro)
+                 {
+                     PyErr_SetString(PyExc_ValueError, "missing tp_getattro");
+                     return NULL;
+                 }
+                 PyObject *name = PyString_FromString("attr1");
+                 PyIntObject *attr = obj->ob_type->tp_getattro(obj, name);
+                 if (attr->ob_ival != value->ob_ival)
+                 {
+                     PyErr_SetString(PyExc_ValueError,
+                                     "tp_getattro returned wrong value");
+                     return NULL;
+                 }
+                 Py_DECREF(name);
+                 Py_DECREF(attr);
+                 name = PyString_FromString("attr2");
+                 attr = obj->ob_type->tp_getattro(obj, name);
+                 if (attr == NULL && 
PyErr_ExceptionMatches(PyExc_AttributeError))
+                 {
+                     PyErr_Clear();
+                 } else {
+                     PyErr_SetString(PyExc_ValueError,
+                                     "tp_getattro should have raised");
+                     return NULL;
+                 }
+                 Py_DECREF(name);
+                 Py_RETURN_TRUE;
+             '''
+             )
+            ])
+        class C:
+            def __init__(self):
+                self.attr1 = 123
+        assert module.test_tp_getattro(C(), 123)
+
     def test_nb_int(self):
         module = self.import_extension('foo', [
             ("nb_int", "METH_O",
@@ -591,45 +643,92 @@
 
     def test_binaryfunc(self):
         module = self.import_extension('foo', [
-            ("new_obj", "METH_NOARGS",
+            ("newInt", "METH_VARARGS",
              """
-                FooObject *fooObj;
+                IntLikeObject *intObj;
+                long intval;
 
-                Foo_Type.tp_as_number = &foo_as_number;
-                foo_as_number.nb_add = foo_nb_add_call;
-                if (PyType_Ready(&Foo_Type) < 0) return NULL;
-                fooObj = PyObject_New(FooObject, &Foo_Type);
-                if (!fooObj) {
+                if (!PyArg_ParseTuple(args, "l", &intval))
+                    return NULL;
+
+                IntLike_Type.tp_as_number = &intlike_as_number;
+                IntLike_Type.tp_flags |= Py_TPFLAGS_CHECKTYPES;
+                intlike_as_number.nb_add = intlike_nb_add;
+                if (PyType_Ready(&IntLike_Type) < 0) return NULL;
+                intObj = PyObject_New(IntLikeObject, &IntLike_Type);
+                if (!intObj) {
                     return NULL;
                 }
 
-                return (PyObject *)fooObj;
+                intObj->ival = intval;
+                return (PyObject *)intObj;
+             """),
+             ("newIntNoOp", "METH_VARARGS",
+             """
+                IntLikeObjectNoOp *intObjNoOp;
+                long intval;
+
+                if (!PyArg_ParseTuple(args, "l", &intval))
+                    return NULL;
+
+                IntLike_Type_NoOp.tp_flags |= Py_TPFLAGS_CHECKTYPES;
+                if (PyType_Ready(&IntLike_Type_NoOp) < 0) return NULL;
+                intObjNoOp = PyObject_New(IntLikeObjectNoOp, 
&IntLike_Type_NoOp);
+                if (!intObjNoOp) {
+                    return NULL;
+                }
+
+                intObjNoOp->ival = intval;
+                return (PyObject *)intObjNoOp;
              """)],
             """
             typedef struct
             {
                 PyObject_HEAD
-            } FooObject;
+                long ival;
+            } IntLikeObject;
 
             static PyObject * 
-            foo_nb_add_call(PyObject *self, PyObject *other)
+            intlike_nb_add(PyObject *self, PyObject *other)
             {
-                return PyInt_FromLong(42); 
+                long val1 = ((IntLikeObject *)(self))->ival;
+                if (PyInt_Check(other)) {
+                  long val2 = PyInt_AsLong(other);
+                  return PyInt_FromLong(val1+val2);
+                }
+
+                long val2 = ((IntLikeObject *)(other))->ival;
+                return PyInt_FromLong(val1+val2);
             }
 
-            PyTypeObject Foo_Type = {
+            PyTypeObject IntLike_Type = {
                 PyObject_HEAD_INIT(0)
                 /*ob_size*/             0,
-                /*tp_name*/             "Foo",
-                /*tp_basicsize*/        sizeof(FooObject),
+                /*tp_name*/             "IntLike",
+                /*tp_basicsize*/        sizeof(IntLikeObject),
             };
-            static PyNumberMethods foo_as_number;
+            static PyNumberMethods intlike_as_number;
+
+            typedef struct
+            {
+                PyObject_HEAD
+                long ival;
+            } IntLikeObjectNoOp;
+
+            PyTypeObject IntLike_Type_NoOp = {
+                PyObject_HEAD_INIT(0)
+                /*ob_size*/             0,
+                /*tp_name*/             "IntLikeNoOp",
+                /*tp_basicsize*/        sizeof(IntLikeObjectNoOp),
+            };
             """)
-        a = module.new_obj()
-        b = module.new_obj() 
+        a = module.newInt(1)
+        b = module.newInt(2)
         c = 3
-        assert (a + b) == 42 
-        raises(TypeError, "b + c")
+        d = module.newIntNoOp(4)
+        assert (a + b) == 3
+        assert (b + c) == 5
+        assert (d + a) == 5
 
     def test_tp_new_in_subclass_of_type(self):
         skip("BROKEN")
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -582,6 +582,8 @@
             pto.c_tp_free = base.c_tp_free
         if not pto.c_tp_setattro:
             pto.c_tp_setattro = base.c_tp_setattro
+        if not pto.c_tp_getattro:
+            pto.c_tp_getattro = base.c_tp_getattro
     finally:
         Py_DecRef(space, base_pyo)
 
@@ -651,6 +653,12 @@
             PyObject_GenericSetAttr.api_func.functype,
             PyObject_GenericSetAttr.api_func.get_wrapper(space))
 
+    if not pto.c_tp_getattro:
+        from pypy.module.cpyext.object import PyObject_GenericGetAttr
+        pto.c_tp_getattro = llhelper(
+            PyObject_GenericGetAttr.api_func.functype,
+            PyObject_GenericGetAttr.api_func.get_wrapper(space))
+
     if w_obj.is_cpytype():
         Py_DecRef(space, pto.c_tp_dict)
         w_dict = w_obj.getdict(space)
diff --git a/pypy/module/mmap/test/test_mmap.py 
b/pypy/module/mmap/test/test_mmap.py
--- a/pypy/module/mmap/test/test_mmap.py
+++ b/pypy/module/mmap/test/test_mmap.py
@@ -1,6 +1,6 @@
 from __future__ import with_statement
 from rpython.tool.udir import udir
-import os
+import os, sys, py
 
 class AppTestMMap:
     spaceconfig = dict(usemodules=('mmap',))
@@ -8,6 +8,15 @@
     def setup_class(cls):
         cls.w_tmpname = cls.space.wrap(str(udir.join('mmap-')))
 
+    def setup_method(self, meth):
+        if getattr(meth, 'is_large', False):
+            if sys.maxsize < 2**32 and not self.runappdirect:
+                # this fails because it uses ll2ctypes to call the posix
+                # functions like 'open' and 'lseek', whereas a real compiled
+                # C program would macro-define them to their longlong versions
+                py.test.skip("emulation of files can't use "
+                             "larger-than-long offsets")
+
     def test_page_size(self):
         import mmap
         assert mmap.PAGESIZE > 0
@@ -648,6 +657,7 @@
                 assert m[0xFFFFFFF] == b'A'
             finally:
                 m.close()
+    test_large_offset.is_large = True
 
     def test_large_filesize(self):
         import mmap
@@ -665,6 +675,7 @@
                 assert m.size() ==  0x180000000
             finally:
                 m.close()
+    test_large_filesize.is_large = True
 
     def test_all(self):
         # this is a global test, ported from test_mmap.py
diff --git a/pypy/module/posix/interp_posix.py 
b/pypy/module/posix/interp_posix.py
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -299,7 +299,7 @@
         return build_stat_result(space, st)
 
 def lstat(space, w_path):
-    "Like stat(path), but do no follow symbolic links."
+    "Like stat(path), but do not follow symbolic links."
     try:
         st = dispatch_filename(rposix_stat.lstat)(space, w_path)
     except OSError, e:
diff --git a/pypy/module/posix/test/test_posix2.py 
b/pypy/module/posix/test/test_posix2.py
--- a/pypy/module/posix/test/test_posix2.py
+++ b/pypy/module/posix/test/test_posix2.py
@@ -93,6 +93,12 @@
 
     def setup_method(self, meth):
         if getattr(meth, 'need_sparse_files', False):
+            if sys.maxsize < 2**32 and not self.runappdirect:
+                # this fails because it uses ll2ctypes to call the posix
+                # functions like 'open' and 'lseek', whereas a real compiled
+                # C program would macro-define them to their longlong versions
+                py.test.skip("emulation of files can't use "
+                             "larger-than-long offsets")
             need_sparse_files()
 
     def test_posix_is_pypy_s(self):
diff --git a/pypy/module/pypyjit/test_pypy_c/test_struct.py 
b/pypy/module/pypyjit/test_pypy_c/test_struct.py
--- a/pypy/module/pypyjit/test_pypy_c/test_struct.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_struct.py
@@ -45,7 +45,7 @@
 
         # the newstr and the strsetitems are because the string is forced,
         # which is in turn because the optimizer doesn't know how to handle a
-        # getarrayitem_gc_i on a virtual string. It could be improved, but it
+        # gc_load_indexed_i on a virtual string. It could be improved, but it
         # is also true that in real life cases struct.unpack is called on
         # strings which come from the outside, so it's a minor issue.
         assert loop.match_by_id("unpack", """
@@ -55,17 +55,17 @@
             strsetitem(p88, 1, i14)
             strsetitem(p88, 2, i17)
             strsetitem(p88, 3, i20)
-            i91 = getarrayitem_gc_i(p88, 0, descr=<ArrayS 4>)
+            i91 = gc_load_indexed_i(p88, 0, 1, _, -4)
         """)
 
     def test_struct_object(self):
         def main(n):
             import struct
-            s = struct.Struct("i")
+            s = struct.Struct("ii")
             i = 1
             while i < n:
-                buf = s.pack(i)       # ID: pack
-                x = s.unpack(buf)[0]  # ID: unpack
+                buf = s.pack(-1, i)     # ID: pack
+                x = s.unpack(buf)[1]    # ID: unpack
                 i += x / i
             return i
 
@@ -88,10 +88,15 @@
 
         assert loop.match_by_id('unpack', """
             # struct.unpack
-            p88 = newstr(4)
-            strsetitem(p88, 0, i11)
-            strsetitem(p88, 1, i14)
-            strsetitem(p88, 2, i17)
-            strsetitem(p88, 3, i20)
-            i91 = getarrayitem_gc_i(p88, 0, descr=<ArrayS 4>)
+            p88 = newstr(8)
+            strsetitem(p88, 0, 255)
+            strsetitem(p88, 1, 255)
+            strsetitem(p88, 2, 255)
+            strsetitem(p88, 3, 255)
+            strsetitem(p88, 4, i11)
+            strsetitem(p88, 5, i14)
+            strsetitem(p88, 6, i17)
+            strsetitem(p88, 7, i20)
+            i90 = gc_load_indexed_i(p88, 0, 1, _, -4)
+            i91 = gc_load_indexed_i(p88, 4, 1, _, -4)
         """)
diff --git a/pypy/module/thread/__init__.py b/pypy/module/thread/__init__.py
--- a/pypy/module/thread/__init__.py
+++ b/pypy/module/thread/__init__.py
@@ -30,7 +30,7 @@
             space.threadlocals = stm.STMThreadLocals()
         else:
             from pypy.module.thread import gil
-            space.threadlocals = gil.GILThreadLocals()
+            space.threadlocals = gil.GILThreadLocals(space)
         space.threadlocals.initialize(space)
         if prev_ec is not None:
             space.threadlocals._set_ec(prev_ec)
diff --git a/pypy/module/thread/test/test_gil.py 
b/pypy/module/thread/test/test_gil.py
--- a/pypy/module/thread/test/test_gil.py
+++ b/pypy/module/thread/test/test_gil.py
@@ -65,7 +65,7 @@
             except Exception, e:
                 assert 0
             thread.gc_thread_die()
-        my_gil_threadlocals = gil.GILThreadLocals()
+        my_gil_threadlocals = gil.GILThreadLocals(space)
         def f():
             state.data = []
             state.datalen1 = 0
diff --git a/pypy/module/thread/threadlocals.py 
b/pypy/module/thread/threadlocals.py
--- a/pypy/module/thread/threadlocals.py
+++ b/pypy/module/thread/threadlocals.py
@@ -1,5 +1,7 @@
-from rpython.rlib import rthread
+import weakref
+from rpython.rlib import rthread, rshrinklist
 from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.rarithmetic import r_ulonglong
 from pypy.module.thread.error import wrap_thread_error
 from pypy.interpreter.executioncontext import ExecutionContext
 
@@ -13,15 +15,51 @@
     a thread finishes.  This works as long as the thread was started by
     os_thread.bootstrap()."""
 
-    def __init__(self):
+    def __init__(self, space):
         "NOT_RPYTHON"
-        self._valuedict = {}   # {thread_ident: ExecutionContext()}
+        #
+        # This object tracks code that enters and leaves threads.
+        # There are two APIs.  For Python-level threads, we know when
+        # the thread starts and ends, and we call enter_thread() and
+        # leave_thread().  In a few other cases, like callbacks, we
+        # might be running in some never-seen-before thread: in this
+        # case, the callback logic needs to call try_enter_thread() at
+        # the start, and if this returns True it needs to call
+        # leave_thread() at the end.
+        #
+        # We implement an optimization for the second case (which only
+        # works if we translate with a framework GC and with
+        # rweakref).  If try_enter_thread() is called in a
+        # never-seen-before thread, it still returns False and
+        # remembers the ExecutionContext with 'self._weaklist'.  The
+        # next time we call try_enter_thread() again in the same
+        # thread, the ExecutionContext is reused.  The optimization is
+        # not completely invisible to the user: 'thread._local()'
+        # values will remain.  We can argue that it is the correct
+        # behavior to do that, and the behavior we get if the
+        # optimization is disabled is buggy (but hard to do better
+        # then).
+        #
+        # 'self._valuedict' is a dict mapping the thread idents to
+        # ExecutionContexts; it does not list the ExecutionContexts
+        # which are in 'self._weaklist'.  (The latter is more precisely
+        # a list of AutoFreeECWrapper objects, defined below, which
+        # each references the ExecutionContext.)
+        #
+        self.space = space
+        self._valuedict = {}
         self._cleanup_()
         self.raw_thread_local = rthread.ThreadLocalReference(ExecutionContext,
                                                             
loop_invariant=True)
 
+    def can_optimize_with_weaklist(self):
+        config = self.space.config
+        return (config.translation.rweakref and
+                rthread.ThreadLocalReference.automatic_keepalive(config))
+
     def _cleanup_(self):
         self._valuedict.clear()
+        self._weaklist = None
         self._mainthreadident = 0
 
     def initialize(self, space):
@@ -35,19 +73,35 @@
         self._set_ec(space.createexecutioncontext())
 
     def try_enter_thread(self, space):
-        if rthread.get_ident() in self._valuedict:
+        # common case: the thread-local has already got a value
+        if self.raw_thread_local.get() is not None:
             return False
-        self.enter_thread(space)
-        return True
 
-    def _set_ec(self, ec):
+        # Else, make and attach a new ExecutionContext
+        ec = space.createexecutioncontext()
+        if not self.can_optimize_with_weaklist():
+            self._set_ec(ec)
+            return True
+
+        # If can_optimize_with_weaklist(), then 'rthread' keeps the
+        # thread-local values alive until the end of the thread.  Use
+        # AutoFreeECWrapper as an object with a __del__; when this
+        # __del__ is called, it means the thread was really finished.
+        # In this case we don't want leave_thread() to be called
+        # explicitly, so we return False.
+        if self._weaklist is None:
+            self._weaklist = ListECWrappers()
+        self._weaklist.append(weakref.ref(AutoFreeECWrapper(ec)))
+        self._set_ec(ec, register_in_valuedict=False)
+        return False
+
+    def _set_ec(self, ec, register_in_valuedict=True):
         ident = rthread.get_ident()
         if self._mainthreadident == 0 or self._mainthreadident == ident:
             ec._signals_enabled = 1    # the main thread is enabled
             self._mainthreadident = ident
-        self._valuedict[ident] = ec
-        # This logic relies on hacks and _make_sure_does_not_move().
-        # It only works because we keep the 'ec' alive in '_valuedict' too.
+        if register_in_valuedict:
+            self._valuedict[ident] = ec
         self.raw_thread_local.set(ec)
 
     def leave_thread(self, space):
@@ -90,7 +144,23 @@
         ec._signals_enabled = new
 
     def getallvalues(self):
-        return self._valuedict
+        if self._weaklist is None:
+            return self._valuedict
+        # This logic walks the 'self._weaklist' list and adds the
+        # ExecutionContexts to 'result'.  We are careful in case there
+        # are two AutoFreeECWrappers in the list which have the same
+        # 'ident'; in this case we must keep the most recent one (the
+        # older one should be deleted soon).  Moreover, entries in
+        # self._valuedict have priority because they are never
+        # outdated.
+        result = {}
+        for h in self._weaklist.items():
+            wrapper = h()
+            if wrapper is not None and not wrapper.deleted:
+                result[wrapper.ident] = wrapper.ec
+                # ^^ this possibly overwrites an older ec
+        result.update(self._valuedict)
+        return result
 
     def reinit_threads(self, space):
         "Called in the child process after a fork()"
@@ -100,7 +170,31 @@
         old_sig = ec._signals_enabled
         if ident != self._mainthreadident:
             old_sig += 1
-        self._cleanup_()
+        self._cleanup_()      # clears self._valuedict
         self._mainthreadident = ident
         self._set_ec(ec)
         ec._signals_enabled = old_sig
+
+
+class AutoFreeECWrapper(object):
+    deleted = False
+
+    def __init__(self, ec):
+        # this makes a loop between 'self' and 'ec'.  It should not prevent
+        # the __del__ method here from being called.
+        self.ec = ec
+        ec._threadlocals_auto_free = self
+        self.ident = rthread.get_ident()
+
+    def __del__(self):
+        from pypy.module.thread.os_local import thread_is_stopping
+        # this is always called in another thread: the thread
+        # referenced by 'self.ec' has finished at that point, and
+        # we're just after the GC which finds no more references to
+        # 'ec' (and thus to 'self').
+        self.deleted = True
+        thread_is_stopping(self.ec)
+
+class ListECWrappers(rshrinklist.AbstractShrinkList):
+    def must_keep(self, wref):
+        return wref() is not None
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
@@ -521,7 +521,6 @@
 
     def descr_getitem(self, space, w_index):
         if isinstance(w_index, W_SliceObject):
-            # XXX consider to extend rlist's functionality?
             length = self.length()
             start, stop, step, slicelength = w_index.indices4(space, length)
             assert slicelength >= 0
diff --git a/pypy/objspace/std/test/test_longobject.py 
b/pypy/objspace/std/test/test_longobject.py
--- a/pypy/objspace/std/test/test_longobject.py
+++ b/pypy/objspace/std/test/test_longobject.py
@@ -358,3 +358,10 @@
         assert 3L.__coerce__(4L) == (3L, 4L)
         assert 3L.__coerce__(4) == (3, 4)
         assert 3L.__coerce__(object()) == NotImplemented
+
+    def test_linear_long_base_16(self):
+        # never finishes if long(_, 16) is not linear-time
+        size = 100000
+        n = "a" * size
+        expected = (2 << (size * 4)) // 3
+        assert long(n, 16) == expected
diff --git a/rpython/annotator/signature.py b/rpython/annotator/signature.py
--- a/rpython/annotator/signature.py
+++ b/rpython/annotator/signature.py
@@ -100,6 +100,7 @@
         self.argtypes = argtypes
 
     def __call__(self, funcdesc, inputcells):
+        from rpython.rlib.objectmodel import NOT_CONSTANT
         from rpython.rtyper.lltypesystem import lltype
         args_s = []
         from rpython.annotator import model as annmodel
@@ -115,6 +116,9 @@
                 args_s.append(s_input)
             elif argtype is None:
                 args_s.append(inputcells[i])     # no change
+            elif argtype is NOT_CONSTANT:
+                from rpython.annotator.model import not_const
+                args_s.append(not_const(inputcells[i]))
             else:
                 args_s.append(annotation(argtype, 
bookkeeper=funcdesc.bookkeeper))
         if len(inputcells) != len(args_s):
diff --git a/rpython/annotator/test/test_annrpython.py 
b/rpython/annotator/test/test_annrpython.py
--- a/rpython/annotator/test/test_annrpython.py
+++ b/rpython/annotator/test/test_annrpython.py
@@ -3516,6 +3516,32 @@
         s = a.build_types(f, [unicode])
         assert isinstance(s, annmodel.SomeUnicodeString)
 
+    def test_extended_slice(self):
+        a = self.RPythonAnnotator()
+        def f(start, end, step):
+            return [1, 2, 3][start:end:step]
+        with py.test.raises(AnnotatorError):
+            a.build_types(f, [int, int, int])
+        a = self.RPythonAnnotator()
+        with py.test.raises(AnnotatorError):
+            a.build_types(f, [annmodel.SomeInteger(nonneg=True),
+                              annmodel.SomeInteger(nonneg=True),
+                              annmodel.SomeInteger(nonneg=True)])
+        def f(x):
+            return x[::-1]
+        a = self.RPythonAnnotator()
+        with py.test.raises(AnnotatorError):
+            a.build_types(f, [str])
+        def f(x):
+            return x[::2]
+        a = self.RPythonAnnotator()
+        with py.test.raises(AnnotatorError):
+            a.build_types(f, [str])
+        def f(x):
+            return x[1:2:1]
+        a = self.RPythonAnnotator()
+        with py.test.raises(AnnotatorError):
+            a.build_types(f, [str])
 
     def test_negative_slice(self):
         def f(s, e):
diff --git a/rpython/annotator/unaryop.py b/rpython/annotator/unaryop.py
--- a/rpython/annotator/unaryop.py
+++ b/rpython/annotator/unaryop.py
@@ -441,7 +441,7 @@
 def dict_contains(s_dct, s_element, position):
     s_dct.dictdef.generalize_key(s_element)
     if s_dct._is_empty(position):
-        s_bool =SomeBool()
+        s_bool = SomeBool()
         s_bool.const = False
         return s_bool
     return s_Bool
diff --git a/rpython/flowspace/operation.py b/rpython/flowspace/operation.py
--- a/rpython/flowspace/operation.py
+++ b/rpython/flowspace/operation.py
@@ -1,5 +1,5 @@
 """
-This module defines all the SpaceOeprations used in rpython.flowspace.
+This module defines all the SpaceOperations used in rpython.flowspace.
 """
 
 import __builtin__
@@ -196,21 +196,6 @@
             return cls._dispatch(type(s_arg))
 
     @classmethod
-    def get_specialization(cls, s_arg, *_ignored):
-        try:
-            impl = getattr(s_arg, cls.opname)
-
-            def specialized(annotator, arg, *other_args):
-                return impl(*[annotator.annotation(x) for x in other_args])
-            try:
-                specialized.can_only_throw = impl.can_only_throw
-            except AttributeError:
-                pass
-            return specialized
-        except AttributeError:
-            return cls._dispatch(type(s_arg))
-
-    @classmethod
     def register_transform(cls, Some_cls):
         def decorator(func):
             cls._transform[Some_cls] = func
@@ -523,6 +508,14 @@
                 *[annotator.annotation(arg) for arg in self.args])
 
 
+class NewSlice(HLOperation):
+    opname = 'newslice'
+    canraise = []
+
+    def consider(self, annotator):
+        raise AnnotatorError("Cannot use extended slicing in rpython")
+
+
 class Pow(PureOperation):
     opname = 'pow'
     arity = 3
diff --git a/rpython/jit/backend/arm/opassembler.py 
b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -19,7 +19,6 @@
 from rpython.jit.backend.arm.locations import imm, RawSPStackLocation
 from rpython.jit.backend.llsupport import symbolic
 from rpython.jit.backend.llsupport.gcmap import allocate_gcmap
-from rpython.jit.backend.llsupport.descr import InteriorFieldDescr
 from rpython.jit.backend.llsupport.assembler import GuardToken, BaseAssembler
 from rpython.jit.backend.llsupport.regalloc import get_scale
 from rpython.jit.metainterp.history import (AbstractFailDescr, ConstInt,
@@ -655,31 +654,24 @@
         pmc.B_offs(offset, c.EQ)
         return fcond
 
-    def emit_op_setfield_gc(self, op, arglocs, regalloc, fcond):
-        value_loc, base_loc, ofs, size = arglocs
-        scale = get_scale(size.value)
-        self._write_to_mem(value_loc, base_loc,
-                                ofs, imm(scale), fcond)
+    def emit_op_gc_store(self, op, arglocs, regalloc, fcond):
+        value_loc, base_loc, ofs_loc, size_loc = arglocs
+        scale = get_scale(size_loc.value)
+        self._write_to_mem(value_loc, base_loc, ofs_loc, imm(scale), fcond)
         return fcond
 
-    emit_op_setfield_raw = emit_op_setfield_gc
-    emit_op_zero_ptr_field = emit_op_setfield_gc
-
-    def _genop_getfield(self, op, arglocs, regalloc, fcond):
-        base_loc, ofs, res, size = arglocs
-        signed = op.getdescr().is_field_signed()
-        scale = get_scale(size.value)
-        self._load_from_mem(res, base_loc, ofs, imm(scale), signed, fcond)
+    def _emit_op_gc_load(self, op, arglocs, regalloc, fcond):
+        base_loc, ofs_loc, res_loc, nsize_loc = arglocs
+        nsize = nsize_loc.value
+        signed = (nsize < 0)
+        scale = get_scale(abs(nsize))
+        self._load_from_mem(res_loc, base_loc, ofs_loc, imm(scale),
+                            signed, fcond)
         return fcond
 
-    emit_op_getfield_gc_i = _genop_getfield
-    emit_op_getfield_gc_r = _genop_getfield
-    emit_op_getfield_gc_f = _genop_getfield
-    emit_op_getfield_gc_pure_i = _genop_getfield
-    emit_op_getfield_gc_pure_r = _genop_getfield
-    emit_op_getfield_gc_pure_f = _genop_getfield
-    emit_op_getfield_raw_i = _genop_getfield
-    emit_op_getfield_raw_f = _genop_getfield
+    emit_op_gc_load_i = _emit_op_gc_load
+    emit_op_gc_load_r = _emit_op_gc_load
+    emit_op_gc_load_f = _emit_op_gc_load
 
     def emit_op_increment_debug_counter(self, op, arglocs, regalloc, fcond):
         base_loc, value_loc = arglocs
@@ -688,68 +680,21 @@
         self.mc.STR_ri(value_loc.value, base_loc.value, 0, cond=fcond)
         return fcond
 
-    def _genop_getinteriorfield(self, op, arglocs, regalloc, fcond):
-        (base_loc, index_loc, res_loc,
-            ofs_loc, ofs, itemsize, fieldsize) = arglocs
-        scale = get_scale(fieldsize.value)
-        tmploc, save = self.get_tmp_reg([base_loc, ofs_loc])
-        assert not save
-        self.mc.gen_load_int(tmploc.value, itemsize.value)
-        self.mc.MUL(tmploc.value, index_loc.value, tmploc.value)
-        descr = op.getdescr()
-        assert isinstance(descr, InteriorFieldDescr)
-        signed = descr.fielddescr.is_field_signed()
-        if ofs.value > 0:
-            if ofs_loc.is_imm():
-                self.mc.ADD_ri(tmploc.value, tmploc.value, ofs_loc.value)
-            else:
-                self.mc.ADD_rr(tmploc.value, tmploc.value, ofs_loc.value)
-        ofs_loc = tmploc
-        self._load_from_mem(res_loc, base_loc, ofs_loc,
-                                imm(scale), signed, fcond)
-        return fcond
-
-    emit_op_getinteriorfield_gc_i = _genop_getinteriorfield
-    emit_op_getinteriorfield_gc_r = _genop_getinteriorfield
-    emit_op_getinteriorfield_gc_f = _genop_getinteriorfield
-
-    def emit_op_setinteriorfield_gc(self, op, arglocs, regalloc, fcond):
-        (base_loc, index_loc, value_loc,
-            ofs_loc, ofs, itemsize, fieldsize) = arglocs
-        scale = get_scale(fieldsize.value)
-        tmploc, save = self.get_tmp_reg([base_loc, index_loc, value_loc, 
ofs_loc])
-        assert not save
-        self.mc.gen_load_int(tmploc.value, itemsize.value)
-        self.mc.MUL(tmploc.value, index_loc.value, tmploc.value)
-        if ofs.value > 0:
-            if ofs_loc.is_imm():
-                self.mc.ADD_ri(tmploc.value, tmploc.value, ofs_loc.value)
-            else:
-                self.mc.ADD_rr(tmploc.value, tmploc.value, ofs_loc.value)
-        self._write_to_mem(value_loc, base_loc, tmploc, imm(scale), fcond)
-        return fcond
-    emit_op_setinteriorfield_raw = emit_op_setinteriorfield_gc
-
-    def emit_op_arraylen_gc(self, op, arglocs, regalloc, fcond):
-        res, base_loc, ofs = arglocs
-        self.load_reg(self.mc, res, base_loc, ofs.value)
-        return fcond
-
-    def emit_op_setarrayitem_gc(self, op, arglocs, regalloc, fcond):
-        value_loc, base_loc, ofs_loc, scale, ofs = arglocs
-        assert ofs_loc.is_core_reg()
-        if scale.value > 0:
-            self.mc.LSL_ri(r.ip.value, ofs_loc.value, scale.value)
-            ofs_loc = r.ip
-
+    def emit_op_gc_store_indexed(self, op, arglocs, regalloc, fcond):
+        value_loc, base_loc, index_loc, size_loc, ofs_loc = arglocs
+        assert index_loc.is_core_reg()
         # add the base offset
-        if ofs.value > 0:
-            self.mc.ADD_ri(r.ip.value, ofs_loc.value, imm=ofs.value)
-            ofs_loc = r.ip
-        self._write_to_mem(value_loc, base_loc, ofs_loc, scale, fcond)
+        if ofs_loc.value > 0:
+            self.mc.ADD_ri(r.ip.value, index_loc.value, imm=ofs_loc.value)
+            index_loc = r.ip
+        scale = get_scale(size_loc.value)
+        self._write_to_mem(value_loc, base_loc, index_loc, imm(scale), fcond)
         return fcond
 
     def _write_to_mem(self, value_loc, base_loc, ofs_loc, scale, fcond=c.AL):
+        # Write a value of size '1 << scale' at the address
+        # 'base_ofs + ofs_loc'.  Note that 'scale' is not used to scale
+        # the offset!
         if scale.value == 3:
             assert value_loc.is_vfp_reg()
             # vstr only supports imm offsets
@@ -789,43 +734,31 @@
         else:
             assert 0
 
-    emit_op_setarrayitem_raw = emit_op_setarrayitem_gc
-
-    def emit_op_raw_store(self, op, arglocs, regalloc, fcond):
-        value_loc, base_loc, ofs_loc, scale, ofs = arglocs
-        assert ofs_loc.is_core_reg()
-        self._write_to_mem(value_loc, base_loc, ofs_loc, scale, fcond)
+    def _emit_op_gc_load_indexed(self, op, arglocs, regalloc, fcond):
+        res_loc, base_loc, index_loc, nsize_loc, ofs_loc = arglocs
+        assert index_loc.is_core_reg()
+        nsize = nsize_loc.value
+        signed = (nsize < 0)
+        # add the base offset
+        if ofs_loc.value > 0:
+            self.mc.ADD_ri(r.ip.value, index_loc.value, imm=ofs_loc.value)
+            index_loc = r.ip
+        #
+        scale = get_scale(abs(nsize))
+        self._load_from_mem(res_loc, base_loc, index_loc, imm(scale),
+                            signed, fcond)
         return fcond
 
-    def _genop_getarrayitem(self, op, arglocs, regalloc, fcond):
-        res_loc, base_loc, ofs_loc, scale, ofs = arglocs
-        assert ofs_loc.is_core_reg()
-        signed = op.getdescr().is_item_signed()
-
-        # scale the offset as required
-        # XXX we should try to encode the scale inside the "shift" part of LDR
-        if scale.value > 0:
-            self.mc.LSL_ri(r.ip.value, ofs_loc.value, scale.value)
-            ofs_loc = r.ip
-        # add the base offset
-        if ofs.value > 0:
-            self.mc.ADD_ri(r.ip.value, ofs_loc.value, imm=ofs.value)
-            ofs_loc = r.ip
-        #
-        self._load_from_mem(res_loc, base_loc, ofs_loc, scale, signed, fcond)
-        return fcond
-
-    emit_op_getarrayitem_gc_i = _genop_getarrayitem
-    emit_op_getarrayitem_gc_r = _genop_getarrayitem
-    emit_op_getarrayitem_gc_f = _genop_getarrayitem
-    emit_op_getarrayitem_gc_pure_i = _genop_getarrayitem
-    emit_op_getarrayitem_gc_pure_r = _genop_getarrayitem
-    emit_op_getarrayitem_gc_pure_f = _genop_getarrayitem
-    emit_op_getarrayitem_raw_i = _genop_getarrayitem
-    emit_op_getarrayitem_raw_f = _genop_getarrayitem
+    emit_op_gc_load_indexed_i = _emit_op_gc_load_indexed
+    emit_op_gc_load_indexed_r = _emit_op_gc_load_indexed
+    emit_op_gc_load_indexed_f = _emit_op_gc_load_indexed
 
     def _load_from_mem(self, res_loc, base_loc, ofs_loc, scale,
                                             signed=False, fcond=c.AL):
+        # Load a value of '1 << scale' bytes, from the memory location
+        # 'base_loc + ofs_loc'.  Note that 'scale' is not used to scale
+        # the offset!
+        #
         if scale.value == 3:
             assert res_loc.is_vfp_reg()
             # vldr only supports imm offsets
@@ -881,51 +814,6 @@
         else:
             assert 0
 
-    def _genop_raw_load(self, op, arglocs, regalloc, fcond):
-        res_loc, base_loc, ofs_loc, scale, ofs = arglocs
-        assert ofs_loc.is_core_reg()
-        # no base offset
-        assert ofs.value == 0
-        signed = op.getdescr().is_item_signed()
-        self._load_from_mem(res_loc, base_loc, ofs_loc, scale, signed, fcond)
-        return fcond
-
-    emit_op_raw_load_i = _genop_raw_load
-    emit_op_raw_load_f = _genop_raw_load
-
-    def emit_op_strlen(self, op, arglocs, regalloc, fcond):
-        l0, l1, res = arglocs
-        if l1.is_imm():
-            self.mc.LDR_ri(res.value, l0.value, l1.getint(), cond=fcond)
-        else:
-            self.mc.LDR_rr(res.value, l0.value, l1.value, cond=fcond)
-        return fcond
-
-    def emit_op_strgetitem(self, op, arglocs, regalloc, fcond):
-        res, base_loc, ofs_loc, basesize = arglocs
-        if ofs_loc.is_imm():
-            self.mc.ADD_ri(r.ip.value, base_loc.value, ofs_loc.getint(),
-                                                                    cond=fcond)
-        else:
-            self.mc.ADD_rr(r.ip.value, base_loc.value, ofs_loc.value,
-                                                                    cond=fcond)
-
-        self.mc.LDRB_ri(res.value, r.ip.value, basesize.value, cond=fcond)
-        return fcond
-
-    def emit_op_strsetitem(self, op, arglocs, regalloc, fcond):
-        value_loc, base_loc, ofs_loc, basesize = arglocs
-        if ofs_loc.is_imm():
-            self.mc.ADD_ri(r.ip.value, base_loc.value, ofs_loc.getint(),
-                                                            cond=fcond)
-        else:
-            self.mc.ADD_rr(r.ip.value, base_loc.value, ofs_loc.value,
-                                                            cond=fcond)
-
-        self.mc.STRB_ri(value_loc.value, r.ip.value, basesize.value,
-                                                            cond=fcond)
-        return fcond
-
     #from ../x86/regalloc.py:928 ff.
     def emit_op_copystrcontent(self, op, arglocs, regalloc, fcond):
         assert len(arglocs) == 0
@@ -1016,35 +904,6 @@
         else:
             raise AssertionError("bad unicode item size")
 
-    emit_op_unicodelen = emit_op_strlen
-
-    def emit_op_unicodegetitem(self, op, arglocs, regalloc, fcond):
-        res, base_loc, ofs_loc, scale, basesize, itemsize = arglocs
-        self.mc.ADD_rr(r.ip.value, base_loc.value, ofs_loc.value, cond=fcond,
-                                        imm=scale.value, shifttype=shift.LSL)
-        if scale.value == 2:
-            self.mc.LDR_ri(res.value, r.ip.value, basesize.value, cond=fcond)
-        elif scale.value == 1:
-            self.mc.LDRH_ri(res.value, r.ip.value, basesize.value, cond=fcond)
-        else:
-            assert 0, itemsize.value
-        return fcond
-
-    def emit_op_unicodesetitem(self, op, arglocs, regalloc, fcond):
-        value_loc, base_loc, ofs_loc, scale, basesize, itemsize = arglocs
-        self.mc.ADD_rr(r.ip.value, base_loc.value, ofs_loc.value, cond=fcond,
-                                        imm=scale.value, shifttype=shift.LSL)
-        if scale.value == 2:
-            self.mc.STR_ri(value_loc.value, r.ip.value, basesize.value,
-                                                                    cond=fcond)
-        elif scale.value == 1:
-            self.mc.STRH_ri(value_loc.value, r.ip.value, basesize.value,
-                                                                    cond=fcond)
-        else:
-            assert 0, itemsize.value
-
-        return fcond
-
     def store_force_descr(self, op, fail_locs, frame_depth):
         pos = self.mc.currpos()
         guard_token = self.build_guard_token(op, frame_depth, fail_locs, pos, 
c.AL)
diff --git a/rpython/jit/backend/arm/regalloc.py 
b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -34,9 +34,6 @@
 from rpython.rtyper.lltypesystem import lltype, rffi, rstr, llmemory
 from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.jit.codewriter.effectinfo import EffectInfo
-from rpython.jit.backend.llsupport.descr import unpack_arraydescr
-from rpython.jit.backend.llsupport.descr import unpack_fielddescr
-from rpython.jit.backend.llsupport.descr import unpack_interiorfielddescr
 from rpython.rlib.rarithmetic import r_uint
 from rpython.jit.backend.llsupport.descr import CallDescr
 
@@ -802,15 +799,12 @@
                                  src_locations2, dst_locations2, vfptmploc)
         return []
 
-    def prepare_op_setfield_gc(self, op, fcond):
+    def prepare_op_gc_store(self, op, fcond):
         boxes = op.getarglist()
-        ofs, size, sign = unpack_fielddescr(op.getdescr())
-        return self._prepare_op_setfield(boxes, ofs, size)
-
-    def _prepare_op_setfield(self, boxes, ofs, size):
-        a0, a1 = boxes
-        base_loc = self.make_sure_var_in_reg(a0, boxes)
-        value_loc = self.make_sure_var_in_reg(a1, boxes)
+        base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
+        ofs = boxes[1].getint()
+        value_loc = self.make_sure_var_in_reg(boxes[2], boxes)
+        size = boxes[3].getint()
         ofs_size = default_imm_size if size < 8 else VMEM_imm_size
         if check_imm_arg(ofs, size=ofs_size):
             ofs_loc = imm(ofs)
@@ -819,19 +813,13 @@
             self.assembler.load(ofs_loc, imm(ofs))
         return [value_loc, base_loc, ofs_loc, imm(size)]
 
-    prepare_op_setfield_raw = prepare_op_setfield_gc
-
-    def prepare_op_zero_ptr_field(self, op, fcond):
+    def _prepare_op_gc_load(self, op, fcond):
         a0 = op.getarg(0)
         ofs = op.getarg(1).getint()
-        return self._prepare_op_setfield([a0, ConstInt(0)], ofs, WORD)
-
-    def _prepare_op_getfield(self, op, fcond):
-        a0 = op.getarg(0)
-        ofs, size, sign = unpack_fielddescr(op.getdescr())
+        nsize = op.getarg(2).getint()    # negative for "signed"
         base_loc = self.make_sure_var_in_reg(a0)
         immofs = imm(ofs)
-        ofs_size = default_imm_size if size < 8 else VMEM_imm_size
+        ofs_size = default_imm_size if abs(nsize) < 8 else VMEM_imm_size
         if check_imm_arg(ofs, size=ofs_size):
             ofs_loc = immofs
         else:
@@ -839,17 +827,12 @@
             self.assembler.load(ofs_loc, immofs)
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        res = self.force_allocate_reg(op)
-        return [base_loc, ofs_loc, res, imm(size)]
+        res_loc = self.force_allocate_reg(op)
+        return [base_loc, ofs_loc, res_loc, imm(nsize)]
 
-    prepare_op_getfield_gc_i = _prepare_op_getfield
-    prepare_op_getfield_gc_r = _prepare_op_getfield
-    prepare_op_getfield_gc_f = _prepare_op_getfield
-    prepare_op_getfield_raw_i = _prepare_op_getfield
-    prepare_op_getfield_raw_f = _prepare_op_getfield
-    prepare_op_getfield_gc_pure_i = _prepare_op_getfield
-    prepare_op_getfield_gc_pure_r = _prepare_op_getfield
-    prepare_op_getfield_gc_pure_f = _prepare_op_getfield
+    prepare_op_gc_load_i = _prepare_op_gc_load
+    prepare_op_gc_load_r = _prepare_op_gc_load
+    prepare_op_gc_load_f = _prepare_op_gc_load
 
     def prepare_op_increment_debug_counter(self, op, fcond):
         boxes = op.getarglist()
@@ -859,188 +842,38 @@
         self.free_temp_vars()
         return [base_loc, value_loc]
 
-    def _prepare_op_getinteriorfield(self, op, fcond):
-        t = unpack_interiorfielddescr(op.getdescr())
-        ofs, itemsize, fieldsize, sign = t
-        args = op.getarglist()
-        base_loc = self.make_sure_var_in_reg(op.getarg(0), args)
-        index_loc = self.make_sure_var_in_reg(op.getarg(1), args)
-        immofs = imm(ofs)
-        ofs_size = default_imm_size if fieldsize < 8 else VMEM_imm_size
-        if check_imm_arg(ofs, size=ofs_size):
-            ofs_loc = immofs
-        else:
-            ofs_loc = self.get_scratch_reg(INT, args)
-            self.assembler.load(ofs_loc, immofs)
+    def prepare_op_gc_store_indexed(self, op, fcond):
+        boxes = op.getarglist()
+        base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
+        value_loc = self.make_sure_var_in_reg(boxes[2], boxes)
+        index_loc = self.make_sure_var_in_reg(boxes[1], boxes)
+        assert boxes[3].getint() == 1    # scale
+        ofs = boxes[4].getint()
+        size = boxes[5].getint()
+        assert check_imm_arg(ofs)
+        return [value_loc, base_loc, index_loc, imm(size), imm(ofs)]
+
+    def _prepare_op_gc_load_indexed(self, op, fcond):
+        boxes = op.getarglist()
+        base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
+        index_loc = self.make_sure_var_in_reg(boxes[1], boxes)
+        assert boxes[2].getint() == 1    # scale
+        ofs = boxes[3].getint()
+        nsize = boxes[4].getint()
+        assert check_imm_arg(ofs)
         self.possibly_free_vars_for_op(op)
         self.free_temp_vars()
-        result_loc = self.force_allocate_reg(op)
-        return [base_loc, index_loc, result_loc, ofs_loc, imm(ofs),
-                                    imm(itemsize), imm(fieldsize)]
+        res_loc = self.force_allocate_reg(op)
+        return [res_loc, base_loc, index_loc, imm(nsize), imm(ofs)]
 
-    prepare_op_getinteriorfield_gc_i = _prepare_op_getinteriorfield
-    prepare_op_getinteriorfield_gc_r = _prepare_op_getinteriorfield
-    prepare_op_getinteriorfield_gc_f = _prepare_op_getinteriorfield
-
-    def prepare_op_setinteriorfield_gc(self, op, fcond):
-        t = unpack_interiorfielddescr(op.getdescr())
-        ofs, itemsize, fieldsize, sign = t
-        args = op.getarglist()
-        base_loc = self.make_sure_var_in_reg(op.getarg(0), args)
-        index_loc = self.make_sure_var_in_reg(op.getarg(1), args)
-        value_loc = self.make_sure_var_in_reg(op.getarg(2), args)
-        immofs = imm(ofs)
-        ofs_size = default_imm_size if fieldsize < 8 else VMEM_imm_size
-        if check_imm_arg(ofs, size=ofs_size):
-            ofs_loc = immofs
-        else:
-            ofs_loc = self.get_scratch_reg(INT, args)
-            self.assembler.load(ofs_loc, immofs)
-        return [base_loc, index_loc, value_loc, ofs_loc, imm(ofs),
-                                        imm(itemsize), imm(fieldsize)]
-    prepare_op_setinteriorfield_raw = prepare_op_setinteriorfield_gc
-
-    def prepare_op_arraylen_gc(self, op, fcond):
-        arraydescr = op.getdescr()
-        assert isinstance(arraydescr, ArrayDescr)
-        ofs = arraydescr.lendescr.offset
-        arg = op.getarg(0)
-        base_loc = self.make_sure_var_in_reg(arg)
-        self.possibly_free_vars_for_op(op)
-        self.free_temp_vars()
-        res = self.force_allocate_reg(op)
-        return [res, base_loc, imm(ofs)]
-
-    def prepare_op_setarrayitem_gc(self, op, fcond):
-        size, ofs, _ = unpack_arraydescr(op.getdescr())
-        scale = get_scale(size)
-        args = op.getarglist()
-        base_loc = self.make_sure_var_in_reg(args[0], args)
-        value_loc = self.make_sure_var_in_reg(args[2], args)
-        ofs_loc = self.make_sure_var_in_reg(args[1], args)
-        assert check_imm_arg(ofs)
-        return [value_loc, base_loc, ofs_loc, imm(scale), imm(ofs)]
-    prepare_op_setarrayitem_raw = prepare_op_setarrayitem_gc
-    prepare_op_raw_store = prepare_op_setarrayitem_gc
-
-    def _prepare_op_getarrayitem(self, op, fcond):
-        boxes = op.getarglist()
-        size, ofs, _ = unpack_arraydescr(op.getdescr())
-        scale = get_scale(size)
-        base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
-        ofs_loc = self.make_sure_var_in_reg(boxes[1], boxes)
-        self.possibly_free_vars_for_op(op)
-        self.free_temp_vars()
-        res = self.force_allocate_reg(op)
-        assert check_imm_arg(ofs)
-        return [res, base_loc, ofs_loc, imm(scale), imm(ofs)]
-
-    prepare_op_getarrayitem_gc_i = _prepare_op_getarrayitem
-    prepare_op_getarrayitem_gc_r = _prepare_op_getarrayitem
-    prepare_op_getarrayitem_gc_f = _prepare_op_getarrayitem
-    prepare_op_getarrayitem_raw_i = _prepare_op_getarrayitem
-    prepare_op_getarrayitem_raw_f = _prepare_op_getarrayitem
-    prepare_op_getarrayitem_gc_pure_i = _prepare_op_getarrayitem
-    prepare_op_getarrayitem_gc_pure_r = _prepare_op_getarrayitem
-    prepare_op_getarrayitem_gc_pure_f = _prepare_op_getarrayitem
-    prepare_op_raw_load_i = _prepare_op_getarrayitem
-    prepare_op_raw_load_f = _prepare_op_getarrayitem
-
-    def prepare_op_strlen(self, op, fcond):
-        args = op.getarglist()
-        l0 = self.make_sure_var_in_reg(op.getarg(0))
-        basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
-                                         self.cpu.translate_support_code)
-        immofs = imm(ofs_length)
-        if check_imm_arg(ofs_length):
-            l1 = immofs
-        else:
-            l1 = self.get_scratch_reg(INT, args)
-            self.assembler.load(l1, immofs)
-
-        self.possibly_free_vars_for_op(op)
-        self.free_temp_vars()
-
-        res = self.force_allocate_reg(op)
-        self.possibly_free_var(op)
-        return [l0, l1, res]
-
-    def prepare_op_strgetitem(self, op, fcond):
-        boxes = op.getarglist()
-        base_loc = self.make_sure_var_in_reg(boxes[0])
-
-        a1 = boxes[1]
-        imm_a1 = check_imm_box(a1)
-        if imm_a1:
-            ofs_loc = self.convert_to_imm(a1)
-        else:
-            ofs_loc = self.make_sure_var_in_reg(a1, boxes)
-
-        self.possibly_free_vars_for_op(op)
-        self.free_temp_vars()
-        res = self.force_allocate_reg(op)
-
-        basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
-                                         self.cpu.translate_support_code)
-        assert itemsize == 1
-        return [res, base_loc, ofs_loc, imm(basesize)]
-
-    def prepare_op_strsetitem(self, op, fcond):
-        boxes = op.getarglist()
-        base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
-        ofs_loc = self.make_sure_var_in_reg(boxes[1], boxes)
-        value_loc = self.make_sure_var_in_reg(boxes[2], boxes)
-        basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
-                                         self.cpu.translate_support_code)
-        assert itemsize == 1
-        return [value_loc, base_loc, ofs_loc, imm(basesize)]
+    prepare_op_gc_load_indexed_i = _prepare_op_gc_load_indexed
+    prepare_op_gc_load_indexed_r = _prepare_op_gc_load_indexed
+    prepare_op_gc_load_indexed_f = _prepare_op_gc_load_indexed
 
     prepare_op_copystrcontent = void
     prepare_op_copyunicodecontent = void
     prepare_op_zero_array = void
 
-    def prepare_op_unicodelen(self, op, fcond):
-        l0 = self.make_sure_var_in_reg(op.getarg(0))
-        basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
-                                         self.cpu.translate_support_code)
-        immofs = imm(ofs_length)
-        if check_imm_arg(ofs_length):
-            l1 = immofs
-        else:
-            l1 = self.get_scratch_reg(INT, [op.getarg(0)])
-            self.assembler.load(l1, immofs)
-
-        self.possibly_free_vars_for_op(op)
-        self.free_temp_vars()
-        res = self.force_allocate_reg(op)
-        return [l0, l1, res]
-
-    def prepare_op_unicodegetitem(self, op, fcond):
-        boxes = op.getarglist()
-        base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
-        ofs_loc = self.make_sure_var_in_reg(boxes[1], boxes)
-
-        self.possibly_free_vars_for_op(op)
-        self.free_temp_vars()
-        res = self.force_allocate_reg(op)
-
-        basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
-                                         self.cpu.translate_support_code)
-        scale = itemsize / 2
-        return [res, base_loc, ofs_loc,
-            imm(scale), imm(basesize), imm(itemsize)]
-
-    def prepare_op_unicodesetitem(self, op, fcond):
-        boxes = op.getarglist()
-        base_loc = self.make_sure_var_in_reg(boxes[0], boxes)
-        ofs_loc = self.make_sure_var_in_reg(boxes[1], boxes)
-        value_loc = self.make_sure_var_in_reg(boxes[2], boxes)
-        basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
-                                         self.cpu.translate_support_code)
-        scale = itemsize / 2
-        return [value_loc, base_loc, ofs_loc,
-            imm(scale), imm(basesize), imm(itemsize)]
-
     def _prepare_op_same_as(self, op, fcond):
         arg = op.getarg(0)
         imm_arg = check_imm_box(arg)
@@ -1142,8 +975,7 @@
 
     def prepare_op_cond_call_gc_wb(self, op, fcond):
         # we force all arguments in a reg because it will be needed anyway by
-        # the following setfield_gc or setarrayitem_gc. It avoids loading it
-        # twice from the memory.
+        # the following gc_store. It avoids loading it twice from the memory.
         N = op.numargs()
         args = op.getarglist()
         arglocs = [self.make_sure_var_in_reg(op.getarg(i), args)
diff --git a/rpython/jit/backend/arm/runner.py 
b/rpython/jit/backend/arm/runner.py
--- a/rpython/jit/backend/arm/runner.py
+++ b/rpython/jit/backend/arm/runner.py
@@ -29,6 +29,10 @@
     float_regs = VFPRegisterManager.all_regs
     frame_reg = fp
 
+    # can an ISA instruction handle a factor to the offset?
+    # XXX should be: tuple(1 << i for i in range(31))
+    load_supported_factors = (1,)
+
     def __init__(self, rtyper, stats, opts=None, translate_support_code=False,
                  gcdescr=None):
         AbstractLLCPU.__init__(self, rtyper, stats, opts,
diff --git a/rpython/jit/backend/llgraph/runner.py 
b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -13,6 +13,7 @@
 
 from rpython.rtyper.llinterp import LLInterpreter, LLException
 from rpython.rtyper.lltypesystem import lltype, llmemory, rffi, rstr
+from rpython.rtyper.lltypesystem.lloperation import llop
 from rpython.rtyper import rclass
 
 from rpython.rlib.clibffi import FFI_DEFAULT_ABI
@@ -33,7 +34,7 @@
         # front-end will mutate them under our feet again.  We also
         # need to make sure things get freed.
         _cache={}
-
+        
         def mapping(box):
             if isinstance(box, Const) or box is None:
                 return box
@@ -205,7 +206,7 @@
 
 class ArrayDescr(AbstractDescr):
     all_interiorfielddescrs = None
-
+    
     def __init__(self, A, runner):
         self.A = self.OUTERA = A
         self._is_pure = A._immutable_field(None)
@@ -642,18 +643,9 @@
         return array.getlength()
 
     def _bh_getarrayitem(self, a, index, descr, pure=False):
+        a = support.cast_arg(lltype.Ptr(descr.A), a)
+        array = a._obj
         assert index >= 0
-        if descr.A is descr.OUTERA:
-            a = support.cast_arg(lltype.Ptr(descr.A), a)
-        else:
-            # we use rffi.cast instead of support.cast_arg because the types
-            # might not be "compatible" enough from the lltype point of
-            # view. In particular, this happens when we use
-            # str_storage_getitem, in which an rpy_string is casted to
-            # rpy_string_as_Signed (or similar)
-            a = rffi.cast(lltype.Ptr(descr.OUTERA), a)
-            a = getattr(a, descr.OUTERA._arrayfld)
-        array = a._obj
         return support.cast_result(descr.A.OF, array.getitem(index))
 
     direct_getarrayitem_gc = _bh_getarrayitem
@@ -722,6 +714,24 @@
         else:
             return self.bh_raw_load_i(struct, offset, descr)
 
+    def bh_gc_load_indexed_i(self, struct, index, scale, base_ofs, bytes):
+        if   bytes == 1: T = rffi.UCHAR
+        elif bytes == 2: T = rffi.USHORT
+        elif bytes == 4: T = rffi.UINT
+        elif bytes == 8: T = rffi.ULONGLONG
+        elif bytes == -1: T = rffi.SIGNEDCHAR
+        elif bytes == -2: T = rffi.SHORT
+        elif bytes == -4: T = rffi.INT
+        elif bytes == -8: T = rffi.LONGLONG
+        else: raise NotImplementedError(bytes)
+        x = llop.gc_load_indexed(T, struct, index, scale, base_ofs)
+        return lltype.cast_primitive(lltype.Signed, x)
+
+    def bh_gc_load_indexed_f(self, struct, index, scale, base_ofs, bytes):
+        if bytes != 8:
+            raise Exception("gc_load_indexed_f is only for 'double'!")
+        return llop.gc_load_indexed(rffi.DOUBLE, struct, index, scale, 
base_ofs)
+
     def bh_increment_debug_counter(self, addr):
         p = rffi.cast(rffi.CArrayPtr(lltype.Signed), addr)
         p[0] += 1
@@ -1048,7 +1058,7 @@
             if box.datatype == INT:
                 for i,a in enumerate(arg):
                     if isinstance(a, bool):
-                        arg[i] = int(a)
+                        arg[i] = int(a) 
                 assert all([lltype.typeOf(a) == lltype.Signed for a in arg])
             elif box.datatype == FLOAT:
                 assert all([lltype.typeOf(a) == longlong.FLOATSTORAGE or \
diff --git a/rpython/jit/backend/llsupport/llmodel.py 
b/rpython/jit/backend/llsupport/llmodel.py
--- a/rpython/jit/backend/llsupport/llmodel.py
+++ b/rpython/jit/backend/llsupport/llmodel.py
@@ -764,6 +764,16 @@
     def bh_raw_load_f(self, addr, offset, descr):
         return self.read_float_at_mem(addr, offset)
 
+    def bh_gc_load_indexed_i(self, addr, index, scale, base_ofs, bytes):
+        offset = base_ofs + scale * index
+        return self.read_int_at_mem(addr, offset, abs(bytes), bytes < 0)
+
+    def bh_gc_load_indexed_f(self, addr, index, scale, base_ofs, bytes):
+        # only for 'double'!
+        assert bytes == rffi.sizeof(lltype.Float)
+        offset = base_ofs + scale * index
+        return self.read_float_at_mem(addr, offset)
+
     def bh_new(self, sizedescr):
         return self.gc_ll_descr.gc_malloc(sizedescr)
 
diff --git a/rpython/jit/backend/llsupport/rewrite.py 
b/rpython/jit/backend/llsupport/rewrite.py
--- a/rpython/jit/backend/llsupport/rewrite.py
+++ b/rpython/jit/backend/llsupport/rewrite.py
@@ -1,6 +1,6 @@
 from rpython.rlib import rgc
 from rpython.rlib.objectmodel import we_are_translated
-from rpython.rlib.rarithmetic import ovfcheck
+from rpython.rlib.rarithmetic import ovfcheck, highest_bit
 from rpython.rtyper.lltypesystem import llmemory, lltype, rstr
 from rpython.jit.metainterp import history
 from rpython.jit.metainterp.history import ConstInt, ConstPtr
@@ -133,11 +133,11 @@
     def emit_gc_store_or_indexed(self, op, ptr_box, index_box, value_box,
                                  itemsize, factor, offset):
         factor, offset, index_box = \
-                self._emit_mul_add_if_factor_offset_not_supported(index_box,
+                self._emit_mul_if_factor_offset_not_supported(index_box,
                         factor, offset)
         #
-        if factor == 1 and offset == 0:
-            args = [ptr_box, index_box, value_box, ConstInt(itemsize)]
+        if index_box is None:
+            args = [ptr_box, ConstInt(offset), value_box, ConstInt(itemsize)]
             newload = ResOperation(rop.GC_STORE, args)
         else:
             args = [ptr_box, index_box, value_box, ConstInt(factor),
@@ -160,34 +160,31 @@
         index_box = op.getarg(1)
         self.emit_gc_load_or_indexed(op, ptr_box, index_box, itemsize, 1, ofs, 
sign)
 
-    def _emit_mul_add_if_factor_offset_not_supported(self, index_box, factor, 
offset):
-        orig_factor = factor
-        # factor
-        must_manually_load_const = False # offset != 0 and not 
self.cpu.load_constant_offset
-        if factor != 1 and (factor not in self.cpu.load_supported_factors or \
-                            (not index_box.is_constant() and 
must_manually_load_const)):
-            # enter here if the factor is supported by the cpu
-            # OR the index is not constant and a new resop must be emitted
-            # to add the offset
-            if isinstance(index_box, ConstInt):
-                index_box = ConstInt(index_box.value * factor)
-            else:
-                index_box = ResOperation(rop.INT_MUL, [index_box, 
ConstInt(factor)])
+    def _emit_mul_if_factor_offset_not_supported(self, index_box,
+                                                 factor, offset):
+        # Returns (factor, offset, index_box) where index_box is either
+        # a non-constant BoxInt or None.
+        if isinstance(index_box, ConstInt):
+            return 1, index_box.value * factor + offset, None
+        else:
+            if factor != 1 and factor not in self.cpu.load_supported_factors:
+                # the factor is supported by the cpu
+                # x & (x - 1) == 0 is a quick test for power of 2
+                assert factor > 0
+                if (factor & (factor - 1)) == 0:
+                    index_box = ResOperation(rop.INT_LSHIFT,
+                            [index_box, ConstInt(highest_bit(factor))])
+                else:
+                    index_box = ResOperation(rop.INT_MUL,
+                            [index_box, ConstInt(factor)])
                 self.emit_op(index_box)
-            factor = 1
-        # adjust the constant offset
-        #if must_manually_load_const:
-        #    if isinstance(index_box, ConstInt):
-        #        index_box = ConstInt(index_box.value + offset)
-        #    else:
-        #        index_box = ResOperation(rop.INT_ADD, [index_box, 
ConstInt(offset)])
-        #        self.emit_op(index_box)
-        #    offset = 0
-        return factor, offset, index_box
+                factor = 1
+            return factor, offset, index_box
 
-    def emit_gc_load_or_indexed(self, op, ptr_box, index_box, itemsize, 
factor, offset, sign, type='i'):
+    def emit_gc_load_or_indexed(self, op, ptr_box, index_box, itemsize,
+                                factor, offset, sign, type='i'):
         factor, offset, index_box = \
-                self._emit_mul_add_if_factor_offset_not_supported(index_box,
+                self._emit_mul_if_factor_offset_not_supported(index_box,
                         factor, offset)
         #
         if sign:
@@ -197,8 +194,8 @@
         optype = type
         if op is not None:
             optype = op.type
-        if factor == 1 and offset == 0:
-            args = [ptr_box, index_box, ConstInt(itemsize)]
+        if index_box is None:
+            args = [ptr_box, ConstInt(offset), ConstInt(itemsize)]
             newload = ResOperation(OpHelpers.get_gc_load(optype), args)
         else:
             args = [ptr_box, index_box, ConstInt(factor),
@@ -303,13 +300,6 @@
                                                  
self.cpu.translate_support_code)
             self.emit_gc_store_or_indexed(op, op.getarg(0), op.getarg(1), 
op.getarg(2),
                                          itemsize, itemsize, basesize)
-        elif op.getopnum() == rop.ZERO_PTR_FIELD:
-            ofs = op.getarg(1).getint()
-            size = WORD
-            index_box = ConstInt(0)
-            value_box = ConstInt(0)
-            self.emit_gc_store_or_indexed(op, op.getarg(0), index_box, 
value_box,
-                                          size, 1, ofs)
         return False
 
 
@@ -548,7 +538,9 @@
             return
         # the ZERO_ARRAY operation will be optimized according to what
         # SETARRAYITEM_GC we see before the next allocation operation.
-        # See emit_pending_zeros().
+        # See emit_pending_zeros().  (This optimization is done by
+        # hacking the object 'o' in-place: e.g., o.getarg(1) may be
+        # replaced with another constant greater than 0.)
         o = ResOperation(rop.ZERO_ARRAY, [v_arr, self.c_zero, v_length],
                          descr=arraydescr)
         self.emit_op(o)
@@ -562,9 +554,8 @@
             ofs, size, sign = unpack_fielddescr(descrs.jfi_frame_depth)
             if sign:
                 size = -size
-            args = [ConstInt(frame_info), ConstInt(0), ConstInt(1),
-                    ConstInt(ofs), ConstInt(size)]
-            size = ResOperation(rop.GC_LOAD_INDEXED_I, args)
+            args = [ConstInt(frame_info), ConstInt(ofs), ConstInt(size)]
+            size = ResOperation(rop.GC_LOAD_I, args)
             self.emit_op(size)
             frame = ResOperation(rop.NEW_ARRAY, [size],
                                  descr=descrs.arraydescr)
@@ -575,9 +566,8 @@
             ofs, size, sign = unpack_fielddescr(descrs.jfi_frame_size)
             if sign:
                 size = -size
-            args = [ConstInt(frame_info), ConstInt(0), ConstInt(1),
-                    ConstInt(ofs), ConstInt(size)]
-            size = ResOperation(rop.GC_LOAD_INDEXED_I, args)
+            args = [ConstInt(frame_info), ConstInt(ofs), ConstInt(size)]
+            size = ResOperation(rop.GC_LOAD_I, args)
             self.emit_op(size)
             frame = self.gen_malloc_nursery_varsize_frame(size)
             self.gen_initialize_tid(frame, descrs.arraydescr.tid)
@@ -657,15 +647,12 @@
             descr = self.cpu.getarraydescr_for_frame(arg.type)
             assert self.cpu.JITFRAME_FIXED_SIZE & 1 == 0
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to