[pypy-commit] pypy arm-backend-2: merge default

bivab noreply at buildbot.pypy.org
Tue Oct 25 11:07:49 CEST 2011


Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r48414:310898482c7b
Date: 2011-10-24 09:53 +0200
http://bitbucket.org/pypy/pypy/changeset/310898482c7b/

Log:	merge default

diff --git a/lib-python/modified-2.7/json/encoder.py b/lib-python/modified-2.7/json/encoder.py
--- a/lib-python/modified-2.7/json/encoder.py
+++ b/lib-python/modified-2.7/json/encoder.py
@@ -2,14 +2,7 @@
 """
 import re
 
-try:
-    from _json import encode_basestring_ascii as c_encode_basestring_ascii
-except ImportError:
-    c_encode_basestring_ascii = None
-try:
-    from _json import make_encoder as c_make_encoder
-except ImportError:
-    c_make_encoder = None
+from __pypy__.builders import StringBuilder, UnicodeBuilder
 
 ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]')
 ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])')
@@ -24,8 +17,7 @@
     '\t': '\\t',
 }
 for i in range(0x20):
-    ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i))
-    #ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
+    ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
 
 # Assume this produces an infinity on all machines (probably not guaranteed)
 INFINITY = float('1e66666')
@@ -37,10 +29,9 @@
     """
     def replace(match):
         return ESCAPE_DCT[match.group(0)]
-    return '"' + ESCAPE.sub(replace, s) + '"'
+    return ESCAPE.sub(replace, s)
 
-
-def py_encode_basestring_ascii(s):
+def encode_basestring_ascii(s):
     """Return an ASCII-only JSON representation of a Python string
 
     """
@@ -53,20 +44,18 @@
         except KeyError:
             n = ord(s)
             if n < 0x10000:
-                return '\\u{0:04x}'.format(n)
-                #return '\\u%04x' % (n,)
+                return '\\u%04x' % (n,)
             else:
                 # surrogate pair
                 n -= 0x10000
                 s1 = 0xd800 | ((n >> 10) & 0x3ff)
                 s2 = 0xdc00 | (n & 0x3ff)
-                return '\\u{0:04x}\\u{1:04x}'.format(s1, s2)
-                #return '\\u%04x\\u%04x' % (s1, s2)
-    return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
-
-
-encode_basestring_ascii = (
-    c_encode_basestring_ascii or py_encode_basestring_ascii)
+                return '\\u%04x\\u%04x' % (s1, s2)
+    if ESCAPE_ASCII.search(s):
+        return str(ESCAPE_ASCII.sub(replace, s))
+    return s
+py_encode_basestring_ascii = lambda s: '"' + encode_basestring_ascii(s) + '"'
+c_encode_basestring_ascii = None
 
 class JSONEncoder(object):
     """Extensible JSON <http://json.org> encoder for Python data structures.
@@ -147,6 +136,17 @@
 
         self.skipkeys = skipkeys
         self.ensure_ascii = ensure_ascii
+        if ensure_ascii:
+            self.encoder = encode_basestring_ascii
+        else:
+            self.encoder = encode_basestring
+        if encoding != 'utf-8':
+            orig_encoder = self.encoder
+            def encoder(o):
+                if isinstance(o, str):
+                    o = o.decode(encoding)
+                return orig_encoder(o)
+            self.encoder = encoder
         self.check_circular = check_circular
         self.allow_nan = allow_nan
         self.sort_keys = sort_keys
@@ -184,24 +184,126 @@
         '{"foo": ["bar", "baz"]}'
 
         """
-        # This is for extremely simple cases and benchmarks.
+        if self.check_circular:
+            markers = {}
+        else:
+            markers = None
+        if self.ensure_ascii:
+            builder = StringBuilder()
+        else:
+            builder = UnicodeBuilder()
+        self._encode(o, markers, builder, 0)
+        return builder.build()
+
+    def _emit_indent(self, builder, _current_indent_level):
+        if self.indent is not None:
+            _current_indent_level += 1
+            newline_indent = '\n' + (' ' * (self.indent *
+                                            _current_indent_level))
+            separator = self.item_separator + newline_indent
+            builder.append(newline_indent)
+        else:
+            separator = self.item_separator
+        return separator, _current_indent_level
+
+    def _emit_unindent(self, builder, _current_indent_level):
+        if self.indent is not None:
+            builder.append('\n')
+            builder.append(' ' * (self.indent * (_current_indent_level - 1)))
+
+    def _encode(self, o, markers, builder, _current_indent_level):
         if isinstance(o, basestring):
-            if isinstance(o, str):
-                _encoding = self.encoding
-                if (_encoding is not None
-                        and not (_encoding == 'utf-8')):
-                    o = o.decode(_encoding)
-            if self.ensure_ascii:
-                return encode_basestring_ascii(o)
+            builder.append('"')
+            builder.append(self.encoder(o))
+            builder.append('"')
+        elif o is None:
+            builder.append('null')
+        elif o is True:
+            builder.append('true')
+        elif o is False:
+            builder.append('false')
+        elif isinstance(o, (int, long)):
+            builder.append(str(o))
+        elif isinstance(o, float):
+            builder.append(self._floatstr(o))
+        elif isinstance(o, (list, tuple)):
+            if not o:
+                builder.append('[]')
+                return
+            self._encode_list(o, markers, builder, _current_indent_level)
+        elif isinstance(o, dict):
+            if not o:
+                builder.append('{}')
+                return
+            self._encode_dict(o, markers, builder, _current_indent_level)
+        else:
+            self._mark_markers(markers, o)
+            res = self.default(o)
+            self._encode(res, markers, builder, _current_indent_level)
+            self._remove_markers(markers, o)
+            return res
+
+    def _encode_list(self, l, markers, builder, _current_indent_level):
+        self._mark_markers(markers, l)
+        builder.append('[')
+        first = True
+        separator, _current_indent_level = self._emit_indent(builder,
+                                                      _current_indent_level)
+        for elem in l:
+            if first:
+                first = False
             else:
-                return encode_basestring(o)
-        # This doesn't pass the iterator directly to ''.join() because the
-        # exceptions aren't as detailed.  The list call should be roughly
-        # equivalent to the PySequence_Fast that ''.join() would do.
-        chunks = self.iterencode(o, _one_shot=True)
-        if not isinstance(chunks, (list, tuple)):
-            chunks = list(chunks)
-        return ''.join(chunks)
+                builder.append(separator)
+            self._encode(elem, markers, builder, _current_indent_level)
+            del elem # XXX grumble
+        self._emit_unindent(builder, _current_indent_level)
+        builder.append(']')
+        self._remove_markers(markers, l)
+
+    def _encode_dict(self, d, markers, builder, _current_indent_level):
+        self._mark_markers(markers, d)
+        first = True
+        builder.append('{')
+        separator, _current_indent_level = self._emit_indent(builder,
+                                                         _current_indent_level)
+        if self.sort_keys:
+            items = sorted(d.items(), key=lambda kv: kv[0])
+        else:
+            items = d.iteritems()
+
+        for key, v in items:
+            if first:
+                first = False
+            else:
+                builder.append(separator)
+            if isinstance(key, basestring):
+                pass
+            # JavaScript is weakly typed for these, so it makes sense to
+            # also allow them.  Many encoders seem to do something like this.
+            elif isinstance(key, float):
+                key = self._floatstr(key)
+            elif key is True:
+                key = 'true'
+            elif key is False:
+                key = 'false'
+            elif key is None:
+                key = 'null'
+            elif isinstance(key, (int, long)):
+                key = str(key)
+            elif self.skipkeys:
+                continue
+            else:
+                raise TypeError("key " + repr(key) + " is not a string")
+            builder.append('"')
+            builder.append(self.encoder(key))
+            builder.append('"')
+            builder.append(self.key_separator)
+            self._encode(v, markers, builder, _current_indent_level)
+            del key
+            del v # XXX grumble
+        self._emit_unindent(builder, _current_indent_level)
+        builder.append('}')
+        self._remove_markers(markers, d)
 
     def iterencode(self, o, _one_shot=False):
         """Encode the given object and yield each string
@@ -217,86 +319,54 @@
             markers = {}
         else:
             markers = None
-        if self.ensure_ascii:
-            _encoder = encode_basestring_ascii
+        return self._iterencode(o, markers, 0)
+
+    def _floatstr(self, o):
+        # Check for specials.  Note that this type of test is processor
+        # and/or platform-specific, so do tests which don't depend on the
+        # internals.
+
+        if o != o:
+            text = 'NaN'
+        elif o == INFINITY:
+            text = 'Infinity'
+        elif o == -INFINITY:
+            text = '-Infinity'
         else:
-            _encoder = encode_basestring
-        if self.encoding != 'utf-8':
-            def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding):
-                if isinstance(o, str):
-                    o = o.decode(_encoding)
-                return _orig_encoder(o)
+            return FLOAT_REPR(o)
 
-        def floatstr(o, allow_nan=self.allow_nan,
-                _repr=FLOAT_REPR, _inf=INFINITY, _neginf=-INFINITY):
-            # Check for specials.  Note that this type of test is processor
-            # and/or platform-specific, so do tests which don't depend on the
-            # internals.
+        if not self.allow_nan:
+            raise ValueError(
+                "Out of range float values are not JSON compliant: " +
+                repr(o))
 
-            if o != o:
-                text = 'NaN'
-            elif o == _inf:
-                text = 'Infinity'
-            elif o == _neginf:
-                text = '-Infinity'
-            else:
-                return _repr(o)
+        return text
 
-            if not allow_nan:
-                raise ValueError(
-                    "Out of range float values are not JSON compliant: " +
-                    repr(o))
+    def _mark_markers(self, markers, o):
+        if markers is not None:
+            if id(o) in markers:
+                raise ValueError("Circular reference detected")
+            markers[id(o)] = None
 
-            return text
+    def _remove_markers(self, markers, o):
+        if markers is not None:
+            del markers[id(o)]
 
-
-        if (_one_shot and c_make_encoder is not None
-                and not self.indent and not self.sort_keys):
-            _iterencode = c_make_encoder(
-                markers, self.default, _encoder, self.indent,
-                self.key_separator, self.item_separator, self.sort_keys,
-                self.skipkeys, self.allow_nan)
-        else:
-            _iterencode = _make_iterencode(
-                markers, self.default, _encoder, self.indent, floatstr,
-                self.key_separator, self.item_separator, self.sort_keys,
-                self.skipkeys, _one_shot)
-        return _iterencode(o, 0)
-
-def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
-        _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot,
-        ## HACK: hand-optimized bytecode; turn globals into locals
-        ValueError=ValueError,
-        basestring=basestring,
-        dict=dict,
-        float=float,
-        id=id,
-        int=int,
-        isinstance=isinstance,
-        list=list,
-        long=long,
-        str=str,
-        tuple=tuple,
-    ):
-
-    def _iterencode_list(lst, _current_indent_level):
+    def _iterencode_list(self, lst, markers, _current_indent_level):
         if not lst:
             yield '[]'
             return
-        if markers is not None:
-            markerid = id(lst)
-            if markerid in markers:
-                raise ValueError("Circular reference detected")
-            markers[markerid] = lst
+        self._mark_markers(markers, lst)
         buf = '['
-        if _indent is not None:
+        if self.indent is not None:
             _current_indent_level += 1
-            newline_indent = '\n' + (' ' * (_indent * _current_indent_level))
-            separator = _item_separator + newline_indent
+            newline_indent = '\n' + (' ' * (self.indent *
+                                            _current_indent_level))
+            separator = self.item_separator + newline_indent
             buf += newline_indent
         else:
             newline_indent = None
-            separator = _item_separator
+            separator = self.item_separator
         first = True
         for value in lst:
             if first:
@@ -304,7 +374,7 @@
             else:
                 buf = separator
             if isinstance(value, basestring):
-                yield buf + _encoder(value)
+                yield buf + '"' + self.encoder(value) + '"'
             elif value is None:
                 yield buf + 'null'
             elif value is True:
@@ -314,44 +384,43 @@
             elif isinstance(value, (int, long)):
                 yield buf + str(value)
             elif isinstance(value, float):
-                yield buf + _floatstr(value)
+                yield buf + self._floatstr(value)
             else:
                 yield buf
                 if isinstance(value, (list, tuple)):
-                    chunks = _iterencode_list(value, _current_indent_level)
+                    chunks = self._iterencode_list(value, markers,
+                                                   _current_indent_level)
                 elif isinstance(value, dict):
-                    chunks = _iterencode_dict(value, _current_indent_level)
+                    chunks = self._iterencode_dict(value, markers,
+                                                   _current_indent_level)
                 else:
-                    chunks = _iterencode(value, _current_indent_level)
+                    chunks = self._iterencode(value, markers,
+                                              _current_indent_level)
                 for chunk in chunks:
                     yield chunk
         if newline_indent is not None:
             _current_indent_level -= 1
-            yield '\n' + (' ' * (_indent * _current_indent_level))
+            yield '\n' + (' ' * (self.indent * _current_indent_level))
         yield ']'
-        if markers is not None:
-            del markers[markerid]
+        self._remove_markers(markers, lst)
 
-    def _iterencode_dict(dct, _current_indent_level):
+    def _iterencode_dict(self, dct, markers, _current_indent_level):
         if not dct:
             yield '{}'
             return
-        if markers is not None:
-            markerid = id(dct)
-            if markerid in markers:
-                raise ValueError("Circular reference detected")
-            markers[markerid] = dct
+        self._mark_markers(markers, dct)
         yield '{'
-        if _indent is not None:
+        if self.indent is not None:
             _current_indent_level += 1
-            newline_indent = '\n' + (' ' * (_indent * _current_indent_level))
-            item_separator = _item_separator + newline_indent
+            newline_indent = '\n' + (' ' * (self.indent *
+                                            _current_indent_level))
+            item_separator = self.item_separator + newline_indent
             yield newline_indent
         else:
             newline_indent = None
-            item_separator = _item_separator
+            item_separator = self.item_separator
         first = True
-        if _sort_keys:
+        if self.sort_keys:
             items = sorted(dct.items(), key=lambda kv: kv[0])
         else:
             items = dct.iteritems()
@@ -361,7 +430,7 @@
             # JavaScript is weakly typed for these, so it makes sense to
             # also allow them.  Many encoders seem to do something like this.
             elif isinstance(key, float):
-                key = _floatstr(key)
+                key = self._floatstr(key)
             elif key is True:
                 key = 'true'
             elif key is False:
@@ -370,7 +439,7 @@
                 key = 'null'
             elif isinstance(key, (int, long)):
                 key = str(key)
-            elif _skipkeys:
+            elif self.skipkeys:
                 continue
             else:
                 raise TypeError("key " + repr(key) + " is not a string")
@@ -378,10 +447,10 @@
                 first = False
             else:
                 yield item_separator
-            yield _encoder(key)
-            yield _key_separator
+            yield '"' + self.encoder(key) + '"'
+            yield self.key_separator
             if isinstance(value, basestring):
-                yield _encoder(value)
+                yield '"' + self.encoder(value) + '"'
             elif value is None:
                 yield 'null'
             elif value is True:
@@ -391,26 +460,28 @@
             elif isinstance(value, (int, long)):
                 yield str(value)
             elif isinstance(value, float):
-                yield _floatstr(value)
+                yield self._floatstr(value)
             else:
                 if isinstance(value, (list, tuple)):
-                    chunks = _iterencode_list(value, _current_indent_level)
+                    chunks = self._iterencode_list(value, markers,
+                                                   _current_indent_level)
                 elif isinstance(value, dict):
-                    chunks = _iterencode_dict(value, _current_indent_level)
+                    chunks = self._iterencode_dict(value, markers,
+                                                   _current_indent_level)
                 else:
-                    chunks = _iterencode(value, _current_indent_level)
+                    chunks = self._iterencode(value, markers,
+                                              _current_indent_level)
                 for chunk in chunks:
                     yield chunk
         if newline_indent is not None:
             _current_indent_level -= 1
-            yield '\n' + (' ' * (_indent * _current_indent_level))
+            yield '\n' + (' ' * (self.indent * _current_indent_level))
         yield '}'
-        if markers is not None:
-            del markers[markerid]
+        self._remove_markers(markers, dct)
 
-    def _iterencode(o, _current_indent_level):
+    def _iterencode(self, o, markers, _current_indent_level):
         if isinstance(o, basestring):
-            yield _encoder(o)
+            yield '"' + self.encoder(o) + '"'
         elif o is None:
             yield 'null'
         elif o is True:
@@ -420,23 +491,19 @@
         elif isinstance(o, (int, long)):
             yield str(o)
         elif isinstance(o, float):
-            yield _floatstr(o)
+            yield self._floatstr(o)
         elif isinstance(o, (list, tuple)):
-            for chunk in _iterencode_list(o, _current_indent_level):
+            for chunk in self._iterencode_list(o, markers,
+                                               _current_indent_level):
                 yield chunk
         elif isinstance(o, dict):
-            for chunk in _iterencode_dict(o, _current_indent_level):
+            for chunk in self._iterencode_dict(o, markers,
+                                               _current_indent_level):
                 yield chunk
         else:
-            if markers is not None:
-                markerid = id(o)
-                if markerid in markers:
-                    raise ValueError("Circular reference detected")
-                markers[markerid] = o
-            o = _default(o)
-            for chunk in _iterencode(o, _current_indent_level):
+            self._mark_markers(markers, o)
+            obj = self.default(o)
+            for chunk in self._iterencode(obj, markers,
+                                          _current_indent_level):
                 yield chunk
-            if markers is not None:
-                del markers[markerid]
-
-    return _iterencode
+            self._remove_markers(markers, o)
diff --git a/lib-python/modified-2.7/json/tests/test_unicode.py b/lib-python/modified-2.7/json/tests/test_unicode.py
--- a/lib-python/modified-2.7/json/tests/test_unicode.py
+++ b/lib-python/modified-2.7/json/tests/test_unicode.py
@@ -80,3 +80,9 @@
         self.assertEqual(type(json.loads(u'["a"]')[0]), unicode)
         # Issue 10038.
         self.assertEqual(type(json.loads('"foo"')), unicode)
+
+    def test_encode_not_utf_8(self):
+        self.assertEqual(json.dumps('\xb1\xe6', encoding='iso8859-2'),
+                         '"\\u0105\\u0107"')
+        self.assertEqual(json.dumps(['\xb1\xe6'], encoding='iso8859-2'),
+                         '["\\u0105\\u0107"]')
diff --git a/lib-python/modified-2.7/test/test_array.py b/lib-python/modified-2.7/test/test_array.py
--- a/lib-python/modified-2.7/test/test_array.py
+++ b/lib-python/modified-2.7/test/test_array.py
@@ -295,9 +295,10 @@
         )
 
         b = array.array(self.badtypecode())
-        self.assertRaises(TypeError, "a + b")
-
-        self.assertRaises(TypeError, "a + 'bad'")
+        with self.assertRaises(TypeError):
+            a + b
+        with self.assertRaises(TypeError):
+            a + 'bad'
 
     def test_iadd(self):
         a = array.array(self.typecode, self.example[::-1])
@@ -316,9 +317,10 @@
         )
 
         b = array.array(self.badtypecode())
-        self.assertRaises(TypeError, "a += b")
-
-        self.assertRaises(TypeError, "a += 'bad'")
+        with self.assertRaises(TypeError):
+            a += b
+        with self.assertRaises(TypeError):
+            a += 'bad'
 
     def test_mul(self):
         a = 5*array.array(self.typecode, self.example)
@@ -345,7 +347,8 @@
             array.array(self.typecode)
         )
 
-        self.assertRaises(TypeError, "a * 'bad'")
+        with self.assertRaises(TypeError):
+            a * 'bad'
 
     def test_imul(self):
         a = array.array(self.typecode, self.example)
@@ -374,7 +377,8 @@
         a *= -1
         self.assertEqual(a, array.array(self.typecode))
 
-        self.assertRaises(TypeError, "a *= 'bad'")
+        with self.assertRaises(TypeError):
+            a *= 'bad'
 
     def test_getitem(self):
         a = array.array(self.typecode, self.example)
diff --git a/lib_pypy/pyrepl/readline.py b/lib_pypy/pyrepl/readline.py
--- a/lib_pypy/pyrepl/readline.py
+++ b/lib_pypy/pyrepl/readline.py
@@ -395,9 +395,21 @@
     _wrapper.f_in = f_in
     _wrapper.f_out = f_out
 
-    if hasattr(sys, '__raw_input__'):    # PyPy
-        _old_raw_input = sys.__raw_input__
+    if '__pypy__' in sys.builtin_module_names:    # PyPy
+
+        def _old_raw_input(prompt=''):
+            # sys.__raw_input__() is only called when stdin and stdout are
+            # as expected and are ttys.  If it is the case, then get_reader()
+            # should not really fail in _wrapper.raw_input().  If it still
+            # does, then we will just cancel the redirection and call again
+            # the built-in raw_input().
+            try:
+                del sys.__raw_input__
+            except AttributeError:
+                pass
+            return raw_input(prompt)
         sys.__raw_input__ = _wrapper.raw_input
+
     else:
         # this is not really what readline.c does.  Better than nothing I guess
         import __builtin__
diff --git a/lib_pypy/resource.py b/lib_pypy/resource.py
--- a/lib_pypy/resource.py
+++ b/lib_pypy/resource.py
@@ -7,7 +7,7 @@
 
 from ctypes_support import standard_c_lib as libc
 from ctypes_support import get_errno
-from ctypes import Structure, c_int, c_long, byref, sizeof, POINTER
+from ctypes import Structure, c_int, c_long, byref, POINTER
 from errno import EINVAL, EPERM
 import _structseq
 
@@ -165,7 +165,6 @@
 
 @builtinify
 def getpagesize():
-    pagesize = 0
     if _getpagesize:
         return _getpagesize()
     else:
diff --git a/pypy/annotation/classdef.py b/pypy/annotation/classdef.py
--- a/pypy/annotation/classdef.py
+++ b/pypy/annotation/classdef.py
@@ -276,8 +276,8 @@
         # create the Attribute and do the generalization asked for
         newattr = Attribute(attr, self.bookkeeper)
         if s_value:
-            if newattr.name == 'intval' and getattr(s_value, 'unsigned', False):
-                import pdb; pdb.set_trace()
+            #if newattr.name == 'intval' and getattr(s_value, 'unsigned', False):
+            #    import pdb; pdb.set_trace()
             newattr.s_value = s_value
 
         # keep all subattributes' values
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -72,6 +72,7 @@
     del working_modules['fcntl']  # LOCK_NB not defined
     del working_modules["_minimal_curses"]
     del working_modules["termios"]
+    del working_modules["_multiprocessing"]   # depends on rctime
 
 
 
@@ -127,7 +128,7 @@
 
 pypy_optiondescription = OptionDescription("objspace", "Object Space Options", [
     ChoiceOption("name", "Object Space name",
-                 ["std", "flow", "thunk", "dump", "taint"],
+                 ["std", "flow", "thunk", "dump"],
                  "std",
                  cmdline='--objspace -o'),
 
diff --git a/pypy/doc/__pypy__-module.rst b/pypy/doc/__pypy__-module.rst
--- a/pypy/doc/__pypy__-module.rst
+++ b/pypy/doc/__pypy__-module.rst
@@ -37,29 +37,6 @@
 .. _`thunk object space docs`: objspace-proxies.html#thunk
 .. _`interface section of the thunk object space docs`: objspace-proxies.html#thunk-interface
 
-.. broken:
-
-    Taint Object Space Functionality
-    ================================
-
-    When the taint object space is used (choose with :config:`objspace.name`),
-    the following names are put into ``__pypy__``:
-
-     - ``taint``
-     - ``is_tainted``
-     - ``untaint``
-     - ``taint_atomic``
-     - ``_taint_debug``
-     - ``_taint_look``
-     - ``TaintError``
-
-    Those are all described in the `interface section of the taint object space
-    docs`_.
-
-    For more detailed explanations and examples see the `taint object space docs`_.
-
-    .. _`taint object space docs`: objspace-proxies.html#taint
-    .. _`interface section of the taint object space docs`: objspace-proxies.html#taint-interface
 
 Transparent Proxy Functionality
 ===============================
diff --git a/pypy/doc/config/objspace.name.txt b/pypy/doc/config/objspace.name.txt
--- a/pypy/doc/config/objspace.name.txt
+++ b/pypy/doc/config/objspace.name.txt
@@ -4,7 +4,6 @@
 for normal usage):
 
   * thunk_: The thunk object space adds lazy evaluation to PyPy.
-  * taint_: The taint object space adds soft security features.
   * dump_:  Using this object spaces results in the dumpimp of all operations
     to a log.
 
@@ -12,5 +11,4 @@
 .. _`Object Space Proxies`: ../objspace-proxies.html
 .. _`Standard Object Space`: ../objspace.html#standard-object-space
 .. _thunk: ../objspace-proxies.html#thunk
-.. _taint: ../objspace-proxies.html#taint
 .. _dump: ../objspace-proxies.html#dump
diff --git a/pypy/doc/index.rst b/pypy/doc/index.rst
--- a/pypy/doc/index.rst
+++ b/pypy/doc/index.rst
@@ -309,7 +309,6 @@
 .. _`object space`: objspace.html
 .. _FlowObjSpace: objspace.html#the-flow-object-space 
 .. _`trace object space`: objspace.html#the-trace-object-space 
-.. _`taint object space`: objspace-proxies.html#taint
 .. _`thunk object space`: objspace-proxies.html#thunk
 .. _`transparent proxies`: objspace-proxies.html#tproxy
 .. _`Differences between PyPy and CPython`: cpython_differences.html
diff --git a/pypy/doc/objspace-proxies.rst b/pypy/doc/objspace-proxies.rst
--- a/pypy/doc/objspace-proxies.rst
+++ b/pypy/doc/objspace-proxies.rst
@@ -129,297 +129,6 @@
    function behaves lazily: all calls to it return a thunk object.
 
 
-.. broken right now:
-
-    .. _taint:
-
-    The Taint Object Space
-    ======================
-
-    Motivation
-    ----------
-
-    The Taint Object Space provides a form of security: "tainted objects",
-    inspired by various sources, see [D12.1]_ for a more detailed discussion. 
-
-    The basic idea of this kind of security is not to protect against
-    malicious code but to help with handling and boxing sensitive data. 
-    It covers two kinds of sensitive data: secret data which should not leak, 
-    and untrusted data coming from an external source and that must be 
-    validated before it is used.
-
-    The idea is that, considering a large application that handles these
-    kinds of sensitive data, there are typically only a small number of
-    places that need to explicitly manipulate that sensitive data; all the
-    other places merely pass it around, or do entirely unrelated things.
-
-    Nevertheless, if a large application needs to be reviewed for security,
-    it must be entirely carefully checked, because it is possible that a
-    bug at some apparently unrelated place could lead to a leak of sensitive
-    information in a way that an external attacker could exploit.  For
-    example, if any part of the application provides web services, an
-    attacker might be able to issue unexpected requests with a regular web
-    browser and deduce secret information from the details of the answers he
-    gets.  Another example is the common CGI attack where an attacker sends
-    malformed inputs and causes the CGI script to do unintended things.
-
-    An approach like that of the Taint Object Space allows the small parts
-    of the program that manipulate sensitive data to be explicitly marked.
-    The effect of this is that although these small parts still need a
-    careful security review, the rest of the application no longer does,
-    because even a bug would be unable to leak the information.
-
-    We have implemented a simple two-level model: objects are either
-    regular (untainted), or sensitive (tainted).  Objects are marked as
-    sensitive if they are secret or untrusted, and only declassified at
-    carefully-checked positions (e.g. where the secret data is needed, or
-    after the untrusted data has been fully validated).
-
-    It would be simple to extend the code for more fine-grained scales of
-    secrecy.  For example it is typical in the literature to consider
-    user-specified lattices of secrecy levels, corresponding to multiple
-    "owners" that cannot access data belonging to another "owner" unless
-    explicitly authorized to do so.
-
-    Tainting and untainting
-    -----------------------
-
-    Start a py.py with the Taint Object Space and try the following example::
-
-        $ py.py -o taint
-        >>>> from __pypy__ import taint
-        >>>> x = taint(6)
-
-        # x is hidden from now on.  We can pass it around and
-        # even operate on it, but not inspect it.  Taintness
-        # is propagated to operation results.
-
-        >>>> x
-        TaintError
-
-        >>>> if x > 5: y = 2   # see below
-        TaintError
-
-        >>>> y = x + 5         # ok
-        >>>> lst = [x, y]
-        >>>> z = lst.pop()
-        >>>> t = type(z)       # type() works too, tainted answer
-        >>>> t
-        TaintError
-        >>>> u = t is int      # even 'is' works
-        >>>> u
-        TaintError
-
-    Notice that using a tainted boolean like ``x > 5`` in an ``if``
-    statement is forbidden.  This is because knowing which path is followed
-    would give away a hint about ``x``; in the example above, if the
-    statement ``if x > 5: y = 2`` was allowed to run, we would know
-    something about the value of ``x`` by looking at the (untainted) value
-    in the variable ``y``.
-
-    Of course, there is a way to inspect tainted objects.  The basic way is
-    to explicitly "declassify" it with the ``untaint()`` function.  In an
-    application, the places that use ``untaint()`` are the places that need
-    careful security review.  To avoid unexpected objects showing up, the
-    ``untaint()`` function must be called with the exact type of the object
-    to declassify.  It will raise ``TaintError`` if the type doesn't match::
-
-        >>>> from __pypy__ import taint
-        >>>> untaint(int, x)
-        6
-        >>>> untaint(int, z)
-        11
-        >>>> untaint(bool, x > 5)
-        True
-        >>>> untaint(int, x > 5)
-        TaintError
-
-
-    Taint Bombs
-    -----------
-
-    In this area, a common problem is what to do about failing operations.
-    If an operation raises an exception when manipulating a tainted object,
-    then the very presence of the exception can leak information about the
-    tainted object itself.  Consider::
-
-        >>>> 5 / (x-6)
-
-    By checking if this raises ``ZeroDivisionError`` or not, we would know
-    if ``x`` was equal to 6 or not.  The solution to this problem in the
-    Taint Object Space is to introduce *Taint Bombs*.  They are a kind of
-    tainted object that doesn't contain a real object, but a pending
-    exception.  Taint Bombs are indistinguishable from normal tainted
-    objects to unprivileged code. See::
-
-        >>>> x = taint(6)
-        >>>> i = 5 / (x-6)     # no exception here
-        >>>> j = i + 1         # nor here
-        >>>> k = j + 5         # nor here
-        >>>> untaint(int, k)
-        TaintError
-
-    In the above example, all of ``i``, ``j`` and ``k`` contain a Taint
-    Bomb.  Trying to untaint it raises an exception - a generic
-    ``TaintError``.  What we win is that the exception gives little away,
-    and most importantly it occurs at the point where ``untaint()`` is
-    called, not where the operation failed.  This means that all calls to
-    ``untaint()`` - but not the rest of the code - must be carefully
-    reviewed for what occurs if they receive a Taint Bomb; they might catch
-    the ``TaintError`` and give the user a generic message that something
-    went wrong, if we are reasonably careful that the message or even its
-    presence doesn't give information away.  This might be a
-    problem by itself, but there is no satisfying general solution here:
-    it must be considered on a case-by-case basis.  Again, what the
-    Taint Object Space approach achieves is not solving these problems, but
-    localizing them to well-defined small parts of the application - namely,
-    around calls to ``untaint()``.
-
-    The ``TaintError`` exception deliberately does not include any
-    useful error messages, because they might give information away.
-    Of course, this makes debugging quite a bit harder; a difficult
-    problem to solve properly.  So far we have implemented a way to peek in a Taint
-    Box or Bomb, ``__pypy__._taint_look(x)``, and a "debug mode" that
-    prints the exception as soon as a Bomb is created - both write
-    information to the low-level stderr of the application, where we hope
-    that it is unlikely to be seen by anyone but the application
-    developer.
-
-
-    Taint Atomic functions
-    ----------------------
-
-    Occasionally, a more complicated computation must be performed on a
-    tainted object.  This requires first untainting the object, performing the
-    computations, and then carefully tainting the result again (including
-    hiding all exceptions into Bombs).
-
-    There is a built-in decorator that does this for you::
-
-        >>>> @__pypy__.taint_atomic
-        >>>> def myop(x, y):
-        ....     while x > 0:
-        ....         x -= y
-        ....     return x
-        ....
-        >>>> myop(42, 10)
-        -8
-        >>>> z = myop(taint(42), 10)
-        >>>> z
-        TaintError
-        >>>> untaint(int, z)
-        -8
-
-    The decorator makes a whole function behave like a built-in operation.
-    If no tainted argument is passed in, the function behaves normally.  But
-    if any of the arguments is tainted, it is automatically untainted - so
-    the function body always sees untainted arguments - and the eventual
-    result is tainted again (possibly in a Taint Bomb).
-
-    It is important for the function marked as ``taint_atomic`` to have no
-    visible side effects, as these could cause information leakage.
-    This is currently not enforced, which means that all ``taint_atomic``
-    functions have to be carefully reviewed for security (but not the
-    callers of ``taint_atomic`` functions).
-
-    A possible future extension would be to forbid side-effects on
-    non-tainted objects from all ``taint_atomic`` functions.
-
-    An example of usage: given a tainted object ``passwords_db`` that
-    references a database of passwords, we can write a function
-    that checks if a password is valid as follows::
-
-        @taint_atomic
-        def validate(passwords_db, username, password):
-            assert type(passwords_db) is PasswordDatabase
-            assert type(username) is str
-            assert type(password) is str
-            ...load username entry from passwords_db...
-            return expected_password == password
-
-    It returns a tainted boolean answer, or a Taint Bomb if something
-    went wrong.  A caller can do::
-
-        ok = validate(passwords_db, 'john', '1234')
-        ok = untaint(bool, ok)
-
-    This can give three outcomes: ``True``, ``False``, or a ``TaintError``
-    exception (with no information on it) if anything went wrong.  If even
-    this is considered giving too much information away, the ``False`` case
-    can be made indistinguishable from the ``TaintError`` case (simply by
-    raising an exception in ``validate()`` if the password is wrong).
-
-    In the above example, the security results achieved are the following:
-    as long as ``validate()`` does not leak information, no other part of
-    the code can obtain more information about a passwords database than a
-    Yes/No answer to a precise query.
-
-    A possible extension of the ``taint_atomic`` decorator would be to check
-    the argument types, as ``untaint()`` does, for the same reason: to
-    prevent bugs where a function like ``validate()`` above is accidentally
-    called with the wrong kind of tainted object, which would make it
-    misbehave.  For now, all ``taint_atomic`` functions should be
-    conservative and carefully check all assumptions on their input
-    arguments.
-
-
-    .. _`taint-interface`:
-
-    Interface
-    ---------
-
-    .. _`like a built-in operation`:
-
-    The basic rule of the Tainted Object Space is that it introduces two new
-    kinds of objects, Tainted Boxes and Tainted Bombs (which are not types
-    in the Python sense).  Each box internally contains a regular object;
-    each bomb internally contains an exception object.  An operation
-    involving Tainted Boxes is performed on the objects contained in the
-    boxes, and gives a Tainted Box or a Tainted Bomb as a result (such an
-    operation does not let an exception be raised).  An operation called
-    with a Tainted Bomb argument immediately returns the same Tainted Bomb.
-
-    In a PyPy running with (or translated with) the Taint Object Space,
-    the ``__pypy__`` module exposes the following interface:
-
-    * ``taint(obj)``
-
-        Return a new Tainted Box wrapping ``obj``.  Return ``obj`` itself
-        if it is already tainted (a Box or a Bomb).
-
-    * ``is_tainted(obj)``
-
-        Check if ``obj`` is tainted (a Box or a Bomb).
-
-    * ``untaint(type, obj)``
-
-        Untaints ``obj`` if it is tainted.  Raise ``TaintError`` if the type
-        of the untainted object is not exactly ``type``, or if ``obj`` is a
-        Bomb.
-
-    * ``taint_atomic(func)``
-
-        Return a wrapper function around the callable ``func``.  The wrapper
-        behaves `like a built-in operation`_ with respect to untainting the
-        arguments, tainting the result, and returning a Bomb.
-
-    * ``TaintError``
-
-        Exception.  On purpose, it provides no attribute or error message.
-
-    * ``_taint_debug(level)``
-
-        Set the debugging level to ``level`` (0=off).  At level 1 or above,
-        all Taint Bombs print a diagnostic message to stderr when they are
-        created.
-
-    * ``_taint_look(obj)``
-
-        For debugging purposes: prints (to stderr) the type and address of
-        the object in a Tainted Box, or prints the exception if ``obj`` is
-        a Taint Bomb.
-
-
 .. _dump:
 
 The Dump Object Space
diff --git a/pypy/interpreter/astcompiler/ast.py b/pypy/interpreter/astcompiler/ast.py
--- a/pypy/interpreter/astcompiler/ast.py
+++ b/pypy/interpreter/astcompiler/ast.py
@@ -2,7 +2,7 @@
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter import typedef
 from pypy.interpreter.gateway import interp2app
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.tool.pairtype import extendabletype
 from pypy.tool.sourcetools import func_with_new_name
@@ -2925,14 +2925,13 @@
 def Module_get_body(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     if w_self.w_body is None:
         if w_self.body is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.body]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_body = w_list
     return w_self.w_body
 
@@ -2968,14 +2967,13 @@
 def Interactive_get_body(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     if w_self.w_body is None:
         if w_self.body is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.body]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_body = w_list
     return w_self.w_body
 
@@ -3015,8 +3013,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     return space.wrap(w_self.body)
 
 def Expression_set_body(space, w_self, w_new_value):
@@ -3057,14 +3054,13 @@
 def Suite_get_body(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     if w_self.w_body is None:
         if w_self.body is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.body]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_body = w_list
     return w_self.w_body
 
@@ -3104,8 +3100,7 @@
             return w_obj
     if not w_self.initialization_state & w_self._lineno_mask:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'lineno'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno')
     return space.wrap(w_self.lineno)
 
 def stmt_set_lineno(space, w_self, w_new_value):
@@ -3126,8 +3121,7 @@
             return w_obj
     if not w_self.initialization_state & w_self._col_offset_mask:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'col_offset'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset')
     return space.wrap(w_self.col_offset)
 
 def stmt_set_col_offset(space, w_self, w_new_value):
@@ -3157,8 +3151,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'name'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name')
     return space.wrap(w_self.name)
 
 def FunctionDef_set_name(space, w_self, w_new_value):
@@ -3179,8 +3172,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'args'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args')
     return space.wrap(w_self.args)
 
 def FunctionDef_set_args(space, w_self, w_new_value):
@@ -3197,14 +3189,13 @@
 def FunctionDef_get_body(space, w_self):
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     if w_self.w_body is None:
         if w_self.body is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.body]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_body = w_list
     return w_self.w_body
 
@@ -3215,14 +3206,13 @@
 def FunctionDef_get_decorator_list(space, w_self):
     if not w_self.initialization_state & 8:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'decorator_list'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'decorator_list')
     if w_self.w_decorator_list is None:
         if w_self.decorator_list is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.decorator_list]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_decorator_list = w_list
     return w_self.w_decorator_list
 
@@ -3266,8 +3256,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'name'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name')
     return space.wrap(w_self.name)
 
 def ClassDef_set_name(space, w_self, w_new_value):
@@ -3284,14 +3273,13 @@
 def ClassDef_get_bases(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'bases'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'bases')
     if w_self.w_bases is None:
         if w_self.bases is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.bases]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_bases = w_list
     return w_self.w_bases
 
@@ -3302,14 +3290,13 @@
 def ClassDef_get_body(space, w_self):
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     if w_self.w_body is None:
         if w_self.body is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.body]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_body = w_list
     return w_self.w_body
 
@@ -3320,14 +3307,13 @@
 def ClassDef_get_decorator_list(space, w_self):
     if not w_self.initialization_state & 8:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'decorator_list'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'decorator_list')
     if w_self.w_decorator_list is None:
         if w_self.decorator_list is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.decorator_list]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_decorator_list = w_list
     return w_self.w_decorator_list
 
@@ -3372,8 +3358,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
     return space.wrap(w_self.value)
 
 def Return_set_value(space, w_self, w_new_value):
@@ -3414,14 +3399,13 @@
 def Delete_get_targets(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'targets'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'targets')
     if w_self.w_targets is None:
         if w_self.targets is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.targets]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_targets = w_list
     return w_self.w_targets
 
@@ -3457,14 +3441,13 @@
 def Assign_get_targets(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'targets'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'targets')
     if w_self.w_targets is None:
         if w_self.targets is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.targets]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_targets = w_list
     return w_self.w_targets
 
@@ -3479,8 +3462,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
     return space.wrap(w_self.value)
 
 def Assign_set_value(space, w_self, w_new_value):
@@ -3527,8 +3509,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'target'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target')
     return space.wrap(w_self.target)
 
 def AugAssign_set_target(space, w_self, w_new_value):
@@ -3549,8 +3530,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'op'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op')
     return operator_to_class[w_self.op - 1]()
 
 def AugAssign_set_op(space, w_self, w_new_value):
@@ -3573,8 +3553,7 @@
             return w_obj
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
     return space.wrap(w_self.value)
 
 def AugAssign_set_value(space, w_self, w_new_value):
@@ -3621,8 +3600,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'dest'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'dest')
     return space.wrap(w_self.dest)
 
 def Print_set_dest(space, w_self, w_new_value):
@@ -3639,14 +3617,13 @@
 def Print_get_values(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'values'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values')
     if w_self.w_values is None:
         if w_self.values is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.values]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_values = w_list
     return w_self.w_values
 
@@ -3661,8 +3638,7 @@
             return w_obj
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'nl'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'nl')
     return space.wrap(w_self.nl)
 
 def Print_set_nl(space, w_self, w_new_value):
@@ -3710,8 +3686,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'target'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target')
     return space.wrap(w_self.target)
 
 def For_set_target(space, w_self, w_new_value):
@@ -3732,8 +3707,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'iter'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'iter')
     return space.wrap(w_self.iter)
 
 def For_set_iter(space, w_self, w_new_value):
@@ -3750,14 +3724,13 @@
 def For_get_body(space, w_self):
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     if w_self.w_body is None:
         if w_self.body is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.body]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_body = w_list
     return w_self.w_body
 
@@ -3768,14 +3741,13 @@
 def For_get_orelse(space, w_self):
     if not w_self.initialization_state & 8:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'orelse'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse')
     if w_self.w_orelse is None:
         if w_self.orelse is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.orelse]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_orelse = w_list
     return w_self.w_orelse
 
@@ -3819,8 +3791,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'test'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test')
     return space.wrap(w_self.test)
 
 def While_set_test(space, w_self, w_new_value):
@@ -3837,14 +3808,13 @@
 def While_get_body(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     if w_self.w_body is None:
         if w_self.body is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.body]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_body = w_list
     return w_self.w_body
 
@@ -3855,14 +3825,13 @@
 def While_get_orelse(space, w_self):
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'orelse'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse')
     if w_self.w_orelse is None:
         if w_self.orelse is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.orelse]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_orelse = w_list
     return w_self.w_orelse
 
@@ -3905,8 +3874,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'test'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test')
     return space.wrap(w_self.test)
 
 def If_set_test(space, w_self, w_new_value):
@@ -3923,14 +3891,13 @@
 def If_get_body(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     if w_self.w_body is None:
         if w_self.body is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.body]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_body = w_list
     return w_self.w_body
 
@@ -3941,14 +3908,13 @@
 def If_get_orelse(space, w_self):
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'orelse'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse')
     if w_self.w_orelse is None:
         if w_self.orelse is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.orelse]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_orelse = w_list
     return w_self.w_orelse
 
@@ -3991,8 +3957,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'context_expr'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'context_expr')
     return space.wrap(w_self.context_expr)
 
 def With_set_context_expr(space, w_self, w_new_value):
@@ -4013,8 +3978,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'optional_vars'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'optional_vars')
     return space.wrap(w_self.optional_vars)
 
 def With_set_optional_vars(space, w_self, w_new_value):
@@ -4031,14 +3995,13 @@
 def With_get_body(space, w_self):
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     if w_self.w_body is None:
         if w_self.body is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.body]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_body = w_list
     return w_self.w_body
 
@@ -4080,8 +4043,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'type'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'type')
     return space.wrap(w_self.type)
 
 def Raise_set_type(space, w_self, w_new_value):
@@ -4102,8 +4064,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'inst'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'inst')
     return space.wrap(w_self.inst)
 
 def Raise_set_inst(space, w_self, w_new_value):
@@ -4124,8 +4085,7 @@
             return w_obj
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'tback'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'tback')
     return space.wrap(w_self.tback)
 
 def Raise_set_tback(space, w_self, w_new_value):
@@ -4168,14 +4128,13 @@
 def TryExcept_get_body(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     if w_self.w_body is None:
         if w_self.body is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.body]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_body = w_list
     return w_self.w_body
 
@@ -4186,14 +4145,13 @@
 def TryExcept_get_handlers(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'handlers'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'handlers')
     if w_self.w_handlers is None:
         if w_self.handlers is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.handlers]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_handlers = w_list
     return w_self.w_handlers
 
@@ -4204,14 +4162,13 @@
 def TryExcept_get_orelse(space, w_self):
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'orelse'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse')
     if w_self.w_orelse is None:
         if w_self.orelse is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.orelse]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_orelse = w_list
     return w_self.w_orelse
 
@@ -4251,14 +4208,13 @@
 def TryFinally_get_body(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     if w_self.w_body is None:
         if w_self.body is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.body]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_body = w_list
     return w_self.w_body
 
@@ -4269,14 +4225,13 @@
 def TryFinally_get_finalbody(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'finalbody'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'finalbody')
     if w_self.w_finalbody is None:
         if w_self.finalbody is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.finalbody]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_finalbody = w_list
     return w_self.w_finalbody
 
@@ -4318,8 +4273,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'test'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test')
     return space.wrap(w_self.test)
 
 def Assert_set_test(space, w_self, w_new_value):
@@ -4340,8 +4294,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'msg'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'msg')
     return space.wrap(w_self.msg)
 
 def Assert_set_msg(space, w_self, w_new_value):
@@ -4383,14 +4336,13 @@
 def Import_get_names(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'names'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names')
     if w_self.w_names is None:
         if w_self.names is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.names]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_names = w_list
     return w_self.w_names
 
@@ -4430,8 +4382,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'module'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'module')
     return space.wrap(w_self.module)
 
 def ImportFrom_set_module(space, w_self, w_new_value):
@@ -4451,14 +4402,13 @@
 def ImportFrom_get_names(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'names'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names')
     if w_self.w_names is None:
         if w_self.names is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.names]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_names = w_list
     return w_self.w_names
 
@@ -4473,8 +4423,7 @@
             return w_obj
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'level'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'level')
     return space.wrap(w_self.level)
 
 def ImportFrom_set_level(space, w_self, w_new_value):
@@ -4522,8 +4471,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     return space.wrap(w_self.body)
 
 def Exec_set_body(space, w_self, w_new_value):
@@ -4544,8 +4492,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'globals'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'globals')
     return space.wrap(w_self.globals)
 
 def Exec_set_globals(space, w_self, w_new_value):
@@ -4566,8 +4513,7 @@
             return w_obj
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'locals'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'locals')
     return space.wrap(w_self.locals)
 
 def Exec_set_locals(space, w_self, w_new_value):
@@ -4610,14 +4556,13 @@
 def Global_get_names(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'names'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'names')
     if w_self.w_names is None:
         if w_self.names is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.names]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_names = w_list
     return w_self.w_names
 
@@ -4657,8 +4602,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
     return space.wrap(w_self.value)
 
 def Expr_set_value(space, w_self, w_new_value):
@@ -4754,8 +4698,7 @@
             return w_obj
     if not w_self.initialization_state & w_self._lineno_mask:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'lineno'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno')
     return space.wrap(w_self.lineno)
 
 def expr_set_lineno(space, w_self, w_new_value):
@@ -4776,8 +4719,7 @@
             return w_obj
     if not w_self.initialization_state & w_self._col_offset_mask:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'col_offset'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset')
     return space.wrap(w_self.col_offset)
 
 def expr_set_col_offset(space, w_self, w_new_value):
@@ -4807,8 +4749,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'op'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op')
     return boolop_to_class[w_self.op - 1]()
 
 def BoolOp_set_op(space, w_self, w_new_value):
@@ -4827,14 +4768,13 @@
 def BoolOp_get_values(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'values'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values')
     if w_self.w_values is None:
         if w_self.values is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.values]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_values = w_list
     return w_self.w_values
 
@@ -4875,8 +4815,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'left'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'left')
     return space.wrap(w_self.left)
 
 def BinOp_set_left(space, w_self, w_new_value):
@@ -4897,8 +4836,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'op'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op')
     return operator_to_class[w_self.op - 1]()
 
 def BinOp_set_op(space, w_self, w_new_value):
@@ -4921,8 +4859,7 @@
             return w_obj
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'right'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'right')
     return space.wrap(w_self.right)
 
 def BinOp_set_right(space, w_self, w_new_value):
@@ -4969,8 +4906,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'op'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'op')
     return unaryop_to_class[w_self.op - 1]()
 
 def UnaryOp_set_op(space, w_self, w_new_value):
@@ -4993,8 +4929,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'operand'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'operand')
     return space.wrap(w_self.operand)
 
 def UnaryOp_set_operand(space, w_self, w_new_value):
@@ -5040,8 +4975,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'args'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args')
     return space.wrap(w_self.args)
 
 def Lambda_set_args(space, w_self, w_new_value):
@@ -5062,8 +4996,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     return space.wrap(w_self.body)
 
 def Lambda_set_body(space, w_self, w_new_value):
@@ -5109,8 +5042,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'test'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'test')
     return space.wrap(w_self.test)
 
 def IfExp_set_test(space, w_self, w_new_value):
@@ -5131,8 +5063,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     return space.wrap(w_self.body)
 
 def IfExp_set_body(space, w_self, w_new_value):
@@ -5153,8 +5084,7 @@
             return w_obj
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'orelse'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'orelse')
     return space.wrap(w_self.orelse)
 
 def IfExp_set_orelse(space, w_self, w_new_value):
@@ -5197,14 +5127,13 @@
 def Dict_get_keys(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'keys'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'keys')
     if w_self.w_keys is None:
         if w_self.keys is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.keys]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_keys = w_list
     return w_self.w_keys
 
@@ -5215,14 +5144,13 @@
 def Dict_get_values(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'values'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'values')
     if w_self.w_values is None:
         if w_self.values is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.values]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_values = w_list
     return w_self.w_values
 
@@ -5260,14 +5188,13 @@
 def Set_get_elts(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'elts'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts')
     if w_self.w_elts is None:
         if w_self.elts is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.elts]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_elts = w_list
     return w_self.w_elts
 
@@ -5307,8 +5234,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'elt'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt')
     return space.wrap(w_self.elt)
 
 def ListComp_set_elt(space, w_self, w_new_value):
@@ -5325,14 +5251,13 @@
 def ListComp_get_generators(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'generators'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators')
     if w_self.w_generators is None:
         if w_self.generators is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.generators]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_generators = w_list
     return w_self.w_generators
 
@@ -5373,8 +5298,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'elt'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt')
     return space.wrap(w_self.elt)
 
 def SetComp_set_elt(space, w_self, w_new_value):
@@ -5391,14 +5315,13 @@
 def SetComp_get_generators(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'generators'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators')
     if w_self.w_generators is None:
         if w_self.generators is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.generators]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_generators = w_list
     return w_self.w_generators
 
@@ -5439,8 +5362,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'key'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'key')
     return space.wrap(w_self.key)
 
 def DictComp_set_key(space, w_self, w_new_value):
@@ -5461,8 +5383,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
     return space.wrap(w_self.value)
 
 def DictComp_set_value(space, w_self, w_new_value):
@@ -5479,14 +5400,13 @@
 def DictComp_get_generators(space, w_self):
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'generators'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators')
     if w_self.w_generators is None:
         if w_self.generators is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.generators]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_generators = w_list
     return w_self.w_generators
 
@@ -5528,8 +5448,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'elt'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elt')
     return space.wrap(w_self.elt)
 
 def GeneratorExp_set_elt(space, w_self, w_new_value):
@@ -5546,14 +5465,13 @@
 def GeneratorExp_get_generators(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'generators'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'generators')
     if w_self.w_generators is None:
         if w_self.generators is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.generators]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_generators = w_list
     return w_self.w_generators
 
@@ -5594,8 +5512,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
     return space.wrap(w_self.value)
 
 def Yield_set_value(space, w_self, w_new_value):
@@ -5640,8 +5557,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'left'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'left')
     return space.wrap(w_self.left)
 
 def Compare_set_left(space, w_self, w_new_value):
@@ -5658,14 +5574,13 @@
 def Compare_get_ops(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'ops'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ops')
     if w_self.w_ops is None:
         if w_self.ops is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [cmpop_to_class[node - 1]() for node in w_self.ops]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_ops = w_list
     return w_self.w_ops
 
@@ -5676,14 +5591,13 @@
 def Compare_get_comparators(space, w_self):
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'comparators'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'comparators')
     if w_self.w_comparators is None:
         if w_self.comparators is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.comparators]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_comparators = w_list
     return w_self.w_comparators
 
@@ -5726,8 +5640,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'func'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'func')
     return space.wrap(w_self.func)
 
 def Call_set_func(space, w_self, w_new_value):
@@ -5744,14 +5657,13 @@
 def Call_get_args(space, w_self):
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'args'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args')
     if w_self.w_args is None:
         if w_self.args is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.args]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_args = w_list
     return w_self.w_args
 
@@ -5762,14 +5674,13 @@
 def Call_get_keywords(space, w_self):
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'keywords'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'keywords')
     if w_self.w_keywords is None:
         if w_self.keywords is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.keywords]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_keywords = w_list
     return w_self.w_keywords
 
@@ -5784,8 +5695,7 @@
             return w_obj
     if not w_self.initialization_state & 8:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'starargs'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'starargs')
     return space.wrap(w_self.starargs)
 
 def Call_set_starargs(space, w_self, w_new_value):
@@ -5806,8 +5716,7 @@
             return w_obj
     if not w_self.initialization_state & 16:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'kwargs'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwargs')
     return space.wrap(w_self.kwargs)
 
 def Call_set_kwargs(space, w_self, w_new_value):
@@ -5858,8 +5767,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
     return space.wrap(w_self.value)
 
 def Repr_set_value(space, w_self, w_new_value):
@@ -5904,8 +5812,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'n'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'n')
     return w_self.n
 
 def Num_set_n(space, w_self, w_new_value):
@@ -5950,8 +5857,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 's'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 's')
     return w_self.s
 
 def Str_set_s(space, w_self, w_new_value):
@@ -5996,8 +5902,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
     return space.wrap(w_self.value)
 
 def Attribute_set_value(space, w_self, w_new_value):
@@ -6018,8 +5923,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'attr'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'attr')
     return space.wrap(w_self.attr)
 
 def Attribute_set_attr(space, w_self, w_new_value):
@@ -6040,8 +5944,7 @@
             return w_obj
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'ctx'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx')
     return expr_context_to_class[w_self.ctx - 1]()
 
 def Attribute_set_ctx(space, w_self, w_new_value):
@@ -6090,8 +5993,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
     return space.wrap(w_self.value)
 
 def Subscript_set_value(space, w_self, w_new_value):
@@ -6112,8 +6014,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'slice'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'slice')
     return space.wrap(w_self.slice)
 
 def Subscript_set_slice(space, w_self, w_new_value):
@@ -6134,8 +6035,7 @@
             return w_obj
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'ctx'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx')
     return expr_context_to_class[w_self.ctx - 1]()
 
 def Subscript_set_ctx(space, w_self, w_new_value):
@@ -6184,8 +6084,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'id'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'id')
     return space.wrap(w_self.id)
 
 def Name_set_id(space, w_self, w_new_value):
@@ -6206,8 +6105,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'ctx'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx')
     return expr_context_to_class[w_self.ctx - 1]()
 
 def Name_set_ctx(space, w_self, w_new_value):
@@ -6251,14 +6149,13 @@
 def List_get_elts(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'elts'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts')
     if w_self.w_elts is None:
         if w_self.elts is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.elts]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_elts = w_list
     return w_self.w_elts
 
@@ -6273,8 +6170,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'ctx'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx')
     return expr_context_to_class[w_self.ctx - 1]()
 
 def List_set_ctx(space, w_self, w_new_value):
@@ -6319,14 +6215,13 @@
 def Tuple_get_elts(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'elts'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'elts')
     if w_self.w_elts is None:
         if w_self.elts is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.elts]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_elts = w_list
     return w_self.w_elts
 
@@ -6341,8 +6236,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'ctx'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ctx')
     return expr_context_to_class[w_self.ctx - 1]()
 
 def Tuple_set_ctx(space, w_self, w_new_value):
@@ -6391,8 +6285,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
     return w_self.value
 
 def Const_set_value(space, w_self, w_new_value):
@@ -6510,8 +6403,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'lower'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lower')
     return space.wrap(w_self.lower)
 
 def Slice_set_lower(space, w_self, w_new_value):
@@ -6532,8 +6424,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'upper'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'upper')
     return space.wrap(w_self.upper)
 
 def Slice_set_upper(space, w_self, w_new_value):
@@ -6554,8 +6445,7 @@
             return w_obj
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'step'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'step')
     return space.wrap(w_self.step)
 
 def Slice_set_step(space, w_self, w_new_value):
@@ -6598,14 +6488,13 @@
 def ExtSlice_get_dims(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'dims'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'dims')
     if w_self.w_dims is None:
         if w_self.dims is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.dims]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_dims = w_list
     return w_self.w_dims
 
@@ -6645,8 +6534,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
     return space.wrap(w_self.value)
 
 def Index_set_value(space, w_self, w_new_value):
@@ -6915,8 +6803,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'target'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'target')
     return space.wrap(w_self.target)
 
 def comprehension_set_target(space, w_self, w_new_value):
@@ -6937,8 +6824,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'iter'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'iter')
     return space.wrap(w_self.iter)
 
 def comprehension_set_iter(space, w_self, w_new_value):
@@ -6955,14 +6841,13 @@
 def comprehension_get_ifs(space, w_self):
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'ifs'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'ifs')
     if w_self.w_ifs is None:
         if w_self.ifs is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.ifs]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_ifs = w_list
     return w_self.w_ifs
 
@@ -7004,8 +6889,7 @@
             return w_obj
     if not w_self.initialization_state & w_self._lineno_mask:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'lineno'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'lineno')
     return space.wrap(w_self.lineno)
 
 def excepthandler_set_lineno(space, w_self, w_new_value):
@@ -7026,8 +6910,7 @@
             return w_obj
     if not w_self.initialization_state & w_self._col_offset_mask:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'col_offset'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'col_offset')
     return space.wrap(w_self.col_offset)
 
 def excepthandler_set_col_offset(space, w_self, w_new_value):
@@ -7057,8 +6940,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'type'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'type')
     return space.wrap(w_self.type)
 
 def ExceptHandler_set_type(space, w_self, w_new_value):
@@ -7079,8 +6961,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'name'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name')
     return space.wrap(w_self.name)
 
 def ExceptHandler_set_name(space, w_self, w_new_value):
@@ -7097,14 +6978,13 @@
 def ExceptHandler_get_body(space, w_self):
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'body'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'body')
     if w_self.w_body is None:
         if w_self.body is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.body]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_body = w_list
     return w_self.w_body
 
@@ -7142,14 +7022,13 @@
 def arguments_get_args(space, w_self):
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'args'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'args')
     if w_self.w_args is None:
         if w_self.args is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.args]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_args = w_list
     return w_self.w_args
 
@@ -7164,8 +7043,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'vararg'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'vararg')
     return space.wrap(w_self.vararg)
 
 def arguments_set_vararg(space, w_self, w_new_value):
@@ -7189,8 +7067,7 @@
             return w_obj
     if not w_self.initialization_state & 4:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'kwarg'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'kwarg')
     return space.wrap(w_self.kwarg)
 
 def arguments_set_kwarg(space, w_self, w_new_value):
@@ -7210,14 +7087,13 @@
 def arguments_get_defaults(space, w_self):
     if not w_self.initialization_state & 8:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'defaults'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'defaults')
     if w_self.w_defaults is None:
         if w_self.defaults is None:
-            w_list = space.newlist([])
+            list_w = []
         else:
             list_w = [space.wrap(node) for node in w_self.defaults]
-            w_list = space.newlist(list_w)
+        w_list = space.newlist(list_w)
         w_self.w_defaults = w_list
     return w_self.w_defaults
 
@@ -7261,8 +7137,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'arg'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'arg')
     return space.wrap(w_self.arg)
 
 def keyword_set_arg(space, w_self, w_new_value):
@@ -7283,8 +7158,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'value'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'value')
     return space.wrap(w_self.value)
 
 def keyword_set_value(space, w_self, w_new_value):
@@ -7330,8 +7204,7 @@
             return w_obj
     if not w_self.initialization_state & 1:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'name'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'name')
     return space.wrap(w_self.name)
 
 def alias_set_name(space, w_self, w_new_value):
@@ -7352,8 +7225,7 @@
             return w_obj
     if not w_self.initialization_state & 2:
         typename = space.type(w_self).getname(space)
-        w_err = space.wrap("'%s' object has no attribute 'asname'" % typename)
-        raise OperationError(space.w_AttributeError, w_err)
+        raise operationerrfmt(space.w_AttributeError, "'%s' object has no attribute '%s'", typename, 'asname')
     return space.wrap(w_self.asname)
 
 def alias_set_asname(space, w_self, w_new_value):
diff --git a/pypy/interpreter/astcompiler/tools/asdl_py.py b/pypy/interpreter/astcompiler/tools/asdl_py.py
--- a/pypy/interpreter/astcompiler/tools/asdl_py.py
+++ b/pypy/interpreter/astcompiler/tools/asdl_py.py
@@ -414,13 +414,12 @@
             self.emit("        return w_obj", 1)
         self.emit("if not w_self.initialization_state & %s:" % (flag,), 1)
         self.emit("typename = space.type(w_self).getname(space)", 2)
-        self.emit("w_err = space.wrap(\"'%%s' object has no attribute '%s'\" %% typename)" %
+        self.emit("raise operationerrfmt(space.w_AttributeError, \"'%%s' object has no attribute '%%s'\", typename, '%s')" %
                   (field.name,), 2)
-        self.emit("raise OperationError(space.w_AttributeError, w_err)", 2)
         if field.seq:
             self.emit("if w_self.w_%s is None:" % (field.name,), 1)
             self.emit("if w_self.%s is None:" % (field.name,), 2)
-            self.emit("w_list = space.newlist([])", 3)
+            self.emit("list_w = []", 3)
             self.emit("else:", 2)
             if field.type.value in self.data.simple_types:
                 wrapper = "%s_to_class[node - 1]()" % (field.type,)
@@ -428,7 +427,7 @@
                 wrapper = "space.wrap(node)"
             self.emit("list_w = [%s for node in w_self.%s]" %
                       (wrapper, field.name), 3)
-            self.emit("w_list = space.newlist(list_w)", 3)
+            self.emit("w_list = space.newlist(list_w)", 2)
             self.emit("w_self.w_%s = w_list" % (field.name,), 2)
             self.emit("return w_self.w_%s" % (field.name,), 1)
         elif field.type.value in self.data.simple_types:
@@ -540,7 +539,7 @@
 from pypy.interpreter.baseobjspace import Wrappable
 from pypy.interpreter import typedef
 from pypy.interpreter.gateway import interp2app
-from pypy.interpreter.error import OperationError
+from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.tool.pairtype import extendabletype
 from pypy.tool.sourcetools import func_with_new_name
@@ -639,9 +638,7 @@
             missing = required[i]
             if missing is not None:
                  err = "required field \\"%s\\" missing from %s"
-                 err = err % (missing, host)
-                 w_err = space.wrap(err)
-                 raise OperationError(space.w_TypeError, w_err)
+                 raise operationerrfmt(space.w_TypeError, err, missing, host)
     raise AssertionError("should not reach here")
 
 
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -391,8 +391,11 @@
     def decrement_ticker(self, by):
         value = self._ticker
         if self.has_bytecode_counter:    # this 'if' is constant-folded
-            value -= by
-            self._ticker = value
+            if jit.isconstant(by) and by == 0:
+                pass     # normally constant-folded too
+            else:
+                value -= by
+                self._ticker = value
         return value
 
 
diff --git a/pypy/interpreter/pyparser/pytokenizer.py b/pypy/interpreter/pyparser/pytokenizer.py
--- a/pypy/interpreter/pyparser/pytokenizer.py
+++ b/pypy/interpreter/pyparser/pytokenizer.py
@@ -226,7 +226,7 @@
                         parenlev = parenlev - 1
                         if parenlev < 0:
                             raise TokenError("unmatched '%s'" % initial, line,
-                                             lnum-1, 0, token_list)
+                                             lnum, start + 1, token_list)
                     if token in python_opmap:
                         punct = python_opmap[token]
                     else:
diff --git a/pypy/interpreter/pyparser/test/test_pyparse.py b/pypy/interpreter/pyparser/test/test_pyparse.py
--- a/pypy/interpreter/pyparser/test/test_pyparse.py
+++ b/pypy/interpreter/pyparser/test/test_pyparse.py
@@ -87,6 +87,10 @@
         assert exc.lineno == 1
         assert exc.offset == 5
         assert exc.lastlineno == 5
+        exc = py.test.raises(SyntaxError, parse, "abc)").value
+        assert exc.msg == "unmatched ')'"
+        assert exc.lineno == 1
+        assert exc.offset == 4
 
     def test_is(self):
         self.parse("x is y")
diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -7,9 +7,7 @@
 import weakref
 from pypy.objspace.flow.model import Variable, Constant
 from pypy.annotation import model as annmodel
-from pypy.jit.metainterp.history import (ConstInt, ConstPtr,
-                                         BoxInt, BoxPtr, BoxObj, BoxFloat,
-                                         REF, INT, FLOAT)
+from pypy.jit.metainterp.history import REF, INT, FLOAT
 from pypy.jit.codewriter import heaptracker
 from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr, rffi
 from pypy.rpython.ootypesystem import ootype
@@ -17,7 +15,7 @@
 from pypy.rpython.llinterp import LLException
 from pypy.rpython.extregistry import ExtRegistryEntry
 
-from pypy.jit.metainterp import resoperation, executor
+from pypy.jit.metainterp import resoperation
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.backend.llgraph import symbolic
 from pypy.jit.codewriter import longlong
@@ -165,6 +163,7 @@
     'unicodegetitem'  : (('ref', 'int'), 'int'),
     'unicodesetitem'  : (('ref', 'int', 'int'), 'int'),
     'cast_ptr_to_int' : (('ref',), 'int'),
+    'cast_int_to_ptr' : (('int',), 'ref'),
     'debug_merge_point': (('ref', 'int'), None),
     'force_token'     : ((), 'int'),
     'call_may_force'  : (('int', 'varargs'), 'intorptr'),
@@ -333,6 +332,13 @@
     assert isinstance(type, str) and len(type) == 1
     op.descr = Descr(ofs, type, arg_types=arg_types)
 
+def compile_add_descr_arg(loop, ofs, type, arg_types):
+    from pypy.jit.backend.llgraph.runner import Descr
+    loop = _from_opaque(loop)
+    op = loop.operations[-1]
+    assert isinstance(type, str) and len(type) == 1
+    op.args.append(Descr(ofs, type, arg_types=arg_types))
+
 def compile_add_loop_token(loop, descr):
     if we_are_translated():
         raise ValueError("CALL_ASSEMBLER not supported")
@@ -437,8 +443,11 @@
         self._may_force = -1
 
     def getenv(self, v):
+        from pypy.jit.backend.llgraph.runner import Descr
         if isinstance(v, Constant):
             return v.value
+        elif isinstance(v, Descr):
+            return v
         else:
             return self.env[v]
 
@@ -806,6 +815,29 @@
         else:
             raise NotImplementedError
 
+    def op_getinteriorfield_gc(self, descr, array, index):
+        if descr.typeinfo == REF:
+            return do_getinteriorfield_gc_ptr(array, index, descr.ofs)
+        elif descr.typeinfo == INT:
+            return do_getinteriorfield_gc_int(array, index, descr.ofs)
+        elif descr.typeinfo == FLOAT:
+            return do_getinteriorfield_gc_float(array, index, descr.ofs)
+        else:
+            raise NotImplementedError
+
+    def op_setinteriorfield_gc(self, descr, array, index, newvalue):
+        if descr.typeinfo == REF:
+            return do_setinteriorfield_gc_ptr(array, index, descr.ofs,
+                                              newvalue)
+        elif descr.typeinfo == INT:
+            return do_setinteriorfield_gc_int(array, index, descr.ofs,
+                                              newvalue)
+        elif descr.typeinfo == FLOAT:
+            return do_setinteriorfield_gc_float(array, index, descr.ofs,
+                                                newvalue)
+        else:
+            raise NotImplementedError
+
     def op_setfield_gc(self, fielddescr, struct, newvalue):
         if fielddescr.typeinfo == REF:
             do_setfield_gc_ptr(struct, fielddescr.ofs, newvalue)
@@ -875,9 +907,6 @@
     def op_new_array(self, arraydescr, count):
         return do_new_array(arraydescr.ofs, count)
 
-    def op_cast_ptr_to_int(self, descr, ptr):
-        return cast_to_int(ptr)
-
     def op_force_token(self, descr):
         opaque_frame = _to_opaque(self)
         return llmemory.cast_ptr_to_adr(opaque_frame)
@@ -1356,6 +1385,22 @@
 def do_getfield_gc_ptr(struct, fieldnum):
     return cast_to_ptr(_getfield_gc(struct, fieldnum))
 
+def _getinteriorfield_gc(struct, fieldnum):
+    STRUCT, fieldname = symbolic.TokenToField[fieldnum]
+    return getattr(struct, fieldname)
+
+def do_getinteriorfield_gc_int(array, index, fieldnum):
+    struct = array._obj.container.getitem(index)
+    return cast_to_int(_getinteriorfield_gc(struct, fieldnum))
+
+def do_getinteriorfield_gc_float(array, index, fieldnum):
+    struct = array._obj.container.getitem(index)
+    return cast_to_floatstorage(_getinteriorfield_gc(struct, fieldnum))
+
+def do_getinteriorfield_gc_ptr(array, index, fieldnum):
+    struct = array._obj.container.getitem(index)
+    return cast_to_ptr(_getinteriorfield_gc(struct, fieldnum))
+
 def _getfield_raw(struct, fieldnum):
     STRUCT, fieldname = symbolic.TokenToField[fieldnum]
     ptr = cast_from_int(lltype.Ptr(STRUCT), struct)
@@ -1411,26 +1456,28 @@
     newvalue = cast_from_ptr(ITEMTYPE, newvalue)
     array.setitem(index, newvalue)
 
-def do_setfield_gc_int(struct, fieldnum, newvalue):
-    STRUCT, fieldname = symbolic.TokenToField[fieldnum]
-    ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct)
-    FIELDTYPE = getattr(STRUCT, fieldname)
-    newvalue = cast_from_int(FIELDTYPE, newvalue)
-    setattr(ptr, fieldname, newvalue)
+def new_setfield_gc(cast_func):
+    def do_setfield_gc(struct, fieldnum, newvalue):
+        STRUCT, fieldname = symbolic.TokenToField[fieldnum]
+        ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct)
+        FIELDTYPE = getattr(STRUCT, fieldname)
+        newvalue = cast_func(FIELDTYPE, newvalue)
+        setattr(ptr, fieldname, newvalue)
+    return do_setfield_gc
+do_setfield_gc_int = new_setfield_gc(cast_from_int)
+do_setfield_gc_float = new_setfield_gc(cast_from_floatstorage)
+do_setfield_gc_ptr = new_setfield_gc(cast_from_ptr)
 
-def do_setfield_gc_float(struct, fieldnum, newvalue):
-    STRUCT, fieldname = symbolic.TokenToField[fieldnum]
-    ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct)
-    FIELDTYPE = getattr(STRUCT, fieldname)
-    newvalue = cast_from_floatstorage(FIELDTYPE, newvalue)
-    setattr(ptr, fieldname, newvalue)
-
-def do_setfield_gc_ptr(struct, fieldnum, newvalue):
-    STRUCT, fieldname = symbolic.TokenToField[fieldnum]
-    ptr = lltype.cast_opaque_ptr(lltype.Ptr(STRUCT), struct)
-    FIELDTYPE = getattr(STRUCT, fieldname)
-    newvalue = cast_from_ptr(FIELDTYPE, newvalue)
-    setattr(ptr, fieldname, newvalue)
+def new_setinteriorfield_gc(cast_func):
+    def do_setinteriorfield_gc(array, index, fieldnum, newvalue):
+        STRUCT, fieldname = symbolic.TokenToField[fieldnum]
+        struct = array._obj.container.getitem(index)
+        FIELDTYPE = getattr(STRUCT, fieldname)
+        setattr(struct, fieldname, cast_func(FIELDTYPE, newvalue))
+    return do_setinteriorfield_gc
+do_setinteriorfield_gc_int = new_setinteriorfield_gc(cast_from_int)
+do_setinteriorfield_gc_float = new_setinteriorfield_gc(cast_from_floatstorage)
+do_setinteriorfield_gc_ptr = new_setinteriorfield_gc(cast_from_ptr)        
 
 def do_setfield_raw_int(struct, fieldnum, newvalue):
     STRUCT, fieldname = symbolic.TokenToField[fieldnum]
@@ -1696,6 +1743,7 @@
 setannotation(compile_start_float_var, annmodel.SomeInteger())
 setannotation(compile_add, annmodel.s_None)
 setannotation(compile_add_descr, annmodel.s_None)
+setannotation(compile_add_descr_arg, annmodel.s_None)
 setannotation(compile_add_var, annmodel.s_None)
 setannotation(compile_add_int_const, annmodel.s_None)
 setannotation(compile_add_ref_const, annmodel.s_None)
@@ -1743,6 +1791,9 @@
 setannotation(do_getfield_raw_int, annmodel.SomeInteger())
 setannotation(do_getfield_raw_ptr, annmodel.SomePtr(llmemory.GCREF))
 setannotation(do_getfield_raw_float, s_FloatStorage)
+setannotation(do_getinteriorfield_gc_int, annmodel.SomeInteger())
+setannotation(do_getinteriorfield_gc_ptr, annmodel.SomePtr(llmemory.GCREF))
+setannotation(do_getinteriorfield_gc_float, s_FloatStorage)
 setannotation(do_new, annmodel.SomePtr(llmemory.GCREF))
 setannotation(do_new_array, annmodel.SomePtr(llmemory.GCREF))
 setannotation(do_setarrayitem_gc_int, annmodel.s_None)
@@ -1756,6 +1807,9 @@
 setannotation(do_setfield_raw_int, annmodel.s_None)
 setannotation(do_setfield_raw_ptr, annmodel.s_None)
 setannotation(do_setfield_raw_float, annmodel.s_None)
+setannotation(do_setinteriorfield_gc_int, annmodel.s_None)
+setannotation(do_setinteriorfield_gc_ptr, annmodel.s_None)
+setannotation(do_setinteriorfield_gc_float, annmodel.s_None)
 setannotation(do_newstr, annmodel.SomePtr(llmemory.GCREF))
 setannotation(do_strsetitem, annmodel.s_None)
 setannotation(do_newunicode, annmodel.SomePtr(llmemory.GCREF))
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -2,21 +2,19 @@
 Minimal-API wrapper around the llinterpreter to run operations.
 """
 
-import sys
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rpython.lltypesystem import lltype, llmemory, rclass
 from pypy.rpython.ootypesystem import ootype
 from pypy.rpython.llinterp import LLInterpreter
 from pypy.jit.metainterp import history
-from pypy.jit.metainterp.history import REF, INT, FLOAT
+from pypy.jit.metainterp.history import REF, INT, FLOAT, STRUCT
 from pypy.jit.metainterp.warmstate import unwrap
-from pypy.jit.metainterp.resoperation import ResOperation, rop
+from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.backend import model
 from pypy.jit.backend.llgraph import llimpl, symbolic
 from pypy.jit.metainterp.typesystem import llhelper, oohelper
 from pypy.jit.codewriter import heaptracker, longlong
-from pypy.rlib import rgc
 
 class MiniStats:
     pass
@@ -62,6 +60,9 @@
     def is_array_of_floats(self):
         return self.typeinfo == FLOAT
 
+    def is_array_of_structs(self):
+        return self.typeinfo == STRUCT
+
     def as_vtable_size_descr(self):
         return self
 
@@ -177,8 +178,10 @@
             llimpl.compile_add(c, op.getopnum())
             descr = op.getdescr()
             if isinstance(descr, Descr):
-                llimpl.compile_add_descr(c, descr.ofs, descr.typeinfo, descr.arg_types)
-            if isinstance(descr, history.LoopToken) and op.getopnum() != rop.JUMP:
+                llimpl.compile_add_descr(c, descr.ofs, descr.typeinfo,
+                                         descr.arg_types)
+            if (isinstance(descr, history.LoopToken) and
+                op.getopnum() != rop.JUMP):
                 llimpl.compile_add_loop_token(c, descr)
             if self.is_oo and isinstance(descr, (OODescr, MethDescr)):
                 # hack hack, not rpython
@@ -193,6 +196,9 @@
                     llimpl.compile_add_ref_const(c, x.value, self.ts.BASETYPE)
                 elif isinstance(x, history.ConstFloat):
                     llimpl.compile_add_float_const(c, x.value)
+                elif isinstance(x, Descr):
+                    llimpl.compile_add_descr_arg(c, x.ofs, x.typeinfo,
+                                                 x.arg_types)
                 else:
                     raise Exception("'%s' args contain: %r" % (op.getopname(),
                                                                x))
@@ -316,6 +322,13 @@
         token = history.getkind(getattr(S, fieldname))
         return self.getdescr(ofs, token[0], name=fieldname)
 
+    def interiorfielddescrof(self, A, fieldname):
+        S = A.OF
+        ofs2 = symbolic.get_size(A)
+        ofs, size = symbolic.get_field_token(S, fieldname)
+        token = history.getkind(getattr(S, fieldname))
+        return self.getdescr(ofs, token[0], name=fieldname, extrainfo=ofs2)
+
     def calldescrof(self, FUNC, ARGS, RESULT, extrainfo):
         arg_types = []
         for ARG in ARGS:
@@ -353,8 +366,13 @@
     def arraydescrof(self, A):
         assert A.OF != lltype.Void
         size = symbolic.get_size(A)
-        token = history.getkind(A.OF)
-        return self.getdescr(size, token[0])
+        if isinstance(A.OF, lltype.Ptr) or isinstance(A.OF, lltype.Primitive):
+            token = history.getkind(A.OF)[0]
+        elif isinstance(A.OF, lltype.Struct):
+            token = 's'
+        else:
+            token = '?'
+        return self.getdescr(size, token)
 
     # ---------- the backend-dependent operations ----------
 
@@ -406,6 +424,29 @@
         assert isinstance(fielddescr, Descr)
         return llimpl.do_getfield_raw_float(struct, fielddescr.ofs)
 
+    def bh_getinteriorfield_gc_i(self, array, index, descr):
+        assert isinstance(descr, Descr)
+        return llimpl.do_getinteriorfield_gc_int(array, index, descr.ofs)
+    def bh_getinteriorfield_gc_r(self, array, index, descr):
+        assert isinstance(descr, Descr)
+        return llimpl.do_getinteriorfield_gc_ptr(array, index, descr.ofs)
+    def bh_getinteriorfield_gc_f(self, array, index, descr):
+        assert isinstance(descr, Descr)
+        return llimpl.do_getinteriorfield_gc_float(array, index, descr.ofs)
+
+    def bh_setinteriorfield_gc_i(self, array, index, descr, value):
+        assert isinstance(descr, Descr)
+        return llimpl.do_setinteriorfield_gc_int(array, index, descr.ofs,
+                                                 value)
+    def bh_setinteriorfield_gc_r(self, array, index, descr, value):
+        assert isinstance(descr, Descr)
+        return llimpl.do_setinteriorfield_gc_ptr(array, index, descr.ofs,
+                                                 value)
+    def bh_setinteriorfield_gc_f(self, array, index, descr, value):
+        assert isinstance(descr, Descr)
+        return llimpl.do_setinteriorfield_gc_float(array, index, descr.ofs,
+                                                   value)
+
     def bh_new(self, sizedescr):
         assert isinstance(sizedescr, Descr)
         return llimpl.do_new(sizedescr.ofs)
@@ -418,7 +459,6 @@
 
     def bh_classof(self, struct):
         struct = lltype.cast_opaque_ptr(rclass.OBJECTPTR, struct)
-        result = struct.typeptr
         result_adr = llmemory.cast_ptr_to_adr(struct.typeptr)
         return heaptracker.adr2int(result_adr)
 
diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py
--- a/pypy/jit/backend/llsupport/descr.py
+++ b/pypy/jit/backend/llsupport/descr.py
@@ -1,13 +1,10 @@
 import py
-from pypy.rpython.lltypesystem import lltype, rffi, llmemory, rclass
+from pypy.rpython.lltypesystem import lltype, rffi, llmemory
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.jit.backend.llsupport import symbolic, support
-from pypy.jit.metainterp.history import AbstractDescr, getkind, BoxInt, BoxPtr
-from pypy.jit.metainterp.history import BasicFailDescr, LoopToken, BoxFloat
+from pypy.jit.metainterp.history import AbstractDescr, getkind
 from pypy.jit.metainterp import history
-from pypy.jit.metainterp.resoperation import ResOperation, rop
 from pypy.jit.codewriter import heaptracker, longlong
-from pypy.rlib.rarithmetic import r_longlong, r_ulonglong
 
 # The point of the class organization in this file is to make instances
 # as compact as possible.  This is done by not storing the field size or
@@ -23,6 +20,7 @@
         self._cache_field = {}
         self._cache_array = {}
         self._cache_call = {}
+        self._cache_interiorfield = {}
 
     def init_size_descr(self, STRUCT, sizedescr):
         assert isinstance(STRUCT, lltype.GcStruct)
@@ -142,7 +140,6 @@
         cachedict[fieldname] = fielddescr
         return fielddescr
 
-
 # ____________________________________________________________
 # ArrayDescrs
 
@@ -167,6 +164,7 @@
 
     _is_array_of_pointers = False      # unless overridden by GcPtrArrayDescr
     _is_array_of_floats   = False      # unless overridden by FloatArrayDescr
+    _is_array_of_structs  = False      # unless overridden by StructArrayDescr
     _is_item_signed       = False      # unless overridden by XxxArrayDescr
 
     def is_array_of_pointers(self):
@@ -175,6 +173,9 @@
     def is_array_of_floats(self):
         return self._is_array_of_floats
 
+    def is_array_of_structs(self):
+        return self._is_array_of_structs
+
     def is_item_signed(self):
         return self._is_item_signed
 
@@ -199,6 +200,10 @@
     def get_item_size(self, translate_support_code):
         return symbolic.get_size(lltype.Float, translate_support_code)
 
+class StructArrayDescr(BaseArrayDescr):
+    _clsname = 'StructArrayDescr'
+    _is_array_of_structs = True
+
 class BaseArrayNoLengthDescr(BaseArrayDescr):
     def get_base_size(self, translate_support_code):
         return 0
@@ -218,6 +223,13 @@
 def getArrayDescrClass(ARRAY):
     if ARRAY.OF is lltype.Float:
         return FloatArrayDescr
+    elif isinstance(ARRAY.OF, lltype.Struct):
+        class Descr(StructArrayDescr):
+            _clsname = '%sArrayDescr' % ARRAY.OF._name
+            def get_item_size(self, translate_support_code):
+                return symbolic.get_size(ARRAY.OF, translate_support_code)
+        Descr.__name__ = Descr._clsname
+        return Descr
     return getDescrClass(ARRAY.OF, BaseArrayDescr, GcPtrArrayDescr,
                          NonGcPtrArrayDescr, 'Array', 'get_item_size',
                          '_is_array_of_floats', '_is_item_signed')
@@ -252,6 +264,36 @@
         cache[ARRAY] = arraydescr
         return arraydescr
 
+# ____________________________________________________________
+# InteriorFieldDescr
+
+class InteriorFieldDescr(AbstractDescr):
+    arraydescr = BaseArrayDescr()     # workaround for the annotator
+    fielddescr = BaseFieldDescr('', 0)
+
+    def __init__(self, arraydescr, fielddescr):
+        self.arraydescr = arraydescr
+        self.fielddescr = fielddescr
+
+    def is_pointer_field(self):
+        return self.fielddescr.is_pointer_field()
+
+    def is_float_field(self):
+        return self.fielddescr.is_float_field()
+
+    def repr_of_descr(self):
+        return '<InteriorFieldDescr %s>' % self.fielddescr.repr_of_descr()
+
+def get_interiorfield_descr(gc_ll_descr, ARRAY, FIELDTP, name):
+    cache = gc_ll_descr._cache_interiorfield
+    try:
+        return cache[(ARRAY, FIELDTP, name)]
+    except KeyError:
+        arraydescr = get_array_descr(gc_ll_descr, ARRAY)
+        fielddescr = get_field_descr(gc_ll_descr, FIELDTP, name)
+        descr = InteriorFieldDescr(arraydescr, fielddescr)
+        cache[(ARRAY, FIELDTP, name)] = descr
+        return descr
 
 # ____________________________________________________________
 # CallDescrs
@@ -525,7 +567,8 @@
         #
         if TYPE is lltype.Float or is_longlong(TYPE):
             setattr(Descr, floatattrname, True)
-        elif TYPE is not lltype.Bool and rffi.cast(TYPE, -1) == -1:
+        elif (TYPE is not lltype.Bool and isinstance(TYPE, lltype.Number) and
+              rffi.cast(TYPE, -1) == -1):
             setattr(Descr, signedattrname, True)
         #
         _cache[nameprefix, TYPE] = Descr
diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -45,6 +45,22 @@
     def freeing_block(self, start, stop):
         pass
 
+    def get_funcptr_for_newarray(self):
+        return llhelper(self.GC_MALLOC_ARRAY, self.malloc_array)
+    def get_funcptr_for_newstr(self):
+        return llhelper(self.GC_MALLOC_STR_UNICODE, self.malloc_str)
+    def get_funcptr_for_newunicode(self):
+        return llhelper(self.GC_MALLOC_STR_UNICODE, self.malloc_unicode)
+
+
+    def record_constptrs(self, op, gcrefs_output_list):
+        for i in range(op.numargs()):
+            v = op.getarg(i)
+            if isinstance(v, ConstPtr) and bool(v.value):
+                p = v.value
+                rgc._make_sure_does_not_move(p)
+                gcrefs_output_list.append(p)
+
 # ____________________________________________________________
 
 class GcLLDescr_boehm(GcLLDescription):
@@ -88,6 +104,39 @@
         malloc_fn_ptr = self.configure_boehm_once()
         self.funcptr_for_new = malloc_fn_ptr
 
+        def malloc_array(basesize, itemsize, ofs_length, num_elem):
+            try:
+                size = ovfcheck(basesize + ovfcheck(itemsize * num_elem))
+            except OverflowError:
+                return lltype.nullptr(llmemory.GCREF.TO)
+            res = self.funcptr_for_new(size)
+            if not res:
+                return res
+            rffi.cast(rffi.CArrayPtr(lltype.Signed), res)[ofs_length/WORD] = num_elem
+            return res
+        self.malloc_array = malloc_array
+        self.GC_MALLOC_ARRAY = lltype.Ptr(lltype.FuncType(
+            [lltype.Signed] * 4, llmemory.GCREF))
+
+
+        (str_basesize, str_itemsize, str_ofs_length
+         ) = symbolic.get_array_token(rstr.STR, self.translate_support_code)
+        (unicode_basesize, unicode_itemsize, unicode_ofs_length
+         ) = symbolic.get_array_token(rstr.UNICODE, self.translate_support_code)
+        def malloc_str(length):
+            return self.malloc_array(
+                str_basesize, str_itemsize, str_ofs_length, length
+            )
+        def malloc_unicode(length):
+            return self.malloc_array(
+                unicode_basesize, unicode_itemsize, unicode_ofs_length, length
+            )
+        self.malloc_str = malloc_str
+        self.malloc_unicode = malloc_unicode
+        self.GC_MALLOC_STR_UNICODE = lltype.Ptr(lltype.FuncType(
+            [lltype.Signed], llmemory.GCREF))
+
+
         # on some platform GC_init is required before any other
         # GC_* functions, call it here for the benefit of tests
         # XXX move this to tests
@@ -108,38 +157,34 @@
         ofs_length = arraydescr.get_ofs_length(self.translate_support_code)
         basesize = arraydescr.get_base_size(self.translate_support_code)
         itemsize = arraydescr.get_item_size(self.translate_support_code)
-        size = basesize + itemsize * num_elem
-        res = self.funcptr_for_new(size)
-        rffi.cast(rffi.CArrayPtr(lltype.Signed), res)[ofs_length/WORD] = num_elem
-        return res
+        return self.malloc_array(basesize, itemsize, ofs_length, num_elem)
 
     def gc_malloc_str(self, num_elem):
-        basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.STR,
-                                                   self.translate_support_code)
-        assert itemsize == 1
-        size = basesize + num_elem
-        res = self.funcptr_for_new(size)
-        rffi.cast(rffi.CArrayPtr(lltype.Signed), res)[ofs_length/WORD] = num_elem
-        return res
+        return self.malloc_str(num_elem)
 
     def gc_malloc_unicode(self, num_elem):
-        basesize, itemsize, ofs_length = symbolic.get_array_token(rstr.UNICODE,
-                                                   self.translate_support_code)
-        size = basesize + num_elem * itemsize
-        res = self.funcptr_for_new(size)
-        rffi.cast(rffi.CArrayPtr(lltype.Signed), res)[ofs_length/WORD] = num_elem
-        return res
+        return self.malloc_unicode(num_elem)
 
     def args_for_new(self, sizedescr):
         assert isinstance(sizedescr, BaseSizeDescr)
         return [sizedescr.size]
 
+    def args_for_new_array(self, arraydescr):
+        ofs_length = arraydescr.get_ofs_length(self.translate_support_code)
+        basesize = arraydescr.get_base_size(self.translate_support_code)
+        itemsize = arraydescr.get_item_size(self.translate_support_code)
+        return [basesize, itemsize, ofs_length]
+
     def get_funcptr_for_new(self):
         return self.funcptr_for_new
 
-    get_funcptr_for_newarray = None
-    get_funcptr_for_newstr = None
-    get_funcptr_for_newunicode = None
+    def rewrite_assembler(self, cpu, operations, gcrefs_output_list):
+        # record all GCREFs too, because Boehm cannot see them and keep them
+        # alive if they end up as constants in the assembler
+        for op in operations:
+            self.record_constptrs(op, gcrefs_output_list)
+        return GcLLDescription.rewrite_assembler(self, cpu, operations,
+                                                 gcrefs_output_list)
 
 
 # ____________________________________________________________
@@ -738,15 +783,6 @@
     def get_funcptr_for_new(self):
         return llhelper(self.GC_MALLOC_BASIC, self.malloc_basic)
 
-    def get_funcptr_for_newarray(self):
-        return llhelper(self.GC_MALLOC_ARRAY, self.malloc_array)
-
-    def get_funcptr_for_newstr(self):
-        return llhelper(self.GC_MALLOC_STR_UNICODE, self.malloc_str)
-
-    def get_funcptr_for_newunicode(self):
-        return llhelper(self.GC_MALLOC_STR_UNICODE, self.malloc_unicode)
-
     def do_write_barrier(self, gcref_struct, gcref_newptr):
         hdr_addr = llmemory.cast_ptr_to_adr(gcref_struct)
         hdr_addr -= self.gcheaderbuilder.size_gc_header
@@ -759,14 +795,6 @@
             funcptr(llmemory.cast_ptr_to_adr(gcref_struct),
                     llmemory.cast_ptr_to_adr(gcref_newptr))
 
-    def record_constptrs(self, op, gcrefs_output_list):
-        for i in range(op.numargs()):
-            v = op.getarg(i)
-            if isinstance(v, ConstPtr) and bool(v.value):
-                p = v.value
-                rgc._make_sure_does_not_move(p)
-                gcrefs_output_list.append(p)
-
     def rewrite_assembler(self, cpu, operations, gcrefs_output_list):
         # Perform two kinds of rewrites in parallel:
         #
diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py
--- a/pypy/jit/backend/llsupport/llmodel.py
+++ b/pypy/jit/backend/llsupport/llmodel.py
@@ -1,24 +1,18 @@
-import sys
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass, rstr
 from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rpython.llinterp import LLInterpreter, LLException
+from pypy.rpython.llinterp import LLInterpreter
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rlib.objectmodel import we_are_translated, specialize
-from pypy.jit.metainterp.history import BoxInt, BoxPtr, set_future_values,\
-     BoxFloat
 from pypy.jit.metainterp import history
 from pypy.jit.codewriter import heaptracker, longlong
 from pypy.jit.backend.model import AbstractCPU
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.backend.llsupport.symbolic import WORD, unroll_basic_sizes
-from pypy.jit.backend.llsupport.descr import get_size_descr,  BaseSizeDescr
-from pypy.jit.backend.llsupport.descr import get_field_descr, BaseFieldDescr
-from pypy.jit.backend.llsupport.descr import get_array_descr, BaseArrayDescr
-from pypy.jit.backend.llsupport.descr import get_call_descr
-from pypy.jit.backend.llsupport.descr import BaseIntCallDescr, GcPtrCallDescr
-from pypy.jit.backend.llsupport.descr import FloatCallDescr, VoidCallDescr
+from pypy.jit.backend.llsupport.descr import (get_size_descr,
+     get_field_descr, BaseFieldDescr, get_array_descr, BaseArrayDescr,
+     get_call_descr, BaseIntCallDescr, GcPtrCallDescr, FloatCallDescr,
+     VoidCallDescr, InteriorFieldDescr, get_interiorfield_descr)
 from pypy.jit.backend.llsupport.asmmemmgr import AsmMemoryManager
-from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
 
 
 class AbstractLLCPU(AbstractCPU):
@@ -243,6 +237,9 @@
     def arraydescrof(self, A):
         return get_array_descr(self.gc_ll_descr, A)
 
+    def interiorfielddescrof(self, A, fieldname):
+        return get_interiorfield_descr(self.gc_ll_descr, A, A.OF, fieldname)
+
     def unpack_arraydescr(self, arraydescr):
         assert isinstance(arraydescr, BaseArrayDescr)
         return arraydescr.get_base_size(self.translate_support_code)
@@ -360,6 +357,100 @@
     bh_getarrayitem_raw_i = bh_getarrayitem_gc_i
     bh_getarrayitem_raw_f = bh_getarrayitem_gc_f
 
+    def bh_getinteriorfield_gc_i(self, gcref, itemindex, descr):
+        assert isinstance(descr, InteriorFieldDescr)
+        arraydescr = descr.arraydescr
+        ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+        ofs += descr.fielddescr.offset
+        fieldsize = descr.fielddescr.get_field_size(self.translate_support_code)
+        sign = descr.fielddescr.is_field_signed()
+        fullofs = itemindex * size + ofs
+        # --- start of GC unsafe code (no GC operation!) ---
+        items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), fullofs)
+        for STYPE, UTYPE, itemsize in unroll_basic_sizes:
+            if fieldsize == itemsize:
+                if sign:
+                    item = rffi.cast(rffi.CArrayPtr(STYPE), items)
+                    val = item[0]
+                    val = rffi.cast(lltype.Signed, val)
+                else:
+                    item = rffi.cast(rffi.CArrayPtr(UTYPE), items)
+                    val = item[0]
+                    val = rffi.cast(lltype.Signed, val)
+                # --- end of GC unsafe code ---
+                return val
+        else:
+            raise NotImplementedError("size = %d" % fieldsize)
+
+    def bh_getinteriorfield_gc_r(self, gcref, itemindex, descr):
+        assert isinstance(descr, InteriorFieldDescr)
+        arraydescr = descr.arraydescr
+        ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+        ofs += descr.fielddescr.offset
+        # --- start of GC unsafe code (no GC operation!) ---
+        items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs +
+                            size * itemindex)
+        items = rffi.cast(rffi.CArrayPtr(lltype.Signed), items)
+        pval = self._cast_int_to_gcref(items[0])
+        # --- end of GC unsafe code ---
+        return pval
+
+    def bh_getinteriorfield_gc_f(self, gcref, itemindex, descr):
+        assert isinstance(descr, InteriorFieldDescr)
+        arraydescr = descr.arraydescr
+        ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+        ofs += descr.fielddescr.offset
+        # --- start of GC unsafe code (no GC operation!) ---
+        items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs +
+                            size * itemindex)
+        items = rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), items)
+        fval = items[0]
+        # --- end of GC unsafe code ---
+        return fval
+
+    def bh_setinteriorfield_gc_i(self, gcref, itemindex, descr, value):
+        assert isinstance(descr, InteriorFieldDescr)
+        arraydescr = descr.arraydescr
+        ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+        ofs += descr.fielddescr.offset
+        fieldsize = descr.fielddescr.get_field_size(self.translate_support_code)
+        ofs = itemindex * size + ofs
+        # --- start of GC unsafe code (no GC operation!) ---
+        items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref), ofs)
+        for TYPE, _, itemsize in unroll_basic_sizes:
+            if fieldsize == itemsize:
+                items = rffi.cast(rffi.CArrayPtr(TYPE), items)
+                items[0] = rffi.cast(TYPE, value)
+                # --- end of GC unsafe code ---
+                return
+        else:
+            raise NotImplementedError("size = %d" % fieldsize)
+
+    def bh_setinteriorfield_gc_r(self, gcref, itemindex, descr, newvalue):
+        assert isinstance(descr, InteriorFieldDescr)
+        arraydescr = descr.arraydescr
+        ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+        ofs += descr.fielddescr.offset
+        self.gc_ll_descr.do_write_barrier(gcref, newvalue)
+        # --- start of GC unsafe code (no GC operation!) ---
+        items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref),
+                            ofs + size * itemindex)
+        items = rffi.cast(rffi.CArrayPtr(lltype.Signed), items)
+        items[0] = self.cast_gcref_to_int(newvalue)
+        # --- end of GC unsafe code ---
+
+    def bh_setinteriorfield_gc_f(self, gcref, itemindex, descr, newvalue):
+        assert isinstance(descr, InteriorFieldDescr)
+        arraydescr = descr.arraydescr
+        ofs, size, _ = self.unpack_arraydescr_size(arraydescr)
+        ofs += descr.fielddescr.offset
+        # --- start of GC unsafe code (no GC operation!) ---
+        items = rffi.ptradd(rffi.cast(rffi.CCHARP, gcref),
+                            ofs + size * itemindex)
+        items = rffi.cast(rffi.CArrayPtr(longlong.FLOATSTORAGE), items)
+        items[0] = newvalue
+        # --- end of GC unsafe code ---
+
     def bh_strlen(self, string):
         s = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), string)
         return len(s.chars)
@@ -477,7 +568,6 @@
 
     def bh_classof(self, struct):
         struct = lltype.cast_opaque_ptr(rclass.OBJECTPTR, struct)
-        result = struct.typeptr
         result_adr = llmemory.cast_ptr_to_adr(struct.typeptr)
         return heaptracker.adr2int(result_adr)
 
diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py
--- a/pypy/jit/backend/llsupport/regalloc.py
+++ b/pypy/jit/backend/llsupport/regalloc.py
@@ -288,7 +288,6 @@
         self.reg_bindings[to_v] = reg
 
     def _move_variable_away(self, v, prev_loc):
-        reg = None
         if self.free_regs:
             loc = self.free_regs.pop()
             self.reg_bindings[v] = loc
diff --git a/pypy/jit/backend/llsupport/test/test_asmmemmgr.py b/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
--- a/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
+++ b/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
@@ -211,14 +211,14 @@
     debug._log = debug.DebugLog()
     try:
         mc._dump(addr, 'test-logname-section')
-        log = list(debug._log)
+        log = list(debug._log) 
     finally:
         debug._log = None
     encoded = ''.join(writtencode).encode('hex').upper()
     ataddr = '@%x' % addr
     assert log == [('test-logname-section',
                     [('debug_print', 'CODE_DUMP', ataddr, '+0 ', encoded)])]
-    #
+    
     lltype.free(p, flavor='raw')
 
 def test_blockbuildermixin2():
diff --git a/pypy/jit/backend/llsupport/test/test_descr.py b/pypy/jit/backend/llsupport/test/test_descr.py
--- a/pypy/jit/backend/llsupport/test/test_descr.py
+++ b/pypy/jit/backend/llsupport/test/test_descr.py
@@ -3,7 +3,6 @@
 from pypy.jit.backend.llsupport import symbolic
 from pypy.rlib.objectmodel import Symbolic
 from pypy.rpython.annlowlevel import llhelper
-from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr
 from pypy.jit.metainterp import history
 from pypy.jit.codewriter import longlong
 import sys, struct, py
@@ -149,7 +148,9 @@
     A2 = lltype.GcArray(lltype.Ptr(T))
     A3 = lltype.GcArray(lltype.Ptr(U))
     A4 = lltype.GcArray(lltype.Float)
-    A5 = lltype.GcArray(lltype.SingleFloat)
+    A5 = lltype.GcArray(lltype.Struct('x', ('v', lltype.Signed),
+                                      ('k', lltype.Signed)))
+    A6 = lltype.GcArray(lltype.SingleFloat)
     assert getArrayDescrClass(A2) is GcPtrArrayDescr
     assert getArrayDescrClass(A3) is NonGcPtrArrayDescr
     cls = getArrayDescrClass(A1)
@@ -158,7 +159,7 @@
     clsf = getArrayDescrClass(A4)
     assert clsf != cls
     assert clsf == getArrayDescrClass(lltype.GcArray(lltype.Float))
-    clss = getArrayDescrClass(A5)
+    clss = getArrayDescrClass(A6)
     assert clss not in (clsf, cls)
     assert clss == getArrayDescrClass(lltype.GcArray(rffi.UINT))
     #
@@ -168,11 +169,12 @@
     descr3 = get_array_descr(c0, A3)
     descr4 = get_array_descr(c0, A4)
     descr5 = get_array_descr(c0, A5)
+    descr6 = get_array_descr(c0, A6)
     assert descr1.__class__ is cls
     assert descr2.__class__ is GcPtrArrayDescr
     assert descr3.__class__ is NonGcPtrArrayDescr
     assert descr4.__class__ is clsf
-    assert descr5.__class__ is clss
+    assert descr6.__class__ is clss
     assert descr1 == get_array_descr(c0, lltype.GcArray(lltype.Char))
     assert not descr1.is_array_of_pointers()
     assert     descr2.is_array_of_pointers()
@@ -202,7 +204,8 @@
     assert descr2.get_item_size(False) == rffi.sizeof(lltype.Ptr(T))
     assert descr3.get_item_size(False) == rffi.sizeof(lltype.Ptr(U))
     assert descr4.get_item_size(False) == rffi.sizeof(lltype.Float)
-    assert descr5.get_item_size(False) == rffi.sizeof(lltype.SingleFloat)
+    assert descr5.get_item_size(False) == rffi.sizeof(lltype.Signed) * 2
+    assert descr6.get_item_size(False) == rffi.sizeof(lltype.SingleFloat)
     #
     assert isinstance(descr1.get_base_size(True), Symbolic)
     assert isinstance(descr2.get_base_size(True), Symbolic)
@@ -348,7 +351,6 @@
                             (rffi.SHORT,      True), (rffi.USHORT, False),
                             (rffi.INT,        True), (rffi.UINT,   False),
                             (rffi.LONG,       True), (rffi.ULONG,  False)]:
-        A = lltype.GcArray(RESTYPE)
         for tsc in [False, True]:
             c2 = GcCache(tsc)
             descr1 = get_call_descr(c2, [], RESTYPE)
@@ -379,7 +381,6 @@
     descr3i = get_array_descr(c0, lltype.GcArray(lltype.Char))
     assert descr3i.repr_of_descr() == '<CharArrayDescr>'
     #
-    cache = {}
     descr4 = get_call_descr(c0, [lltype.Char, lltype.Ptr(S)], lltype.Ptr(S))
     assert 'GcPtrCallDescr' in descr4.repr_of_descr()
     #
@@ -412,10 +413,10 @@
     ARGS = [lltype.Float, lltype.Ptr(ARRAY)]
     RES = lltype.Float
 
-    def f(a, b):
+    def f2(a, b):
         return float(b[0]) + a
 
-    fnptr = llhelper(lltype.Ptr(lltype.FuncType(ARGS, RES)), f)
+    fnptr = llhelper(lltype.Ptr(lltype.FuncType(ARGS, RES)), f2)
     descr2 = get_call_descr(c0, ARGS, RES)
     a = lltype.malloc(ARRAY, 3)
     opaquea = lltype.cast_opaque_ptr(llmemory.GCREF, a)
diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py
--- a/pypy/jit/backend/model.py
+++ b/pypy/jit/backend/model.py
@@ -1,5 +1,5 @@
 from pypy.rlib.debug import debug_start, debug_print, debug_stop
-from pypy.jit.metainterp import history, compile
+from pypy.jit.metainterp import history
 
 
 class AbstractCPU(object):
@@ -218,6 +218,10 @@
     def typedescrof(TYPE):
         raise NotImplementedError
 
+    @staticmethod
+    def interiorfielddescrof(A, fieldname):
+        raise NotImplementedError
+
     # ---------- the backend-dependent operations ----------
 
     # lltype specific operations
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -143,7 +143,7 @@
             ]
         inputargs = [i0]
         operations[2].setfailargs([i1])
-        
+
         self.cpu.compile_loop(inputargs, operations, looptoken)
         self.cpu.set_future_value_int(0, 2)
         fail = self.cpu.execute_token(looptoken)
@@ -164,7 +164,7 @@
             ]
         inputargs = [i0]
         operations[2].setfailargs([None, None, i1, None])
-        
+
         self.cpu.compile_loop(inputargs, operations, looptoken)
         self.cpu.set_future_value_int(0, 2)
         fail = self.cpu.execute_token(looptoken)
@@ -388,7 +388,7 @@
         for opnum, boxargs, retvalue in get_int_tests():
             res = self.execute_operation(opnum, boxargs, 'int')
             assert res.value == retvalue
-        
+
     def test_float_operations(self):
         from pypy.jit.metainterp.test.test_executor import get_float_tests
         for opnum, boxargs, rettype, retvalue in get_float_tests(self.cpu):
@@ -454,7 +454,7 @@
 
     def test_ovf_operations_reversed(self):
         self.test_ovf_operations(reversed=True)
-        
+
     def test_bh_call(self):
         cpu = self.cpu
         #
@@ -566,7 +566,7 @@
         funcbox = self.get_funcbox(self.cpu, func_ptr)
         res = self.execute_operation(rop.CALL, [funcbox] + map(BoxInt, args), 'int', descr=calldescr)
         assert res.value == func(*args)
-        
+
     def test_call_stack_alignment(self):
         # test stack alignment issues, notably for Mac OS/X.
         # also test the ordering of the arguments.
@@ -640,7 +640,7 @@
         res = self.execute_operation(rop.GETFIELD_GC, [t_box],
                                      'int', descr=shortdescr)
         assert res.value == 1331
-        
+
         #
         u_box, U_box = self.alloc_instance(self.U)
         fielddescr2 = self.cpu.fielddescrof(self.S, 'next')
@@ -720,7 +720,7 @@
 
     def test_failing_guard_class(self):
         t_box, T_box = self.alloc_instance(self.T)
-        u_box, U_box = self.alloc_instance(self.U)        
+        u_box, U_box = self.alloc_instance(self.U)
         null_box = self.null_instance()
         for opname, args in [(rop.GUARD_CLASS, [t_box, U_box]),
                              (rop.GUARD_CLASS, [u_box, T_box]),
@@ -812,7 +812,7 @@
         r = self.execute_operation(rop.GETARRAYITEM_GC, [a_box, BoxInt(3)],
                                    'int', descr=arraydescr)
         assert r.value == 160
-        
+
         #
         if isinstance(A, lltype.GcArray):
             A = lltype.Ptr(A)
@@ -905,6 +905,73 @@
                                    'int', descr=arraydescr)
         assert r.value == 7441
 
+    def test_array_of_structs(self):
+        TP = lltype.GcStruct('x')
+        ITEM = lltype.Struct('x',
+                             ('vs', lltype.Signed),
+                             ('vu', lltype.Unsigned),
+                             ('vsc', rffi.SIGNEDCHAR),
+                             ('vuc', rffi.UCHAR),
+                             ('vss', rffi.SHORT),
+                             ('vus', rffi.USHORT),
+                             ('vsi', rffi.INT),
+                             ('vui', rffi.UINT),
+                             ('k', lltype.Float),
+                             ('p', lltype.Ptr(TP)))
+        a_box, A = self.alloc_array_of(ITEM, 15)
+        s_box, S = self.alloc_instance(TP)
+        kdescr = self.cpu.interiorfielddescrof(A, 'k')
+        pdescr = self.cpu.interiorfielddescrof(A, 'p')
+        self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3),
+                                                         boxfloat(1.5)],
+                               'void', descr=kdescr)
+        f = self.cpu.bh_getinteriorfield_gc_f(a_box.getref_base(), 3, kdescr)
+        assert longlong.getrealfloat(f) == 1.5
+        self.cpu.bh_setinteriorfield_gc_f(a_box.getref_base(), 3, kdescr, longlong.getfloatstorage(2.5))
+        r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)],
+                                   'float', descr=kdescr)
+        assert r.getfloat() == 2.5
+        #
+        NUMBER_FIELDS = [('vs', lltype.Signed),
+                         ('vu', lltype.Unsigned),
+                         ('vsc', rffi.SIGNEDCHAR),
+                         ('vuc', rffi.UCHAR),
+                         ('vss', rffi.SHORT),
+                         ('vus', rffi.USHORT),
+                         ('vsi', rffi.INT),
+                         ('vui', rffi.UINT)]
+        for name, TYPE in NUMBER_FIELDS[::-1]:
+            vdescr = self.cpu.interiorfielddescrof(A, name)
+            self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(3),
+                                                             BoxInt(-15)],
+                                   'void', descr=vdescr)
+        for name, TYPE in NUMBER_FIELDS:
+            vdescr = self.cpu.interiorfielddescrof(A, name)
+            i = self.cpu.bh_getinteriorfield_gc_i(a_box.getref_base(), 3,
+                                                  vdescr)
+            assert i == rffi.cast(lltype.Signed, rffi.cast(TYPE, -15))
+        for name, TYPE in NUMBER_FIELDS[::-1]:
+            vdescr = self.cpu.interiorfielddescrof(A, name)
+            self.cpu.bh_setinteriorfield_gc_i(a_box.getref_base(), 3,
+                                              vdescr, -25)
+        for name, TYPE in NUMBER_FIELDS:
+            vdescr = self.cpu.interiorfielddescrof(A, name)
+            r = self.execute_operation(rop.GETINTERIORFIELD_GC,
+                                       [a_box, BoxInt(3)],
+                                       'int', descr=vdescr)
+            assert r.getint() == rffi.cast(lltype.Signed, rffi.cast(TYPE, -25))
+        #
+        self.execute_operation(rop.SETINTERIORFIELD_GC, [a_box, BoxInt(4),
+                                                         s_box],
+                               'void', descr=pdescr)
+        r = self.cpu.bh_getinteriorfield_gc_r(a_box.getref_base(), 4, pdescr)
+        assert r == s_box.getref_base()
+        self.cpu.bh_setinteriorfield_gc_r(a_box.getref_base(), 3, pdescr,
+                                          s_box.getref_base())
+        r = self.execute_operation(rop.GETINTERIORFIELD_GC, [a_box, BoxInt(3)],
+                                   'ref', descr=pdescr)
+        assert r.getref_base() == s_box.getref_base()
+
     def test_string_basic(self):
         s_box = self.alloc_string("hello\xfe")
         r = self.execute_operation(rop.STRLEN, [s_box], 'int')
@@ -1429,7 +1496,7 @@
         addr = llmemory.cast_ptr_to_adr(func_ptr)
         return ConstInt(heaptracker.adr2int(addr))
 
-    
+
     MY_VTABLE = rclass.OBJECT_VTABLE    # for tests only
 
     S = lltype.GcForwardReference()
@@ -1495,20 +1562,16 @@
         return u''.join(u.chars)
 
 
-    def test_casts(self):
-        py.test.skip("xxx fix or kill")
-        from pypy.rpython.lltypesystem import lltype, llmemory
-        TP = lltype.GcStruct('x')
-        x = lltype.malloc(TP)        
-        x = lltype.cast_opaque_ptr(llmemory.GCREF, x)
+    def test_cast_int_to_ptr(self):
+        res = self.execute_operation(rop.CAST_INT_TO_PTR,
+                                     [BoxInt(-17)],  'ref').value
+        assert lltype.cast_ptr_to_int(res) == -17
+
+    def test_cast_ptr_to_int(self):
+        x = lltype.cast_int_to_ptr(llmemory.GCREF, -19)
         res = self.execute_operation(rop.CAST_PTR_TO_INT,
-                                     [BoxPtr(x)],  'int').value
-        expected = self.cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(x))
-        assert rffi.get_real_int(res) == rffi.get_real_int(expected)
-        res = self.execute_operation(rop.CAST_PTR_TO_INT,
-                                     [ConstPtr(x)],  'int').value
-        expected = self.cpu.cast_adr_to_int(llmemory.cast_ptr_to_adr(x))
-        assert rffi.get_real_int(res) == rffi.get_real_int(expected)
+                                     [BoxPtr(x)], 'int').value
+        assert res == -19
 
     def test_ooops_non_gc(self):
         x = lltype.malloc(lltype.Struct('x'), flavor='raw')
@@ -2328,13 +2391,6 @@
         #
         cpu.bh_strsetitem(x, 4, ord('/'))
         assert str.chars[4] == '/'
-        #
-##        x = cpu.bh_newstr(5)
-##        y = cpu.bh_cast_ptr_to_int(x)
-##        z = cpu.bh_cast_ptr_to_int(x)
-##        y = rffi.get_real_int(y)
-##        z = rffi.get_real_int(z)
-##        assert type(y) == type(z) == int and y == z
 
     def test_sorting_of_fields(self):
         S = self.S
@@ -2358,7 +2414,7 @@
         for opname, arg, res in ops:
             self.execute_operation(opname, [arg], 'void')
             assert self.guard_failed == res
-        
+
         lltype.free(x, flavor='raw')
 
     def test_assembler_call(self):
@@ -3028,4 +3084,4 @@
 
     def alloc_unicode(self, unicode):
         py.test.skip("implement me")
-    
+
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -1,7 +1,7 @@
 import sys, os
 from pypy.jit.backend.llsupport import symbolic
 from pypy.jit.backend.llsupport.asmmemmgr import MachineDataBlockWrapper
-from pypy.jit.metainterp.history import Const, Box, BoxInt, BoxPtr, BoxFloat
+from pypy.jit.metainterp.history import Const, Box, BoxInt, ConstInt
 from pypy.jit.metainterp.history import (AbstractFailDescr, INT, REF, FLOAT,
                                          LoopToken)
 from pypy.rpython.lltypesystem import lltype, rffi, rstr, llmemory
@@ -36,7 +36,6 @@
 from pypy.rlib import rgc
 from pypy.rlib.clibffi import FFI_DEFAULT_ABI
 from pypy.jit.backend.x86.jump import remap_frame_layout
-from pypy.jit.metainterp.history import ConstInt, BoxInt
 from pypy.jit.codewriter.effectinfo import EffectInfo
 from pypy.jit.codewriter import longlong
 
@@ -729,8 +728,8 @@
         # Also, make sure this is consistent with FRAME_FIXED_SIZE.
         self.mc.PUSH_r(ebp.value)
         self.mc.MOV_rr(ebp.value, esp.value)
-        for regloc in self.cpu.CALLEE_SAVE_REGISTERS:
-            self.mc.PUSH_r(regloc.value)
+        for loc in self.cpu.CALLEE_SAVE_REGISTERS:
+            self.mc.PUSH_r(loc.value)
 
         gcrootmap = self.cpu.gc_ll_descr.gcrootmap
         if gcrootmap and gcrootmap.is_shadow_stack:
@@ -994,7 +993,7 @@
         effectinfo = op.getdescr().get_extra_info()
         oopspecindex = effectinfo.oopspecindex
         genop_llong_list[oopspecindex](self, op, arglocs, resloc)
-        
+
     def regalloc_perform_math(self, op, arglocs, resloc):
         effectinfo = op.getdescr().get_extra_info()
         oopspecindex = effectinfo.oopspecindex
@@ -1311,7 +1310,7 @@
     genop_guard_float_eq = _cmpop_guard_float("E", "E", "NE","NE")
     genop_guard_float_gt = _cmpop_guard_float("A", "B", "BE","AE")
     genop_guard_float_ge = _cmpop_guard_float("AE","BE", "B", "A")
-    
+
     def genop_math_sqrt(self, op, arglocs, resloc):
         self.mc.SQRTSD(arglocs[0], resloc)
 
@@ -1387,7 +1386,8 @@
 
     def genop_same_as(self, op, arglocs, resloc):
         self.mov(arglocs[0], resloc)
-    #genop_cast_ptr_to_int = genop_same_as
+    genop_cast_ptr_to_int = genop_same_as
+    genop_cast_int_to_ptr = genop_same_as
 
     def genop_int_mod(self, op, arglocs, resloc):
         if IS_X86_32:
@@ -1596,12 +1596,27 @@
     genop_getarrayitem_gc_pure = genop_getarrayitem_gc
     genop_getarrayitem_raw = genop_getarrayitem_gc
 
+    def genop_getinteriorfield_gc(self, op, arglocs, resloc):
+        base_loc, ofs_loc, itemsize_loc, fieldsize_loc, index_loc, sign_loc = arglocs
+        # XXX should not use IMUL in most cases
+        self.mc.IMUL(index_loc, itemsize_loc)
+        src_addr = AddressLoc(base_loc, index_loc, 0, ofs_loc.value)
+        self.load_from_mem(resloc, src_addr, fieldsize_loc, sign_loc)
+
+
     def genop_discard_setfield_gc(self, op, arglocs):
         base_loc, ofs_loc, size_loc, value_loc = arglocs
         assert isinstance(size_loc, ImmedLoc)
         dest_addr = AddressLoc(base_loc, ofs_loc)
         self.save_into_mem(dest_addr, value_loc, size_loc)
 
+    def genop_discard_setinteriorfield_gc(self, op, arglocs):
+        base_loc, ofs_loc, itemsize_loc, fieldsize_loc, index_loc, value_loc = arglocs
+        # XXX should not use IMUL in most cases
+        self.mc.IMUL(index_loc, itemsize_loc)
+        dest_addr = AddressLoc(base_loc, index_loc, 0, ofs_loc.value)
+        self.save_into_mem(dest_addr, value_loc, fieldsize_loc)
+
     def genop_discard_setarrayitem_gc(self, op, arglocs):
         base_loc, ofs_loc, value_loc, size_loc, baseofs = arglocs
         assert isinstance(baseofs, ImmedLoc)
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -7,7 +7,7 @@
                                          ResOperation, BoxPtr, ConstFloat,
                                          BoxFloat, LoopToken, INT, REF, FLOAT)
 from pypy.jit.backend.x86.regloc import *
-from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi, rstr
+from pypy.rpython.lltypesystem import lltype, rffi, rstr
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib import rgc
 from pypy.jit.backend.llsupport import symbolic
@@ -17,11 +17,12 @@
 from pypy.jit.metainterp.resoperation import rop
 from pypy.jit.backend.llsupport.descr import BaseFieldDescr, BaseArrayDescr
 from pypy.jit.backend.llsupport.descr import BaseCallDescr, BaseSizeDescr
+from pypy.jit.backend.llsupport.descr import InteriorFieldDescr
 from pypy.jit.backend.llsupport.regalloc import FrameManager, RegisterManager,\
      TempBox, compute_vars_longevity, compute_loop_consts
 from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE
 from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64, MY_COPY_OF_REGS
-from pypy.rlib.rarithmetic import r_longlong, r_uint
+from pypy.rlib.rarithmetic import r_longlong
 
 class X86RegisterManager(RegisterManager):
 
@@ -423,7 +424,7 @@
             if self.can_merge_with_next_guard(op, i, operations):
                 oplist_with_guard[op.getopnum()](self, op, operations[i + 1])
                 i += 1
-            elif not we_are_translated() and op.getopnum() == -124: 
+            elif not we_are_translated() and op.getopnum() == -124:
                 self._consider_force_spill(op)
             else:
                 oplist[op.getopnum()](self, op)
@@ -765,7 +766,7 @@
         save_all_regs = guard_not_forced_op is not None
         self.xrm.before_call(force_store, save_all_regs=save_all_regs)
         if not save_all_regs:
-            gcrootmap = gc_ll_descr = self.assembler.cpu.gc_ll_descr.gcrootmap
+            gcrootmap = self.assembler.cpu.gc_ll_descr.gcrootmap
             if gcrootmap and gcrootmap.is_shadow_stack:
                 save_all_regs = 2
         self.rm.before_call(force_store, save_all_regs=save_all_regs)
@@ -922,74 +923,27 @@
             return self._call(op, arglocs)
 
     def consider_newstr(self, op):
-        gc_ll_descr = self.assembler.cpu.gc_ll_descr
-        if gc_ll_descr.get_funcptr_for_newstr is not None:
-            # framework GC
-            loc = self.loc(op.getarg(0))
-            return self._call(op, [loc])
-        # boehm GC (XXX kill the following code at some point)
-        ofs_items, itemsize, ofs = symbolic.get_array_token(rstr.STR, self.translate_support_code)
-        assert itemsize == 1
-        return self._malloc_varsize(ofs_items, ofs, 0, op.getarg(0),
-                                    op.result)
+        loc = self.loc(op.getarg(0))
+        return self._call(op, [loc])
 
     def consider_newunicode(self, op):
-        gc_ll_descr = self.assembler.cpu.gc_ll_descr
-        if gc_ll_descr.get_funcptr_for_newunicode is not None:
-            # framework GC
-            loc = self.loc(op.getarg(0))
-            return self._call(op, [loc])
-        # boehm GC (XXX kill the following code at some point)
-        ofs_items, _, ofs = symbolic.get_array_token(rstr.UNICODE,
-                                                   self.translate_support_code)
-        scale = self._get_unicode_item_scale()
-        return self._malloc_varsize(ofs_items, ofs, scale, op.getarg(0),
-                                    op.result)
-
-    def _malloc_varsize(self, ofs_items, ofs_length, scale, v, res_v):
-        # XXX kill this function at some point
-        if isinstance(v, Box):
-            loc = self.rm.make_sure_var_in_reg(v, [v])
-            tempbox = TempBox()
-            other_loc = self.rm.force_allocate_reg(tempbox, [v])
-            self.assembler.load_effective_addr(loc, ofs_items,scale, other_loc)
-        else:
-            tempbox = None
-            other_loc = imm(ofs_items + (v.getint() << scale))
-        self._call(ResOperation(rop.NEW, [], res_v),
-                   [other_loc], [v])
-        loc = self.rm.make_sure_var_in_reg(v, [res_v])
-        assert self.loc(res_v) == eax
-        # now we have to reload length to some reasonable place
-        self.rm.possibly_free_var(v)
-        if tempbox is not None:
-            self.rm.possibly_free_var(tempbox)
-        self.PerformDiscard(ResOperation(rop.SETFIELD_GC, [None, None], None),
-                            [eax, imm(ofs_length), imm(WORD), loc])
+        loc = self.loc(op.getarg(0))
+        return self._call(op, [loc])
 
     def consider_new_array(self, op):
         gc_ll_descr = self.assembler.cpu.gc_ll_descr
-        if gc_ll_descr.get_funcptr_for_newarray is not None:
-            # framework GC
-            box_num_elem = op.getarg(0)
-            if isinstance(box_num_elem, ConstInt):
-                num_elem = box_num_elem.value
-                if gc_ll_descr.can_inline_malloc_varsize(op.getdescr(),
-                                                         num_elem):
-                    self.fastpath_malloc_varsize(op, op.getdescr(), num_elem)
-                    return
-            args = self.assembler.cpu.gc_ll_descr.args_for_new_array(
-                op.getdescr())
-            arglocs = [imm(x) for x in args]
-            arglocs.append(self.loc(box_num_elem))
-            self._call(op, arglocs)
-            return
-        # boehm GC (XXX kill the following code at some point)
-        itemsize, basesize, ofs_length, _, _ = (
-            self._unpack_arraydescr(op.getdescr()))
-        scale_of_field = _get_scale(itemsize)
-        self._malloc_varsize(basesize, ofs_length, scale_of_field,
-                             op.getarg(0), op.result)
+        box_num_elem = op.getarg(0)
+        if isinstance(box_num_elem, ConstInt):
+            num_elem = box_num_elem.value
+            if gc_ll_descr.can_inline_malloc_varsize(op.getdescr(),
+                                                     num_elem):
+                self.fastpath_malloc_varsize(op, op.getdescr(), num_elem)
+                return
+        args = self.assembler.cpu.gc_ll_descr.args_for_new_array(
+            op.getdescr())
+        arglocs = [imm(x) for x in args]
+        arglocs.append(self.loc(box_num_elem))
+        self._call(op, arglocs)
 
     def _unpack_arraydescr(self, arraydescr):
         assert isinstance(arraydescr, BaseArrayDescr)
@@ -1008,6 +962,16 @@
         sign = fielddescr.is_field_signed()
         return imm(ofs), imm(size), ptr, sign
 
+    def _unpack_interiorfielddescr(self, descr):
+        assert isinstance(descr, InteriorFieldDescr)
+        arraydescr = descr.arraydescr
+        ofs = arraydescr.get_base_size(self.translate_support_code)
+        itemsize = arraydescr.get_item_size(self.translate_support_code)
+        fieldsize = descr.fielddescr.get_field_size(self.translate_support_code)
+        sign = descr.fielddescr.is_field_signed()
+        ofs += descr.fielddescr.offset
+        return imm(ofs), imm(itemsize), imm(fieldsize), sign
+
     def consider_setfield_gc(self, op):
         ofs_loc, size_loc, _, _ = self._unpack_fielddescr(op.getdescr())
         assert isinstance(size_loc, ImmedLoc)
@@ -1024,6 +988,21 @@
 
     consider_setfield_raw = consider_setfield_gc
 
+    def consider_setinteriorfield_gc(self, op):
+        t = self._unpack_interiorfielddescr(op.getdescr())
+        ofs, itemsize, fieldsize, _ = t
+        args = op.getarglist()
+        tmpvar = TempBox()
+        base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args)
+        index_loc = self.rm.force_result_in_reg(tmpvar, op.getarg(1),
+                                                args)
+        # we're free to modify index now
+        value_loc = self.make_sure_var_in_reg(op.getarg(2), args)
+        self.possibly_free_vars(args)
+        self.rm.possibly_free_var(tmpvar)
+        self.PerformDiscard(op, [base_loc, ofs, itemsize, fieldsize,
+                                 index_loc, value_loc])
+
     def consider_strsetitem(self, op):
         args = op.getarglist()
         base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args)
@@ -1085,6 +1064,24 @@
     consider_getarrayitem_raw = consider_getarrayitem_gc
     consider_getarrayitem_gc_pure = consider_getarrayitem_gc
 
+    def consider_getinteriorfield_gc(self, op):
+        t = self._unpack_interiorfielddescr(op.getdescr())
+        ofs, itemsize, fieldsize, sign = t
+        if sign:
+            sign_loc = imm1
+        else:
+            sign_loc = imm0
+        args = op.getarglist()
+        tmpvar = TempBox()
+        base_loc = self.rm.make_sure_var_in_reg(op.getarg(0), args)
+        index_loc = self.rm.force_result_in_reg(tmpvar, op.getarg(1),
+                                                args)
+        self.rm.possibly_free_vars_for_op(op)
+        self.rm.possibly_free_var(tmpvar)
+        result_loc = self.force_allocate_reg(op.result)
+        self.Perform(op, [base_loc, ofs, itemsize, fieldsize,
+                          index_loc, sign_loc], result_loc)
+
     def consider_int_is_true(self, op, guard_op):
         # doesn't need arg to be in a register
         argloc = self.loc(op.getarg(0))
@@ -1102,7 +1099,8 @@
         self.possibly_free_var(op.getarg(0))
         resloc = self.force_allocate_reg(op.result)
         self.Perform(op, [argloc], resloc)
-    #consider_cast_ptr_to_int = consider_same_as
+    consider_cast_ptr_to_int = consider_same_as
+    consider_cast_int_to_ptr = consider_same_as
 
     def consider_strlen(self, op):
         args = op.getarglist()
@@ -1190,7 +1188,6 @@
         self.rm.possibly_free_var(srcaddr_box)
 
     def _gen_address_inside_string(self, baseloc, ofsloc, resloc, is_unicode):
-        cpu = self.assembler.cpu
         if is_unicode:
             ofs_items, _, _ = symbolic.get_array_token(rstr.UNICODE,
                                                   self.translate_support_code)
@@ -1249,7 +1246,7 @@
         tmpreg = X86RegisterManager.all_regs[0]
         tmploc = self.rm.force_allocate_reg(box, selected_reg=tmpreg)
         xmmtmp = X86XMMRegisterManager.all_regs[0]
-        xmmtmploc = self.xrm.force_allocate_reg(box1, selected_reg=xmmtmp)
+        self.xrm.force_allocate_reg(box1, selected_reg=xmmtmp)
         # Part about non-floats
         # XXX we don't need a copy, we only just the original list
         src_locations1 = [self.loc(op.getarg(i)) for i in range(op.numargs())
@@ -1329,7 +1326,7 @@
     return lambda self, op: fn(self, op, None)
 
 def is_comparison_or_ovf_op(opnum):
-    from pypy.jit.metainterp.resoperation import opclasses, AbstractResOp
+    from pypy.jit.metainterp.resoperation import opclasses
     cls = opclasses[opnum]
     # hack hack: in theory they are instance method, but they don't use
     # any instance field, we can use a fake object
diff --git a/pypy/jit/backend/x86/test/test_del.py b/pypy/jit/backend/x86/test/test_del.py
--- a/pypy/jit/backend/x86/test/test_del.py
+++ b/pypy/jit/backend/x86/test/test_del.py
@@ -1,5 +1,4 @@
 
-import py
 from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
 from pypy.jit.metainterp.test.test_del import DelTests
 
diff --git a/pypy/jit/backend/x86/test/test_dict.py b/pypy/jit/backend/x86/test/test_dict.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/backend/x86/test/test_dict.py
@@ -0,0 +1,9 @@
+
+from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
+from pypy.jit.metainterp.test.test_dict import DictTests
+
+
+class TestDict(Jit386Mixin, DictTests):
+    # for the individual tests see
+    # ====> ../../../metainterp/test/test_dict.py
+    pass
diff --git a/pypy/jit/backend/x86/test/test_runner.py b/pypy/jit/backend/x86/test/test_runner.py
--- a/pypy/jit/backend/x86/test/test_runner.py
+++ b/pypy/jit/backend/x86/test/test_runner.py
@@ -31,7 +31,7 @@
 
     # for the individual tests see
     # ====> ../../test/runner_test.py
-    
+
     def setup_method(self, meth):
         self.cpu = CPU(rtyper=None, stats=FakeStats())
         self.cpu.setup_once()
@@ -69,22 +69,16 @@
 
     def test_allocations(self):
         from pypy.rpython.lltypesystem import rstr
-        
+
         allocs = [None]
         all = []
+        orig_new = self.cpu.gc_ll_descr.funcptr_for_new
         def f(size):
             allocs.insert(0, size)
-            buf = ctypes.create_string_buffer(size)
-            all.append(buf)
-            return ctypes.cast(buf, ctypes.c_void_p).value
-        func = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)(f)
-        addr = ctypes.cast(func, ctypes.c_void_p).value
-        # ctypes produces an unsigned value. We need it to be signed for, eg,
-        # relative addressing to work properly.
-        addr = rffi.cast(lltype.Signed, addr)
-        
+            return orig_new(size)
+
         self.cpu.assembler.setup_once()
-        self.cpu.assembler.malloc_func_addr = addr
+        self.cpu.gc_ll_descr.funcptr_for_new = f
         ofs = symbolic.get_field_token(rstr.STR, 'chars', False)[0]
 
         res = self.execute_operation(rop.NEWSTR, [ConstInt(7)], 'ref')
@@ -108,7 +102,7 @@
         res = self.execute_operation(rop.NEW_ARRAY, [ConstInt(10)],
                                          'ref', descr)
         assert allocs[0] == 10*WORD + ofs + WORD
-        resbuf = self._resbuf(res)            
+        resbuf = self._resbuf(res)
         assert resbuf[ofs/WORD] == 10
 
         # ------------------------------------------------------------
@@ -116,7 +110,7 @@
         res = self.execute_operation(rop.NEW_ARRAY, [BoxInt(10)],
                                          'ref', descr)
         assert allocs[0] == 10*WORD + ofs + WORD
-        resbuf = self._resbuf(res)                        
+        resbuf = self._resbuf(res)
         assert resbuf[ofs/WORD] == 10
 
     def test_stringitems(self):
@@ -146,7 +140,7 @@
                                                      ConstInt(2), BoxInt(38)],
                                'void', descr)
         assert resbuf[itemsofs/WORD + 2] == 38
-        
+
         self.execute_operation(rop.SETARRAYITEM_GC, [res,
                                                      BoxInt(3), BoxInt(42)],
                                'void', descr)
@@ -167,7 +161,7 @@
                                                          BoxInt(2)],
                                    'int', descr)
         assert r.value == 38
-        
+
         r = self.execute_operation(rop.GETARRAYITEM_GC, [res, BoxInt(3)],
                                    'int', descr)
         assert r.value == 42
@@ -226,7 +220,7 @@
         self.execute_operation(rop.SETFIELD_GC, [res, BoxInt(1234)], 'void', ofs_i)
         i = self.execute_operation(rop.GETFIELD_GC, [res], 'int', ofs_i)
         assert i.value == 1234
-        
+
         #u = self.execute_operation(rop.GETFIELD_GC, [res, ofs_u], 'int')
         #assert u.value == 5
         self.execute_operation(rop.SETFIELD_GC, [res, ConstInt(1)], 'void',
@@ -299,7 +293,7 @@
                     else:
                         assert result != execute(self.cpu, None,
                                                  op, None, b).value
-                    
+
 
     def test_stuff_followed_by_guard(self):
         boxes = [(BoxInt(1), BoxInt(0)),
@@ -523,7 +517,7 @@
     def test_debugger_on(self):
         from pypy.tool.logparser import parse_log_file, extract_category
         from pypy.rlib import debug
-        
+
         loop = """
         [i0]
         debug_merge_point('xyz', 0)
diff --git a/pypy/jit/backend/x86/tool/viewcode.py b/pypy/jit/backend/x86/tool/viewcode.py
--- a/pypy/jit/backend/x86/tool/viewcode.py
+++ b/pypy/jit/backend/x86/tool/viewcode.py
@@ -9,7 +9,12 @@
 """
 
 import autopath
-import operator, sys, os, re, py, new
+import new
+import operator
+import py
+import re
+import sys
+import subprocess
 from bisect import bisect_left
 
 # don't use pypy.tool.udir here to avoid removing old usessions which
@@ -44,14 +49,16 @@
     f = open(tmpfile, 'wb')
     f.write(data)
     f.close()
-    g = os.popen(objdump % {
+    p = subprocess.Popen(objdump % {
         'file': tmpfile,
         'origin': originaddr,
         'backend': objdump_backend_option[backend_name],
-    }, 'r')
-    result = g.readlines()
-    g.close()
-    lines = result[6:]   # drop some objdump cruft
+    }, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    stdout, stderr = p.communicate()
+    assert not p.returncode, ('Encountered an error running objdump: %s' %
+                              stderr)
+    # drop some objdump cruft
+    lines = stdout.splitlines()[6:]
     return format_code_dump_with_labels(originaddr, lines, label_list)
 
 def format_code_dump_with_labels(originaddr, lines, label_list):
@@ -85,8 +92,12 @@
     #
     print 'loading symbols from %s...' % (filename,)
     symbols = {}
-    g = os.popen(symbollister % filename, "r")
-    for line in g:
+    p = subprocess.Popen(symbollister % filename, shell=True,
+                         stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    stdout, stderr = p.communicate()
+    assert not p.returncode, ('Encountered an error running nm: %s' %
+                              stderr)
+    for line in stdout.splitlines():
         match = re_symbolentry.match(line)
         if match:
             addr = long(match.group(1), 16)
@@ -94,7 +105,6 @@
             if name.startswith('pypy_g_'):
                 name = '\xb7' + name[7:]
             symbols[addr] = name
-    g.close()
     print '%d symbols found' % (len(symbols),)
     return symbols
 
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -52,9 +52,11 @@
         newoperations = []
         #
         def do_rename(var, var_or_const):
+            if var.concretetype is lltype.Void:
+                renamings[var] = Constant(None, lltype.Void)
+                return
             renamings[var] = var_or_const
-            if (isinstance(var_or_const, Constant)
-                and var.concretetype != lltype.Void):
+            if isinstance(var_or_const, Constant):
                 value = var_or_const.value
                 value = lltype._cast_whatever(var.concretetype, value)
                 renamings_constants[var] = Constant(value, var.concretetype)
@@ -455,6 +457,23 @@
             # the special return value None forces op.result to be considered
             # equal to op.args[0]
             return [op0, op1, None]
+        if (hints.get('promote_string') and
+            op.args[0].concretetype is not lltype.Void):
+            S = lltype.Ptr(rstr.STR)
+            assert op.args[0].concretetype == S
+            self._register_extra_helper(EffectInfo.OS_STREQ_NONNULL,
+                                        "str.eq_nonnull",
+                                        [S, S],
+                                        lltype.Signed,
+                                        EffectInfo.EF_ELIDABLE_CANNOT_RAISE)
+            descr, p = self.callcontrol.callinfocollection.callinfo_for_oopspec(
+                EffectInfo.OS_STREQ_NONNULL)
+            # XXX this is fairly ugly way of creating a constant,
+            #     however, callinfocollection has no better interface
+            c = Constant(p.adr.ptr, lltype.typeOf(p.adr.ptr))
+            op1 = SpaceOperation('str_guard_value', [op.args[0], c, descr],
+                                 op.result)
+            return [SpaceOperation('-live-', [], None), op1, None]
         else:
             log.WARNING('ignoring hint %r at %r' % (hints, self.graph))
 
@@ -718,29 +737,54 @@
         return SpaceOperation(opname, [op.args[0]], op.result)
 
     def rewrite_op_getinteriorfield(self, op):
-        # only supports strings and unicodes
         assert len(op.args) == 3
-        assert op.args[1].value == 'chars'
         optype = op.args[0].concretetype
         if optype == lltype.Ptr(rstr.STR):
             opname = "strgetitem"
+            return SpaceOperation(opname, [op.args[0], op.args[2]], op.result)
+        elif optype == lltype.Ptr(rstr.UNICODE):
+            opname = "unicodegetitem"
+            return SpaceOperation(opname, [op.args[0], op.args[2]], op.result)
         else:
-            assert optype == lltype.Ptr(rstr.UNICODE)
-            opname = "unicodegetitem"
-        return SpaceOperation(opname, [op.args[0], op.args[2]], op.result)
+            v_inst, v_index, c_field = op.args
+            if op.result.concretetype is lltype.Void:
+                return
+            # only GcArray of Struct supported
+            assert isinstance(v_inst.concretetype.TO, lltype.GcArray)
+            STRUCT = v_inst.concretetype.TO.OF
+            assert isinstance(STRUCT, lltype.Struct)
+            descr = self.cpu.interiorfielddescrof(v_inst.concretetype.TO,
+                                                  c_field.value)
+            args = [v_inst, v_index, descr]
+            kind = getkind(op.result.concretetype)[0]
+            return SpaceOperation('getinteriorfield_gc_%s' % kind, args,
+                                  op.result)
 
     def rewrite_op_setinteriorfield(self, op):
-        # only supports strings and unicodes
         assert len(op.args) == 4
-        assert op.args[1].value == 'chars'
         optype = op.args[0].concretetype
         if optype == lltype.Ptr(rstr.STR):
             opname = "strsetitem"
+            return SpaceOperation(opname, [op.args[0], op.args[2], op.args[3]],
+                                  op.result)
+        elif optype == lltype.Ptr(rstr.UNICODE):
+            opname = "unicodesetitem"
+            return SpaceOperation(opname, [op.args[0], op.args[2], op.args[3]],
+                                  op.result)
         else:
-            assert optype == lltype.Ptr(rstr.UNICODE)
-            opname = "unicodesetitem"
-        return SpaceOperation(opname, [op.args[0], op.args[2], op.args[3]],
-                              op.result)
+            v_inst, v_index, c_field, v_value = op.args
+            if v_value.concretetype is lltype.Void:
+                return
+            # only GcArray of Struct supported
+            assert isinstance(v_inst.concretetype.TO, lltype.GcArray)
+            STRUCT = v_inst.concretetype.TO.OF
+            assert isinstance(STRUCT, lltype.Struct)
+            descr = self.cpu.interiorfielddescrof(v_inst.concretetype.TO,
+                                                  c_field.value)
+            kind = getkind(v_value.concretetype)[0]
+            args = [v_inst, v_index, v_value, descr]
+            return SpaceOperation('setinteriorfield_gc_%s' % kind, args,
+                                  op.result)
 
     def _rewrite_equality(self, op, opname):
         arg0, arg1 = op.args
@@ -783,8 +827,7 @@
 
     def rewrite_op_cast_ptr_to_int(self, op):
         if self._is_gc(op.args[0]):
-            #return op
-            raise NotImplementedError("cast_ptr_to_int")
+            return op
 
     def rewrite_op_force_cast(self, op):
         v_arg = op.args[0]
@@ -1526,6 +1569,10 @@
     def rewrite_op_jit_force_virtual(self, op):
         return self._do_builtin_call(op)
 
+    def rewrite_op_jit_is_virtual(self, op):
+        raise Exception, (
+            "'vref.virtual' should not be used from jit-visible code")
+
     def rewrite_op_jit_force_virtualizable(self, op):
         # this one is for virtualizables
         vinfo = self.get_vinfo(op.args[0])
diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -13,7 +13,6 @@
 from pypy.translator.simplify import get_funcobj
 from pypy.translator.unsimplify import split_block
 from pypy.objspace.flow.model import Constant
-from pypy import conftest
 from pypy.translator.translator import TranslationContext
 from pypy.annotation.policy import AnnotatorPolicy
 from pypy.annotation import model as annmodel
@@ -48,15 +47,13 @@
     a.build_types(func, argtypes, main_entry_point=True)
     rtyper = t.buildrtyper(type_system = type_system)
     rtyper.specialize()
-    if inline:
-        auto_inlining(t, threshold=inline)
+    #if inline:
+    #    auto_inlining(t, threshold=inline)
     if backendoptimize:
         from pypy.translator.backendopt.all import backend_optimizations
         backend_optimizations(t, inline_threshold=inline or 0,
                 remove_asserts=True, really_remove_asserts=True)
 
-    #if conftest.option.view:
-    #    t.view()
     return rtyper
 
 def getgraph(func, values):
@@ -456,6 +453,8 @@
         return LLtypeHelpers._dictnext_items(lltype.Ptr(RES), iter)
     _ll_1_dictiter_nextitems.need_result_type = True
 
+    _ll_1_dict_resize = ll_rdict.ll_dict_resize
+
     # ---------- strings and unicode ----------
 
     _ll_1_str_str2unicode = ll_rstr.LLHelpers.ll_str2unicode
diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py
--- a/pypy/jit/codewriter/test/test_jtransform.py
+++ b/pypy/jit/codewriter/test/test_jtransform.py
@@ -1,4 +1,3 @@
-import py
 import random
 try:
     from itertools import product
@@ -16,13 +15,13 @@
 
 from pypy.objspace.flow.model import FunctionGraph, Block, Link
 from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
-from pypy.jit.codewriter.jtransform import Transformer
-from pypy.jit.metainterp.history import getkind
-from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr, rlist
+from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr
 from pypy.rpython.lltypesystem.module import ll_math
 from pypy.translator.unsimplify import varoftype
 from pypy.jit.codewriter import heaptracker, effectinfo
 from pypy.jit.codewriter.flatten import ListOfKind
+from pypy.jit.codewriter.jtransform import Transformer
+from pypy.jit.metainterp.history import getkind
 
 def const(x):
     return Constant(x, lltype.typeOf(x))
@@ -37,6 +36,8 @@
         return ('calldescr', FUNC, ARGS, RESULT)
     def fielddescrof(self, STRUCT, name):
         return ('fielddescr', STRUCT, name)
+    def interiorfielddescrof(self, ARRAY, name):
+        return ('interiorfielddescr', ARRAY, name)
     def arraydescrof(self, ARRAY):
         return FakeDescr(('arraydescr', ARRAY))
     def sizeof(self, STRUCT):
@@ -99,6 +100,12 @@
             if i == oopspecindex:
                 return True
         return False
+    def callinfo_for_oopspec(self, oopspecindex):
+        assert oopspecindex == effectinfo.EffectInfo.OS_STREQ_NONNULL
+        class c:
+            class adr:
+                ptr = 1
+        return ('calldescr', c)
 
 class FakeBuiltinCallControl:
     def __init__(self):
@@ -119,6 +126,7 @@
              EI.OS_STR2UNICODE:([PSTR], PUNICODE),
              EI.OS_STR_CONCAT: ([PSTR, PSTR], PSTR),
              EI.OS_STR_SLICE:  ([PSTR, INT, INT], PSTR),
+             EI.OS_STREQ_NONNULL:  ([PSTR, PSTR], INT),
              EI.OS_UNI_CONCAT: ([PUNICODE, PUNICODE], PUNICODE),
              EI.OS_UNI_SLICE:  ([PUNICODE, INT, INT], PUNICODE),
              EI.OS_UNI_EQUAL:  ([PUNICODE, PUNICODE], lltype.Bool),
@@ -532,7 +540,7 @@
 
 def test_rename_on_links():
     v1 = Variable()
-    v2 = Variable()
+    v2 = Variable(); v2.concretetype = llmemory.Address
     v3 = Variable()
     block = Block([v1])
     block.operations = [SpaceOperation('cast_pointer', [v1], v2)]
@@ -669,6 +677,22 @@
     assert op1.args == [v, v_index]
     assert op1.result == v_result
 
+def test_dict_getinteriorfield():
+    DICT = lltype.GcArray(lltype.Struct('ENTRY', ('v', lltype.Signed),
+                                        ('k', lltype.Signed)))
+    v = varoftype(lltype.Ptr(DICT))
+    i = varoftype(lltype.Signed)
+    v_result = varoftype(lltype.Signed)
+    op = SpaceOperation('getinteriorfield', [v, i, Constant('v', lltype.Void)],
+                        v_result)
+    op1 = Transformer(FakeCPU()).rewrite_operation(op)
+    assert op1.opname == 'getinteriorfield_gc_i'
+    assert op1.args == [v, i, ('interiorfielddescr', DICT, 'v')]
+    op = SpaceOperation('getinteriorfield', [v, i, Constant('v', lltype.Void)],
+                        Constant(None, lltype.Void))
+    op1 = Transformer(FakeCPU()).rewrite_operation(op)
+    assert op1 is None
+
 def test_str_setinteriorfield():
     v = varoftype(lltype.Ptr(rstr.STR))
     v_index = varoftype(lltype.Signed)
@@ -695,6 +719,23 @@
     assert op1.args == [v, v_index, v_newchr]
     assert op1.result == v_void
 
+def test_dict_setinteriorfield():
+    DICT = lltype.GcArray(lltype.Struct('ENTRY', ('v', lltype.Signed),
+                                        ('k', lltype.Signed)))
+    v = varoftype(lltype.Ptr(DICT))
+    i = varoftype(lltype.Signed)
+    v_void = varoftype(lltype.Void)
+    op = SpaceOperation('setinteriorfield', [v, i, Constant('v', lltype.Void),
+                                             i],
+                        v_void)
+    op1 = Transformer(FakeCPU()).rewrite_operation(op)
+    assert op1.opname == 'setinteriorfield_gc_i'
+    assert op1.args == [v, i, i, ('interiorfielddescr', DICT, 'v')]
+    op = SpaceOperation('setinteriorfield', [v, i, Constant('v', lltype.Void),
+                                             v_void], v_void)
+    op1 = Transformer(FakeCPU()).rewrite_operation(op)
+    assert not op1
+
 def test_promote_1():
     v1 = varoftype(lltype.Signed)
     v2 = varoftype(lltype.Signed)
@@ -844,6 +885,21 @@
     assert op1.args[2] == ListOfKind('ref', [v1, v2])
     assert op1.result == v3
 
+def test_str_promote():
+    PSTR = lltype.Ptr(rstr.STR)
+    v1 = varoftype(PSTR)
+    v2 = varoftype(PSTR)
+    op = SpaceOperation('hint',
+                        [v1, Constant({'promote_string': True}, lltype.Void)],
+                        v2)
+    tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+    op0, op1, _ = tr.rewrite_operation(op)
+    assert op1.opname == 'str_guard_value'
+    assert op1.args[0] == v1
+    assert op1.args[2] == 'calldescr'
+    assert op1.result == v2
+    assert op0.opname == '-live-'
+
 def test_unicode_concat():
     # test that the oopspec is present and correctly transformed
     PSTR = lltype.Ptr(rstr.UNICODE)
diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -2,11 +2,10 @@
 from pypy.rlib.rtimer import read_timestamp
 from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck
 from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.debug import debug_start, debug_stop
+from pypy.rlib.debug import debug_start, debug_stop, ll_assert
 from pypy.rlib.debug import make_sure_not_resized
 from pypy.rpython.lltypesystem import lltype, llmemory, rclass
 from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rpython.llinterp import LLException
 from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr
 from pypy.jit.codewriter import heaptracker, longlong
 from pypy.jit.metainterp.jitexc import JitException, get_llexception, reraise
@@ -503,6 +502,15 @@
     @arguments("r", returns="r")
     def bhimpl_cast_opaque_ptr(a):
         return a
+    @arguments("r", returns="i")
+    def bhimpl_cast_ptr_to_int(a):
+        i = lltype.cast_ptr_to_int(a)
+        ll_assert((i & 1) == 1, "bhimpl_cast_ptr_to_int: not an odd int")
+        return i
+    @arguments("i", returns="r")
+    def bhimpl_cast_int_to_ptr(i):
+        ll_assert((i & 1) == 1, "bhimpl_cast_int_to_ptr: not an odd int")
+        return lltype.cast_int_to_ptr(llmemory.GCREF, i)
 
     @arguments("i", returns="i")
     def bhimpl_int_copy(a):
@@ -523,6 +531,9 @@
     @arguments("f")
     def bhimpl_float_guard_value(a):
         pass
+    @arguments("r", "i", "d", returns="r")
+    def bhimpl_str_guard_value(a, i, d):
+        return a
 
     @arguments("self", "i")
     def bhimpl_int_push(self, a):
@@ -1142,6 +1153,26 @@
         array = cpu.bh_getfield_gc_r(vable, fdescr)
         return cpu.bh_arraylen_gc(adescr, array)
 
+    @arguments("cpu", "r", "i", "d", returns="i")
+    def bhimpl_getinteriorfield_gc_i(cpu, array, index, descr):
+        return cpu.bh_getinteriorfield_gc_i(array, index, descr)
+    @arguments("cpu", "r", "i", "d", returns="r")
+    def bhimpl_getinteriorfield_gc_r(cpu, array, index, descr):
+        return cpu.bh_getinteriorfield_gc_r(array, index, descr)
+    @arguments("cpu", "r", "i", "d", returns="f")
+    def bhimpl_getinteriorfield_gc_f(cpu, array, index, descr):
+        return cpu.bh_getinteriorfield_gc_f(array, index, descr)
+
+    @arguments("cpu", "r", "i", "d", "i")
+    def bhimpl_setinteriorfield_gc_i(cpu, array, index, descr, value):
+        cpu.bh_setinteriorfield_gc_i(array, index, descr, value)
+    @arguments("cpu", "r", "i", "d", "r")
+    def bhimpl_setinteriorfield_gc_r(cpu, array, index, descr, value):
+        cpu.bh_setinteriorfield_gc_r(array, index, descr, value)
+    @arguments("cpu", "r", "i", "d", "f")
+    def bhimpl_setinteriorfield_gc_f(cpu, array, index, descr, value):
+        cpu.bh_setinteriorfield_gc_f(array, index, descr, value)
+
     @arguments("cpu", "r", "d", returns="i")
     def bhimpl_getfield_gc_i(cpu, struct, fielddescr):
         return cpu.bh_getfield_gc_i(struct, fielddescr)
diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py
--- a/pypy/jit/metainterp/executor.py
+++ b/pypy/jit/metainterp/executor.py
@@ -1,11 +1,8 @@
 """This implements pyjitpl's execution of operations.
 """
 
-import py
-from pypy.rpython.lltypesystem import lltype, llmemory, rstr
-from pypy.rpython.ootypesystem import ootype
-from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rlib.rarithmetic import ovfcheck, r_uint, intmask, r_longlong
+from pypy.rpython.lltypesystem import lltype, rstr
+from pypy.rlib.rarithmetic import ovfcheck, r_longlong
 from pypy.rlib.rtimer import read_timestamp
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.jit.metainterp.history import BoxInt, BoxPtr, BoxFloat, check_descr
@@ -123,6 +120,29 @@
     else:
         cpu.bh_setarrayitem_raw_i(arraydescr, array, index, itembox.getint())
 
+def do_getinteriorfield_gc(cpu, _, arraybox, indexbox, descr):
+    array = arraybox.getref_base()
+    index = indexbox.getint()
+    if descr.is_pointer_field():
+        return BoxPtr(cpu.bh_getinteriorfield_gc_r(array, index, descr))
+    elif descr.is_float_field():
+        return BoxFloat(cpu.bh_getinteriorfield_gc_f(array, index, descr))
+    else:
+        return BoxInt(cpu.bh_getinteriorfield_gc_i(array, index, descr))
+
+def do_setinteriorfield_gc(cpu, _, arraybox, indexbox, valuebox, descr):
+    array = arraybox.getref_base()
+    index = indexbox.getint()
+    if descr.is_pointer_field():
+        cpu.bh_setinteriorfield_gc_r(array, index, descr,
+                                     valuebox.getref_base())
+    elif descr.is_float_field():
+        cpu.bh_setinteriorfield_gc_f(array, index, descr,
+                                     valuebox.getfloatstorage())
+    else:
+        cpu.bh_setinteriorfield_gc_i(array, index, descr,
+                                     valuebox.getint())
+
 def do_getfield_gc(cpu, _, structbox, fielddescr):
     struct = structbox.getref_base()
     if fielddescr.is_pointer_field():
diff --git a/pypy/jit/metainterp/graphpage.py b/pypy/jit/metainterp/graphpage.py
--- a/pypy/jit/metainterp/graphpage.py
+++ b/pypy/jit/metainterp/graphpage.py
@@ -12,8 +12,8 @@
     def get_display_text(self):
         return None
 
-def display_loops(loops, errmsg=None, highlight_loops=()):
-    graphs = [(loop, loop in highlight_loops) for loop in loops]    
+def display_loops(loops, errmsg=None, highlight_loops={}):
+    graphs = [(loop, highlight_loops.get(loop, 0)) for loop in loops]    
     for graph, highlight in graphs:
         for op in graph.get_operations():
             if is_interesting_guard(op):
@@ -65,8 +65,7 @@
     def add_graph(self, graph, highlight=False):
         graphindex = len(self.graphs)
         self.graphs.append(graph)
-        if highlight:
-            self.highlight_graphs[graph] = True
+        self.highlight_graphs[graph] = highlight
         for i, op in enumerate(graph.get_operations()):
             self.all_operations[op] = graphindex, i
 
@@ -126,10 +125,13 @@
             self.dotgen.emit('subgraph cluster%d {' % graphindex)
         label = graph.get_display_text()
         if label is not None:
-            if self.highlight_graphs.get(graph):
-                fillcolor = '#f084c2'
+            colorindex = self.highlight_graphs.get(graph, 0)
+            if colorindex == 1:
+                fillcolor = '#f084c2'    # highlighted graph
+            elif colorindex == 2:
+                fillcolor = '#808080'    # invalidated graph
             else:
-                fillcolor = '#84f0c2'
+                fillcolor = '#84f0c2'    # normal color
             self.dotgen.emit_node(graphname, shape="octagon",
                                   label=label, fillcolor=fillcolor)
             self.pendingedges.append((graphname,
diff --git a/pypy/jit/metainterp/heapcache.py b/pypy/jit/metainterp/heapcache.py
--- a/pypy/jit/metainterp/heapcache.py
+++ b/pypy/jit/metainterp/heapcache.py
@@ -54,9 +54,10 @@
         if box in self.new_boxes:
             self.new_boxes[box] = False
         if box in self.dependencies:
-            for dep in self.dependencies[box]:
+            deps = self.dependencies[box]
+            del self.dependencies[box]
+            for dep in deps:
                 self._escape(dep)
-            del self.dependencies[box]
 
     def clear_caches(self, opnum, descr, argboxes):
         if opnum == rop.SETFIELD_GC:
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -9,12 +9,14 @@
 
 from pypy.jit.metainterp.resoperation import ResOperation, rop
 from pypy.jit.codewriter import heaptracker, longlong
+from pypy.rlib.objectmodel import compute_identity_hash
 
 # ____________________________________________________________
 
 INT   = 'i'
 REF   = 'r'
 FLOAT = 'f'
+STRUCT = 's'
 HOLE  = '_'
 VOID  = 'v'
 
@@ -104,7 +106,7 @@
     getref._annspecialcase_ = 'specialize:arg(1)'
 
     def _get_hash_(self):
-        raise NotImplementedError
+        return compute_identity_hash(self)
 
     def clonebox(self):
         raise NotImplementedError
@@ -133,6 +135,9 @@
     def _get_str(self):
         raise NotImplementedError
 
+    def same_box(self, other):
+        return self is other
+
 class AbstractDescr(AbstractValue):
     __slots__ = ()
 
@@ -168,6 +173,11 @@
         """
         raise NotImplementedError
 
+    def is_array_of_structs(self):
+        """ Implement for array descr
+        """
+        raise NotImplementedError
+
     def is_pointer_field(self):
         """ Implement for field descr
         """
@@ -241,32 +251,15 @@
     def constbox(self):
         return self
 
+    def same_box(self, other):
+        return self.same_constant(other)
+
     def same_constant(self, other):
         raise NotImplementedError
 
     def __repr__(self):
         return 'Const(%s)' % self._getrepr_()
 
-    def __eq__(self, other):
-        "NOT_RPYTHON"
-        # Remember that you should not compare Consts with '==' in RPython.
-        # Consts have no special __hash__, in order to force different Consts
-        # from being considered as different keys when stored in dicts
-        # (as they always are after translation).  Use a dict_equal_consts()
-        # to get the other behavior (i.e. using this __eq__).
-        if self.__class__ is not other.__class__:
-            return False
-        try:
-            return self.value == other.value
-        except TypeError:
-            if (isinstance(self.value, Symbolic) and
-                isinstance(other.value, Symbolic)):
-                return self.value is other.value
-            raise
-
-    def __ne__(self, other):
-        return not (self == other)
-
 
 class ConstInt(Const):
     type = INT
@@ -688,33 +681,6 @@
 
 # ____________________________________________________________
 
-def dict_equal_consts():
-    "NOT_RPYTHON"
-    # Returns a dict in which Consts that compare as equal
-    # are identified when used as keys.
-    return r_dict(dc_eq, dc_hash)
-
-def dc_eq(c1, c2):
-    return c1 == c2
-
-def dc_hash(c):
-    "NOT_RPYTHON"
-    # This is called during translation only.  Avoid using identityhash(),
-    # to avoid forcing a hash, at least on lltype objects.
-    if not isinstance(c, Const):
-        return hash(c)
-    if isinstance(c.value, Symbolic):
-        return id(c.value)
-    try:
-        if isinstance(c, ConstPtr):
-            p = lltype.normalizeptr(c.value)
-            if p is not None:
-                return hash(p._obj)
-            else:
-                return 0
-        return c._get_hash_()
-    except lltype.DelayedPointer:
-        return -2      # xxx risk of changing hash...
 
 def make_hashable_int(i):
     from pypy.rpython.lltypesystem.ll2ctypes import NotCtypesAllocatedStructure
@@ -772,6 +738,7 @@
     failed_states = None
     retraced_count = 0
     terminating = False # see TerminatingLoopToken in compile.py
+    invalidated = False
     outermost_jitdriver_sd = None
     # and more data specified by the backend when the loop is compiled
     number = -1
@@ -974,6 +941,7 @@
         self.loops = []
         self.locations = []
         self.aborted_keys = []
+        self.invalidated_token_numbers = set()
 
     def set_history(self, history):
         self.operations = history.operations
@@ -1052,7 +1020,12 @@
             if loop in loops:
                 loops.remove(loop)
             loops.append(loop)
-        display_loops(loops, errmsg, extraloops)
+        highlight_loops = dict.fromkeys(extraloops, 1)
+        for loop in loops:
+            if hasattr(loop, '_looptoken_number') and (
+                    loop._looptoken_number in self.invalidated_token_numbers):
+                highlight_loops.setdefault(loop, 2)
+        display_loops(loops, errmsg, highlight_loops)
 
 # ----------------------------------------------------------------
 
diff --git a/pypy/jit/metainterp/memmgr.py b/pypy/jit/metainterp/memmgr.py
--- a/pypy/jit/metainterp/memmgr.py
+++ b/pypy/jit/metainterp/memmgr.py
@@ -68,7 +68,8 @@
         debug_print("Loop tokens before:", oldtotal)
         max_generation = self.current_generation - (self.max_age-1)
         for looptoken in self.alive_loops.keys():
-            if 0 <= looptoken.generation < max_generation:
+            if (0 <= looptoken.generation < max_generation or
+                looptoken.invalidated):
                 del self.alive_loops[looptoken]
         newtotal = len(self.alive_loops)
         debug_print("Loop tokens freed: ", oldtotal - newtotal)
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -106,10 +106,9 @@
             self.make_equal_to(op.result, v1)
         else:
             self.emit_operation(op)
-
-        # Synthesize the reverse ops for optimize_default to reuse
-        self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0))
-        self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1))
+            # Synthesize the reverse ops for optimize_default to reuse
+            self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0))
+            self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1))
 
     def optimize_INT_ADD(self, op):
         v1 = self.getvalue(op.getarg(0))
@@ -122,10 +121,9 @@
             self.make_equal_to(op.result, v1)
         else:
             self.emit_operation(op)
-
-        # Synthesize the reverse op for optimize_default to reuse
-        self.pure(rop.INT_SUB, [op.result, op.getarg(1)], op.getarg(0))
-        self.pure(rop.INT_SUB, [op.result, op.getarg(0)], op.getarg(1))
+            # Synthesize the reverse op for optimize_default to reuse
+            self.pure(rop.INT_SUB, [op.result, op.getarg(1)], op.getarg(0))
+            self.pure(rop.INT_SUB, [op.result, op.getarg(0)], op.getarg(1))
 
     def optimize_INT_MUL(self, op):
         v1 = self.getvalue(op.getarg(0))
@@ -141,13 +139,13 @@
             self.make_constant_int(op.result, 0)
         else:
             for lhs, rhs in [(v1, v2), (v2, v1)]:
-                # x & (x -1) == 0 is a quick test for power of 2
-                if (lhs.is_constant() and
-                    (lhs.box.getint() & (lhs.box.getint() - 1)) == 0):
-                    new_rhs = ConstInt(highest_bit(lhs.box.getint()))
-                    op = op.copy_and_change(rop.INT_LSHIFT, args=[rhs.box, new_rhs])
-                    break
-
+                if lhs.is_constant():
+                    x = lhs.box.getint()
+                    # x & (x - 1) == 0 is a quick test for power of 2
+                    if x & (x - 1) == 0:
+                        new_rhs = ConstInt(highest_bit(lhs.box.getint()))
+                        op = op.copy_and_change(rop.INT_LSHIFT, args=[rhs.box, new_rhs])
+                        break
             self.emit_operation(op)
 
     def optimize_UINT_FLOORDIV(self, op):
@@ -450,6 +448,9 @@
         if v2.is_constant() and v2.box.getint() == 1:
             self.make_equal_to(op.result, v1)
             return
+        elif v1.is_constant() and v1.box.getint() == 0:
+            self.make_constant_int(op.result, 0)
+            return
         if v1.intbound.known_ge(IntBound(0, 0)) and v2.is_constant():
             val = v2.box.getint()
             if val & (val - 1) == 0 and val > 0: # val == 2**shift
@@ -462,6 +463,14 @@
         self.optimizer.opaque_pointers[value] = True
         self.make_equal_to(op.result, value)
 
+    def optimize_CAST_PTR_TO_INT(self, op):
+        self.pure(rop.CAST_INT_TO_PTR, [op.result], op.getarg(0))
+        self.emit_operation(op)
+
+    def optimize_CAST_INT_TO_PTR(self, op):
+        self.pure(rop.CAST_PTR_TO_INT, [op.result], op.getarg(0))
+        self.emit_operation(op)
+
 dispatch_opt = make_dispatcher_method(OptRewrite, 'optimize_',
         default=OptRewrite.emit_operation)
 optimize_guards = _findall(OptRewrite, 'optimize_', 'GUARD')
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -2181,6 +2181,17 @@
         """
         self.optimize_loop(ops, expected)
 
+        ops = """
+        [i0]
+        i1 = int_floordiv(0, i0)
+        jump(i1)
+        """
+        expected = """
+        [i0]
+        jump(0)
+        """
+        self.optimize_loop(ops, expected)
+
     def test_fold_partially_constant_ops_ovf(self):
         ops = """
         [i0]
@@ -2329,7 +2340,7 @@
         def _variables_equal(box, varname, strict):
             if varname not in virtuals:
                 if strict:
-                    assert box == oparse.getvar(varname)
+                    assert box.same_box(oparse.getvar(varname))
                 else:
                     assert box.value == oparse.getvar(varname).value
             else:
@@ -4789,6 +4800,18 @@
         """
         self.optimize_strunicode_loop(ops, expected)
 
+    def test_ptr_eq_str_constant(self):
+        ops = """
+        []
+        i0 = ptr_eq(s"abc", s"\x00")
+        finish(i0)
+        """
+        expected = """
+        []
+        finish(0)
+        """
+        self.optimize_loop(ops, expected)
+
 
 class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin):
     pass
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -234,6 +234,30 @@
             """ % expected_value
             self.optimize_loop(ops, expected)
 
+    def test_reverse_of_cast(self):
+        ops = """
+        [i0]
+        p0 = cast_int_to_ptr(i0)
+        i1 = cast_ptr_to_int(p0)
+        jump(i1)
+        """
+        expected = """
+        [i0]
+        jump(i0)
+        """
+        self.optimize_loop(ops, expected)
+        ops = """
+        [p0]
+        i1 = cast_ptr_to_int(p0)
+        p1 = cast_int_to_ptr(i1)
+        jump(p1)
+        """
+        expected = """
+        [p0]
+        jump(p0)
+        """
+        self.optimize_loop(ops, expected)
+
     # ----------
 
     def test_remove_guard_class_1(self):
diff --git a/pypy/jit/metainterp/optimizeopt/util.py b/pypy/jit/metainterp/optimizeopt/util.py
--- a/pypy/jit/metainterp/optimizeopt/util.py
+++ b/pypy/jit/metainterp/optimizeopt/util.py
@@ -90,14 +90,11 @@
     for i in range(len(args1)):
         arg1 = args1[i]
         arg2 = args2[i]
-        if isinstance(arg1, history.Const):
-            if arg1.__class__ is not arg2.__class__:
+        if arg1 is None:
+            if arg2 is not None:
                 return False
-            if not arg1.same_constant(arg2):
-                return False
-        else:
-            if not arg1 is arg2:
-                return False
+        elif not arg1.same_box(arg2):
+            return False
     return True
 
 def args_hash(args):
@@ -106,10 +103,8 @@
     for arg in args:
         if arg is None:
             y = 17
-        elif isinstance(arg, history.Const):
+        else:
             y = arg._get_hash_()
-        else:
-            y = compute_identity_hash(arg)
         res = intmask((1000003 * res) ^ y)
     return res
 
@@ -145,9 +140,12 @@
         for i in range(op1.numargs()):
             x = op1.getarg(i)
             y = op2.getarg(i)
-            assert x == remap.get(y, y)
+            assert x.same_box(remap.get(y, y))
         if op2.result in remap:
-            assert op1.result == remap[op2.result]
+            if op2.result is None:
+                assert op1.result == remap[op2.result]
+            else:
+                assert op1.result.same_box(remap[op2.result])
         else:
             remap[op2.result] = op1.result
         if op1.getopnum() != rop.JUMP:      # xxx obscure
@@ -156,11 +154,20 @@
             assert len(op1.getfailargs()) == len(op2.getfailargs())
             if strict_fail_args:
                 for x, y in zip(op1.getfailargs(), op2.getfailargs()):
-                    assert x == remap.get(y, y)
+                    if x is None:
+                        assert remap.get(y, y) is None
+                    else:
+                        assert x.same_box(remap.get(y, y))
             else:
                 fail_args1 = set(op1.getfailargs())
                 fail_args2 = set([remap.get(y, y) for y in op2.getfailargs()])
-                assert fail_args1 == fail_args2
+                for x in fail_args1:
+                    for y in fail_args2:
+                        if x.same_box(y):
+                            fail_args2.remove(y)
+                            break
+                    else:
+                        assert False
     assert len(oplist1) == len(oplist2)
     print '-'*totwidth
     return True
diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py
--- a/pypy/jit/metainterp/optimizeopt/virtualize.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualize.py
@@ -59,7 +59,7 @@
 
     def import_from(self, other, optimizer):
         raise NotImplementedError("should not be called at this level")
-    
+
 def get_fielddescrlist_cache(cpu):
     if not hasattr(cpu, '_optimizeopt_fielddescrlist_cache'):
         result = descrlist_dict()
@@ -113,7 +113,7 @@
         #
         if not we_are_translated():
             op.name = 'FORCE ' + self.source_op.name
-            
+
         if self._is_immutable_and_filled_with_constants(optforce):
             box = optforce.optimizer.constant_fold(op)
             self.make_constant(box)
@@ -239,12 +239,12 @@
         for index in range(len(self._items)):
             self._items[index] = self._items[index].force_at_end_of_preamble(already_forced, optforce)
         return self
-    
+
     def _really_force(self, optforce):
         assert self.source_op is not None
         if not we_are_translated():
             self.source_op.name = 'FORCE ' + self.source_op.name
-        optforce.emit_operation(self.source_op)        
+        optforce.emit_operation(self.source_op)
         self.box = box = self.source_op.result
         for index in range(len(self._items)):
             subvalue = self._items[index]
@@ -276,7 +276,7 @@
 
     def new(self):
         return OptVirtualize()
-        
+
     def make_virtual(self, known_class, box, source_op=None):
         vvalue = VirtualValue(self.optimizer.cpu, known_class, box, source_op)
         self.make_equal_to(box, vvalue)
@@ -386,7 +386,8 @@
 
     def optimize_NEW_ARRAY(self, op):
         sizebox = self.get_constant_box(op.getarg(0))
-        if sizebox is not None:
+        # For now we can't make arrays of structs virtual.
+        if sizebox is not None and not op.getdescr().is_array_of_structs():
             # if the original 'op' did not have a ConstInt as argument,
             # build a new one with the ConstInt argument
             if not isinstance(op.getarg(0), ConstInt):
diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py
--- a/pypy/jit/metainterp/optimizeopt/vstring.py
+++ b/pypy/jit/metainterp/optimizeopt/vstring.py
@@ -587,10 +587,7 @@
             return True
         #
         if v1.is_nonnull() and v2.is_nonnull():
-            if l1box is not None and l2box is not None and (
-                l1box == l2box or (isinstance(l1box, ConstInt) and
-                                   isinstance(l2box, ConstInt) and
-                                   l1box.value == l2box.value)):
+            if l1box is not None and l2box is not None and l1box.same_box(l2box):
                 do = EffectInfo.OS_STREQ_LENGTHOK
             else:
                 do = EffectInfo.OS_STREQ_NONNULL
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -36,6 +36,7 @@
 
 
 class MIFrame(object):
+    debug = False
 
     def __init__(self, metainterp):
         self.metainterp = metainterp
@@ -162,15 +163,18 @@
             if registers[i] is oldbox:
                 registers[i] = newbox
         if not we_are_translated():
-            assert oldbox not in registers[count:]
+            for b in registers[count:]:
+                assert not oldbox.same_box(b)
+                
 
     def make_result_of_lastop(self, resultbox):
         got_type = resultbox.type
-        if not we_are_translated():
-            typeof = {'i': history.INT,
-                      'r': history.REF,
-                      'f': history.FLOAT}
-            assert typeof[self.jitcode._resulttypes[self.pc]] == got_type
+        # XXX disabled for now, conflicts with str_guard_value
+        #if not we_are_translated():
+        #    typeof = {'i': history.INT,
+        #              'r': history.REF,
+        #              'f': history.FLOAT}
+        #    assert typeof[self.jitcode._resulttypes[self.pc]] == got_type
         target_index = ord(self.bytecode[self.pc-1])
         if got_type == history.INT:
             self.registers_i[target_index] = resultbox
@@ -219,6 +223,7 @@
                     'cast_float_to_int', 'cast_int_to_float',
                     'cast_float_to_singlefloat', 'cast_singlefloat_to_float',
                     'float_neg', 'float_abs',
+                    'cast_ptr_to_int', 'cast_int_to_ptr',
                     ]:
         exec py.code.Source('''
             @arguments("box")
@@ -544,6 +549,14 @@
     opimpl_getfield_gc_r_pure = _opimpl_getfield_gc_pure_any
     opimpl_getfield_gc_f_pure = _opimpl_getfield_gc_pure_any
 
+    @arguments("box", "box", "descr")
+    def _opimpl_getinteriorfield_gc_any(self, array, index, descr):
+        return self.execute_with_descr(rop.GETINTERIORFIELD_GC, descr,
+                                       array, index)
+    opimpl_getinteriorfield_gc_i = _opimpl_getinteriorfield_gc_any
+    opimpl_getinteriorfield_gc_f = _opimpl_getinteriorfield_gc_any
+    opimpl_getinteriorfield_gc_r = _opimpl_getinteriorfield_gc_any
+
     @specialize.arg(1)
     def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr):
         tobox = self.metainterp.heapcache.getfield(box, fielddescr)
@@ -584,6 +597,15 @@
     opimpl_setfield_gc_r = _opimpl_setfield_gc_any
     opimpl_setfield_gc_f = _opimpl_setfield_gc_any
 
+    @arguments("box", "box", "box", "descr")
+    def _opimpl_setinteriorfield_gc_any(self, array, index, value, descr):
+        self.execute_with_descr(rop.SETINTERIORFIELD_GC, descr,
+                                array, index, value)
+    opimpl_setinteriorfield_gc_i = _opimpl_setinteriorfield_gc_any
+    opimpl_setinteriorfield_gc_f = _opimpl_setinteriorfield_gc_any
+    opimpl_setinteriorfield_gc_r = _opimpl_setinteriorfield_gc_any
+                                
+
     @arguments("box", "descr")
     def _opimpl_getfield_raw_any(self, box, fielddescr):
         return self.execute_with_descr(rop.GETFIELD_RAW, fielddescr, box)
@@ -895,6 +917,21 @@
     def _opimpl_guard_value(self, orgpc, box):
         self.implement_guard_value(orgpc, box)
 
+    @arguments("orgpc", "box", "box", "descr")
+    def opimpl_str_guard_value(self, orgpc, box, funcbox, descr):
+        if isinstance(box, Const):
+            return box     # no promotion needed, already a Const
+        else:
+            constbox = box.constbox()
+            resbox = self.do_residual_call(funcbox, descr, [box, constbox])
+            promoted_box = resbox.constbox()
+            # This is GUARD_VALUE because GUARD_TRUE assumes the existance
+            # of a label when computing resumepc
+            self.generate_guard(rop.GUARD_VALUE, resbox, [promoted_box],
+                                resumepc=orgpc)
+            self.metainterp.replace_box(box, constbox)
+            return constbox
+
     opimpl_int_guard_value = _opimpl_guard_value
     opimpl_ref_guard_value = _opimpl_guard_value
     opimpl_float_guard_value = _opimpl_guard_value
@@ -2569,17 +2606,21 @@
         self.pc = position
         #
         if not we_are_translated():
-            print '\tpyjitpl: %s(%s)' % (name, ', '.join(map(repr, args))),
+            if self.debug:
+                print '\tpyjitpl: %s(%s)' % (name, ', '.join(map(repr, args))),
             try:
                 resultbox = unboundmethod(self, *args)
             except Exception, e:
-                print '-> %s!' % e.__class__.__name__
+                if self.debug:
+                    print '-> %s!' % e.__class__.__name__
                 raise
             if num_return_args == 0:
-                print
+                if self.debug:
+                    print
                 assert resultbox is None
             else:
-                print '-> %r' % (resultbox,)
+                if self.debug:
+                    print '-> %r' % (resultbox,)
                 assert argcodes[next_argcode] == '>'
                 result_argcode = argcodes[next_argcode + 1]
                 assert resultbox.type == {'i': history.INT,
diff --git a/pypy/jit/metainterp/quasiimmut.py b/pypy/jit/metainterp/quasiimmut.py
--- a/pypy/jit/metainterp/quasiimmut.py
+++ b/pypy/jit/metainterp/quasiimmut.py
@@ -2,6 +2,7 @@
 from pypy.rpython.lltypesystem import lltype, rclass
 from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
 from pypy.jit.metainterp.history import AbstractDescr
+from pypy.rlib.objectmodel import we_are_translated
 
 
 def get_mutate_field_name(fieldname):
@@ -50,13 +51,13 @@
 
 class QuasiImmut(object):
     llopaque = True
+    compress_limit = 30
     
     def __init__(self, cpu):
         self.cpu = cpu
         # list of weakrefs to the LoopTokens that must be invalidated if
         # this value ever changes
         self.looptokens_wrefs = []
-        self.compress_limit = 30
 
     def hide(self):
         qmut_ptr = self.cpu.ts.cast_instance_to_base_ref(self)
@@ -75,6 +76,8 @@
     def compress_looptokens_list(self):
         self.looptokens_wrefs = [wref for wref in self.looptokens_wrefs
                                       if wref() is not None]
+        # NB. we must keep around the looptoken_wrefs that are
+        # already invalidated; see below
         self.compress_limit = (len(self.looptokens_wrefs) + 15) * 2
 
     def invalidate(self):
@@ -86,7 +89,16 @@
         for wref in wrefs:
             looptoken = wref()
             if looptoken is not None:
+                looptoken.invalidated = True
                 self.cpu.invalidate_loop(looptoken)
+                # NB. we must call cpu.invalidate_loop() even if
+                # looptoken.invalidated was already set to True.
+                # It's possible to invalidate several times the
+                # same looptoken; see comments in jit.backend.model
+                # in invalidate_loop().
+                if not we_are_translated():
+                    self.cpu.stats.invalidated_token_numbers.add(
+                        looptoken.number)
 
 
 class QuasiImmutDescr(AbstractDescr):
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -1,5 +1,4 @@
 from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.debug import make_sure_not_resized
 
 def ResOperation(opnum, args, result, descr=None):
     cls = opclasses[opnum]
@@ -433,6 +432,8 @@
     'INT_INVERT/1',
     #
     'SAME_AS/1',      # gets a Const or a Box, turns it into another Box
+    'CAST_PTR_TO_INT/1',
+    'CAST_INT_TO_PTR/1',
     #
     'PTR_EQ/2b',
     'PTR_NE/2b',
@@ -455,6 +456,7 @@
 
     'GETARRAYITEM_GC/2d',
     'GETARRAYITEM_RAW/2d',
+    'GETINTERIORFIELD_GC/2d',
     'GETFIELD_GC/1d',
     'GETFIELD_RAW/1d',
     '_MALLOC_FIRST',
@@ -471,6 +473,7 @@
 
     'SETARRAYITEM_GC/3d',
     'SETARRAYITEM_RAW/3d',
+    'SETINTERIORFIELD_GC/3d',
     'SETFIELD_GC/2d',
     'SETFIELD_RAW/2d',
     'STRSETITEM/3',
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -13,7 +13,7 @@
 from pypy.rlib.jit import (JitDriver, we_are_jitted, hint, dont_look_inside,
     loop_invariant, elidable, promote, jit_debug, assert_green,
     AssertGreenFailed, unroll_safe, current_trace_length, look_inside_iff,
-    isconstant, isvirtual)
+    isconstant, isvirtual, promote_string)
 from pypy.rlib.rarithmetic import ovfcheck
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rpython.ootypesystem import ootype
@@ -3435,12 +3435,43 @@
             return sa
         res = self.meta_interp(f, [16])
         assert res == f(16)
-        
+
+    def test_ptr_eq_str_constants(self):
+        myjitdriver = JitDriver(greens = [], reds = ["n", "x"])
+        class A(object):
+            def __init__(self, v):
+                self.v = v
+        def f(n, x):
+            while n > 0:
+                myjitdriver.jit_merge_point(n=n, x=x)
+                z = 0 / x
+                a1 = A("key")
+                a2 = A("\x00")
+                n -= [a1, a2][z].v is not a2.v
+            return n
+        res = self.meta_interp(f, [10, 1])
+        assert res == 0
+
+    def test_virtual_array_of_structs(self):
+        myjitdriver = JitDriver(greens = [], reds=["n", "d"])
+        def f(n):
+            d = None
+            while n > 0:
+                myjitdriver.jit_merge_point(n=n, d=d)
+                d = {}
+                if n % 2:
+                    d["k"] = n
+                else:
+                    d["z"] = n
+                n -= len(d)
+            return n
+        res = self.meta_interp(f, [10])
+        assert res == 0
+
 
 
 class TestLLtype(BaseLLtypeTests, LLJitMixin):
     def test_tagged(self):
-        py.test.skip("implement me")
         from pypy.rlib.objectmodel import UnboxedValue
         class Base(object):
             __slots__ = ()
@@ -3492,3 +3523,35 @@
                 pc += 1
             return pc
         res = self.meta_interp(main, [False, 100, True], taggedpointers=True)
+
+    def test_rerased(self):
+        from pypy.rlib.rerased import erase_int, unerase_int, new_erasing_pair
+        eraseX, uneraseX = new_erasing_pair("X")
+        #
+        class X:
+            def __init__(self, a, b):
+                self.a = a
+                self.b = b
+        #
+        def f(i, j):
+            # 'j' should be 0 or 1, not other values
+            if j > 0:
+                e = eraseX(X(i, j))
+            else:
+                try:
+                    e = erase_int(i)
+                except OverflowError:
+                    return -42
+            if j & 1:
+                x = uneraseX(e)
+                return x.a - x.b
+            else:
+                return unerase_int(e)
+        #
+        x = self.interp_operations(f, [-128, 0], taggedpointers=True)
+        assert x == -128
+        bigint = sys.maxint//2 + 1
+        x = self.interp_operations(f, [bigint, 0], taggedpointers=True)
+        assert x == -42
+        x = self.interp_operations(f, [1000, 1], taggedpointers=True)
+        assert x == 999
diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py
--- a/pypy/jit/metainterp/test/test_dict.py
+++ b/pypy/jit/metainterp/test/test_dict.py
@@ -91,7 +91,7 @@
         res1 = f(100)
         res2 = self.meta_interp(f, [100], listops=True)
         assert res1 == res2
-        self.check_loops(int_mod=1) # the hash was traced
+        self.check_loops(int_mod=1) # the hash was traced and eq, but cached
 
     def test_dict_setdefault(self):
         myjitdriver = JitDriver(greens = [], reds = ['total', 'dct'])
@@ -128,7 +128,7 @@
         assert f(100) == 50
         res = self.meta_interp(f, [100], listops=True)
         assert res == 50
-        self.check_loops(int_mod=1)
+        self.check_loops(int_mod=1) # key + eq, but cached
 
     def test_repeated_lookup(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'd'])
@@ -153,10 +153,12 @@
 
         res = self.meta_interp(f, [100], listops=True)
         assert res == f(50)
-        self.check_loops({"call": 7, "guard_false": 1, "guard_no_exception": 6,
+        self.check_loops({"call": 5, "getfield_gc": 1, "getinteriorfield_gc": 1,
+                          "guard_false": 1, "guard_no_exception": 4,
                           "guard_true": 1, "int_and": 1, "int_gt": 1,
                           "int_is_true": 1, "int_sub": 1, "jump": 1,
-                          "new_with_vtable": 1, "setfield_gc": 1})
+                          "new_with_vtable": 1, "new": 1, "new_array": 1,
+                          "setfield_gc": 3, })
 
 
 class TestOOtype(DictTests, OOJitMixin):
diff --git a/pypy/jit/metainterp/test/test_heapcache.py b/pypy/jit/metainterp/test/test_heapcache.py
--- a/pypy/jit/metainterp/test/test_heapcache.py
+++ b/pypy/jit/metainterp/test/test_heapcache.py
@@ -355,6 +355,14 @@
         assert not h.is_unescaped(box1)
         assert not h.is_unescaped(box2)
 
+    def test_circular_virtuals(self):
+        h = HeapCache()
+        h.new(box1)
+        h.new(box2)
+        h.invalidate_caches(rop.SETFIELD_GC, None, [box1, box2])
+        h.invalidate_caches(rop.SETFIELD_GC, None, [box2, box1])
+        h.invalidate_caches(rop.SETFIELD_GC, None, [box3, box1]) # does not crash
+
     def test_unescaped_array(self):
         h = HeapCache()
         h.new_array(box1, lengthbox1)
@@ -362,4 +370,4 @@
         h.invalidate_caches(rop.SETARRAYITEM_GC, None, [box1, index1, box2])
         assert h.is_unescaped(box1)
         h.invalidate_caches(rop.SETARRAYITEM_GC, None, [box2, index1, box1])
-        assert not h.is_unescaped(box1)
\ No newline at end of file
+        assert not h.is_unescaped(box1)
diff --git a/pypy/jit/metainterp/test/test_memmgr.py b/pypy/jit/metainterp/test/test_memmgr.py
--- a/pypy/jit/metainterp/test/test_memmgr.py
+++ b/pypy/jit/metainterp/test/test_memmgr.py
@@ -18,6 +18,7 @@
 
 class FakeLoopToken:
     generation = 0
+    invalidated = False
 
 
 class _TestMemoryManager:
diff --git a/pypy/jit/metainterp/test/test_quasiimmut.py b/pypy/jit/metainterp/test/test_quasiimmut.py
--- a/pypy/jit/metainterp/test/test_quasiimmut.py
+++ b/pypy/jit/metainterp/test/test_quasiimmut.py
@@ -48,6 +48,13 @@
 
 class QuasiImmutTests(object):
 
+    def setup_method(self, meth):
+        self.prev_compress_limit = QuasiImmut.compress_limit
+        QuasiImmut.compress_limit = 1
+
+    def teardown_method(self, meth):
+        QuasiImmut.compress_limit = self.prev_compress_limit
+
     def test_simple_1(self):
         myjitdriver = JitDriver(greens=['foo'], reds=['x', 'total'])
         class Foo:
@@ -289,7 +296,7 @@
             return total
 
         res = self.meta_interp(main, [])
-        self.check_loop_count(9)
+        self.check_tree_loop_count(6)
         assert res == main()
 
     def test_change_during_running(self):
@@ -317,7 +324,7 @@
         assert f(100, 15) == 3009
         res = self.meta_interp(f, [100, 15])
         assert res == 3009
-        self.check_loops(guard_not_invalidated=2, getfield_gc=0,
+        self.check_loops(guard_not_invalidated=4, getfield_gc=0,
                          call_may_force=0, guard_not_forced=0)
 
     def test_list_simple_1(self):
@@ -453,10 +460,30 @@
         assert f(100, 15) == 3009
         res = self.meta_interp(f, [100, 15])
         assert res == 3009
-        self.check_loops(guard_not_invalidated=2, getfield_gc=0,
+        self.check_loops(guard_not_invalidated=4, getfield_gc=0,
                          getarrayitem_gc=0, getarrayitem_gc_pure=0,
                          call_may_force=0, guard_not_forced=0)
 
+    def test_invalidated_loop_is_not_used_any_more_as_target(self):
+        myjitdriver = JitDriver(greens=['foo'], reds=['x'])
+        class Foo:
+            _immutable_fields_ = ['step?']
+        @dont_look_inside
+        def residual(x, foo):
+            if x == 20:
+                foo.step = 1
+        def f(x):
+            foo = Foo()
+            foo.step = 2
+            while x > 0:
+                myjitdriver.jit_merge_point(foo=foo, x=x)
+                residual(x, foo)
+                x -= foo.step
+            return foo.step
+        res = self.meta_interp(f, [60])
+        assert res == 1
+        self.check_tree_loop_count(4)   # at least not 2 like before
+
 
 class TestLLtypeGreenFieldsTests(QuasiImmutTests, LLJitMixin):
     pass
diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py
--- a/pypy/jit/metainterp/test/test_resume.py
+++ b/pypy/jit/metainterp/test/test_resume.py
@@ -1,3 +1,4 @@
+from __future__ import with_statement
 import py
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.jit.metainterp.optimizeopt.optimizer import OptValue
@@ -180,22 +181,27 @@
     reader.consume_boxes(info, bi, br, bf)
     b1s = reader.liveboxes[0]
     b2s = reader.liveboxes[1]
-    assert bi == [b1s, ConstInt(111), b1s]
-    assert br == [ConstPtr(gcrefnull), b2s]
+    assert_same(bi, [b1s, ConstInt(111), b1s])
+    assert_same(br, [ConstPtr(gcrefnull), b2s])
     bi, br, bf = [None]*2, [None]*0, [None]*0
     info = MyBlackholeInterp([lltype.Signed,
                               lltype.Signed]).get_current_position_info()
     reader.consume_boxes(info, bi, br, bf)
-    assert bi == [ConstInt(222), ConstInt(333)]
+    assert_same(bi, [ConstInt(222), ConstInt(333)])
     bi, br, bf = [None]*2, [None]*1, [None]*0
     info = MyBlackholeInterp([lltype.Signed, llmemory.GCREF,
                               lltype.Signed]).get_current_position_info()
     reader.consume_boxes(info, bi, br, bf)
     b3s = reader.liveboxes[2]
-    assert bi == [b1s, b3s]
-    assert br == [b2s]
+    assert_same(bi, [b1s, b3s])
+    assert_same(br, [b2s])
     #
 
+def assert_same(list1, list2):
+    assert len(list1) == len(list2)
+    for b1, b2 in zip(list1, list2):
+        assert b1.same_box(b2)
+
 def test_simple_read_tagged_ints():
     storage = Storage()
     storage.rd_consts = []
@@ -1023,11 +1029,11 @@
     metainterp = MyMetaInterp()
     reader = ResumeDataFakeReader(storage, newboxes, metainterp)
     lst = reader.consume_boxes()
-    assert lst == [b1t, b1t, b3t]
+    assert_same(lst, [b1t, b1t, b3t])
     lst = reader.consume_boxes()
-    assert lst == [ConstInt(2), ConstInt(3)]
+    assert_same(lst, [ConstInt(2), ConstInt(3)])
     lst = reader.consume_boxes()
-    assert lst == [b1t, ConstInt(1), b1t, b1t]
+    assert_same(lst, [b1t, ConstInt(1), b1t, b1t])
     assert metainterp.trace == []    
 
 
@@ -1044,11 +1050,11 @@
     reader = ResumeDataFakeReader(storage, newboxes, metainterp)
     lst = reader.consume_boxes()
     c1t = ConstInt(111)
-    assert lst == [c1t, b2t, b3t]
+    assert_same(lst, [c1t, b2t, b3t])
     lst = reader.consume_boxes()
-    assert lst == [ConstInt(2), ConstInt(3)]
+    assert_same(lst, [ConstInt(2), ConstInt(3)])
     lst = reader.consume_boxes()
-    assert lst == [c1t, ConstInt(1), c1t, b2t]
+    assert_same(lst, [c1t, ConstInt(1), c1t, b2t])
     assert metainterp.trace == []
 
 
@@ -1114,9 +1120,11 @@
     # check that we get the operations in 'expected', in a possibly different
     # order.
     assert len(trace) == len(expected)
-    for x in trace:
-        assert x in expected
-        expected.remove(x)
+    with CompareableConsts():
+        for x in trace:
+            assert x in expected
+            expected.remove(x)
+
     ptr = b2t.value._obj.container._as_ptr()
     assert lltype.typeOf(ptr) == lltype.Ptr(LLtypeMixin.NODE)
     assert ptr.value == 111
@@ -1126,6 +1134,18 @@
     assert ptr2.parent.value == 33
     assert ptr2.parent.next == ptr
 
+class CompareableConsts(object):
+    def __init__(self):
+        self.oldeq = None
+        
+    def __enter__(self):
+        assert self.oldeq is None
+        self.oldeq = Const.__eq__
+        Const.__eq__ = Const.same_box
+        
+    def __exit__(self, type, value, traceback):
+        Const.__eq__ = self.oldeq
+
 def test_virtual_adder_make_varray():
     b2s, b4s = [BoxPtr(), BoxInt(4)]
     c1s = ConstInt(111)
@@ -1163,8 +1183,9 @@
         (rop.SETARRAYITEM_GC, [b2t,ConstInt(1), c1s], None,
                               LLtypeMixin.arraydescr),
         ]
-    for x, y in zip(expected, trace):
-        assert x == y
+    with CompareableConsts():
+        for x, y in zip(expected, trace):
+            assert x == y
     #
     ptr = b2t.value._obj.container._as_ptr()
     assert lltype.typeOf(ptr) == lltype.Ptr(lltype.GcArray(lltype.Signed))
@@ -1207,8 +1228,9 @@
         (rop.SETFIELD_GC, [b2t, c1s],  None, LLtypeMixin.adescr),
         (rop.SETFIELD_GC, [b2t, b4t], None, LLtypeMixin.bdescr),
         ]
-    for x, y in zip(expected, trace):
-        assert x == y
+    with CompareableConsts():
+        for x, y in zip(expected, trace):
+            assert x == y
     #
     ptr = b2t.value._obj.container._as_ptr()
     assert lltype.typeOf(ptr) == lltype.Ptr(LLtypeMixin.S)
diff --git a/pypy/jit/metainterp/test/test_string.py b/pypy/jit/metainterp/test/test_string.py
--- a/pypy/jit/metainterp/test/test_string.py
+++ b/pypy/jit/metainterp/test/test_string.py
@@ -3,7 +3,8 @@
 from pypy.jit.codewriter.policy import StopAtXPolicy
 from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
 from pypy.rlib.debug import debug_print
-from pypy.rlib.jit import JitDriver, dont_look_inside, we_are_jitted
+from pypy.rlib.jit import JitDriver, dont_look_inside, we_are_jitted,\
+     promote_string
 from pypy.rlib.rstring import StringBuilder
 from pypy.rpython.ootypesystem import ootype
 
@@ -507,6 +508,18 @@
                           'jump': 1, 'int_is_true': 1,
                           'guard_not_invalidated': 1})
 
+    def test_promote_string(self):
+        driver = JitDriver(greens = [], reds = ['n'])
+        
+        def f(n):
+            while n < 21:
+                driver.jit_merge_point(n=n)
+                promote_string(str(n % 3))
+                n += 1
+            return 0
+
+        self.meta_interp(f, [0])
+        self.check_loops(call=3 + 1) # one for int2str
 
 #class TestOOtype(StringTests, OOJitMixin):
 #    CALL = "oosend"
diff --git a/pypy/jit/metainterp/test/test_virtualref.py b/pypy/jit/metainterp/test/test_virtualref.py
--- a/pypy/jit/metainterp/test/test_virtualref.py
+++ b/pypy/jit/metainterp/test/test_virtualref.py
@@ -3,6 +3,7 @@
 from pypy.rpython.llinterp import LLException
 from pypy.rlib.jit import JitDriver, dont_look_inside, vref_None
 from pypy.rlib.jit import virtual_ref, virtual_ref_finish, InvalidVirtualRef
+from pypy.rlib.jit import non_virtual_ref
 from pypy.rlib.objectmodel import compute_unique_id
 from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin, _get_jitcodes
 from pypy.jit.metainterp.resoperation import rop
@@ -595,6 +596,65 @@
         res = self.meta_interp(fn, [10])
         assert res == 6
 
+    def test_is_virtual(self):
+        myjitdriver = JitDriver(greens=[], reds=['n', 'res1'])
+        class X:
+            pass
+        @dont_look_inside
+        def residual(vref):
+            return vref.virtual
+        #
+        def f(n):
+            res1 = -42
+            while n > 0:
+                myjitdriver.jit_merge_point(n=n, res1=res1)
+                x = X()
+                vref = virtual_ref(x)
+                res1 = residual(vref)
+                virtual_ref_finish(vref, x)
+                n -= 1
+            return res1
+        #
+        res = self.meta_interp(f, [10])
+        assert res == 1
+
+    def test_is_not_virtual_none(self):
+        myjitdriver = JitDriver(greens=[], reds=['n', 'res1'])
+        @dont_look_inside
+        def residual(vref):
+            return vref.virtual
+        #
+        def f(n):
+            res1 = -42
+            while n > 0:
+                myjitdriver.jit_merge_point(n=n, res1=res1)
+                res1 = residual(vref_None)
+                n -= 1
+            return res1
+        #
+        res = self.meta_interp(f, [10])
+        assert res == 0
+
+    def test_is_not_virtual_non_none(self):
+        myjitdriver = JitDriver(greens=[], reds=['n', 'res1'])
+        class X:
+            pass
+        @dont_look_inside
+        def residual(vref):
+            return vref.virtual
+        #
+        def f(n):
+            res1 = -42
+            while n > 0:
+                myjitdriver.jit_merge_point(n=n, res1=res1)
+                x = X()
+                res1 = residual(non_virtual_ref(x))
+                n -= 1
+            return res1
+        #
+        res = self.meta_interp(f, [10])
+        assert res == 0
+
 
 class TestLLtype(VRefTests, LLJitMixin):
     pass
diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py
--- a/pypy/jit/metainterp/virtualref.py
+++ b/pypy/jit/metainterp/virtualref.py
@@ -39,6 +39,7 @@
     def replace_force_virtual_with_call(self, graphs):
         # similar to rvirtualizable2.replace_force_virtualizable_with_call().
         c_force_virtual_ptr = None
+        c_is_virtual_ptr = None
         force_virtual_count = 0
         for graph in graphs:
             for block in graph.iterblocks():
@@ -52,6 +53,13 @@
                         op.opname = 'direct_call'
                         op.args = [c_force_virtual_ptr, op.args[0]]
                         force_virtual_count += 1
+                    #
+                    if op.opname == 'jit_is_virtual':
+                        if c_is_virtual_ptr is None:
+                            c_is_virtual_ptr = self.get_is_virtual_fnptr()
+                        #
+                        op.opname = 'direct_call'
+                        op.args = [c_is_virtual_ptr, op.args[0]]
         #
         if c_force_virtual_ptr is not None:
             log("replaced %d 'jit_force_virtual' with %r" % (force_virtual_count,
@@ -129,6 +137,17 @@
             force_virtual_if_necessary)
         return inputconst(lltype.typeOf(funcptr), funcptr)
 
+    def get_is_virtual_fnptr(self):
+        #
+        def is_virtual(inst):
+            if not inst:
+                return False
+            return inst.typeptr == self.jit_virtual_ref_vtable
+        #
+        FUNC = lltype.FuncType([rclass.OBJECTPTR], lltype.Bool)
+        funcptr = self.warmrunnerdesc.helper_func(lltype.Ptr(FUNC), is_virtual)
+        return inputconst(lltype.typeOf(funcptr), funcptr)
+
     def force_virtual(self, inst):
         vref = lltype.cast_pointer(lltype.Ptr(self.JIT_VIRTUAL_REF), inst)
         token = vref.virtual_token
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -206,7 +206,7 @@
         self.make_enter_functions()
         self.rewrite_jit_merge_points(policy)
 
-        verbose = not self.cpu.translate_support_code
+        verbose = False # not self.cpu.translate_support_code
         self.codewriter.make_jitcodes(verbose=verbose)
         self.rewrite_can_enter_jits()
         self.rewrite_set_param()
diff --git a/pypy/jit/metainterp/warmstate.py b/pypy/jit/metainterp/warmstate.py
--- a/pypy/jit/metainterp/warmstate.py
+++ b/pypy/jit/metainterp/warmstate.py
@@ -178,7 +178,7 @@
         if self.compiled_merge_points_wref is not None:
             for wref in self.compiled_merge_points_wref:
                 looptoken = wref()
-                if looptoken is not None:
+                if looptoken is not None and not looptoken.invalidated:
                     result.append(looptoken)
         return result
 
diff --git a/pypy/module/__builtin__/__init__.py b/pypy/module/__builtin__/__init__.py
--- a/pypy/module/__builtin__/__init__.py
+++ b/pypy/module/__builtin__/__init__.py
@@ -20,6 +20,10 @@
         'any'           : 'app_functional.any',
         'all'           : 'app_functional.all',
         'sum'           : 'app_functional.sum',
+        'map'           : 'app_functional.map',
+        'reduce'        : 'app_functional.reduce',
+        'filter'        : 'app_functional.filter',
+        'zip'           : 'app_functional.zip',
         'vars'          : 'app_inspect.vars',
         'dir'           : 'app_inspect.dir',
 
@@ -86,11 +90,7 @@
         'enumerate'     : 'functional.W_Enumerate',
         'min'           : 'functional.min',
         'max'           : 'functional.max',
-        'map'           : 'functional.map',
-        'zip'           : 'functional.zip',
-        'reduce'        : 'functional.reduce',
         'reversed'      : 'functional.reversed',
-        'filter'        : 'functional.filter',
         'super'         : 'descriptor.W_Super',
         'staticmethod'  : 'descriptor.StaticMethod',
         'classmethod'   : 'descriptor.ClassMethod',
@@ -119,7 +119,7 @@
            builtin = space.interpclass_w(w_builtin)
            if isinstance(builtin, module.Module):
                return builtin
-       # no builtin! make a default one.  Given them None, at least.
+       # no builtin! make a default one.  Give them None, at least.
        builtin = module.Module(space, None)
        space.setitem(builtin.w_dict, space.wrap('None'), space.w_None)
        return builtin
diff --git a/pypy/module/__builtin__/app_functional.py b/pypy/module/__builtin__/app_functional.py
--- a/pypy/module/__builtin__/app_functional.py
+++ b/pypy/module/__builtin__/app_functional.py
@@ -48,4 +48,135 @@
         # Very intentionally *not* +=, that would have different semantics if
         # start was a mutable type, such as a list
         last = last + x
-    return last
\ No newline at end of file
+    return last
+
+def map(func, *collections):
+    """map(function, sequence[, sequence, ...]) -> list
+
+Return a list of the results of applying the function to the items of
+the argument sequence(s).  If more than one sequence is given, the
+function is called with an argument list consisting of the corresponding
+item of each sequence, substituting None for missing values when not all
+sequences have the same length.  If the function is None, return a list of
+the items of the sequence (or a list of tuples if more than one sequence)."""
+    if not collections:
+        raise TypeError("map() requires at least two arguments")
+    num_collections = len(collections)
+    none_func = func is None
+    if num_collections == 1:
+        if none_func:
+            return list(collections[0])
+        else:
+            # Special case for the really common case of a single collection,
+            # this can be eliminated if we could unroll that loop that creates
+            # `args` based on whether or not len(collections) was constant
+            result = []
+            for item in collections[0]:
+                result.append(func(item))
+            return result
+    result = []
+    # Pair of (iterator, has_finished)
+    iterators = [(iter(seq), False) for seq in collections]
+    while True:
+        cont = False
+        args = []
+        for idx, (iterator, has_finished) in enumerate(iterators):
+            val = None
+            if not has_finished:
+                try:
+                    val = next(iterator)
+                except StopIteration:
+                    iterators[idx] = (None, True)
+                else:
+                    cont = True
+            args.append(val)
+        args = tuple(args)
+        if cont:
+            if none_func:
+                result.append(args)
+            else:
+                result.append(func(*args))
+        else:
+            return result
+
+sentinel = object()
+
+def reduce(func, sequence, initial=sentinel):
+    """reduce(function, sequence[, initial]) -> value
+
+Apply a function of two arguments cumulatively to the items of a sequence,
+from left to right, so as to reduce the sequence to a single value.
+For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates
+((((1+2)+3)+4)+5).  If initial is present, it is placed before the items
+of the sequence in the calculation, and serves as a default when the
+sequence is empty."""
+    iterator = iter(sequence)
+    if initial is sentinel:
+        try:
+            initial = next(iterator)
+        except StopIteration:
+            raise TypeError("reduce() of empty sequence with no initial value")
+    result = initial
+    for item in iterator:
+        result = func(result, item)
+    return result
+
+def filter(func, seq):
+    """filter(function or None, sequence) -> list, tuple, or string
+
+Return those items of sequence for which function(item) is true.  If
+function is None, return the items that are true.  If sequence is a tuple
+or string, return the same type, else return a list."""
+    if func is None:
+        func = bool
+    if isinstance(seq, str):
+        return _filter_string(func, seq, str)
+    elif isinstance(seq, unicode):
+        return _filter_string(func, seq, unicode)
+    elif isinstance(seq, tuple):
+        return _filter_tuple(func, seq)
+    result = []
+    for item in seq:
+        if func(item):
+            result.append(item)
+    return result
+
+def _filter_string(func, string, str_type):
+    if func is bool and type(string) is str_type:
+        return string
+    result = []
+    for i in range(len(string)):
+        # You must call __getitem__ on the strings, simply iterating doesn't
+        # work :/
+        item = string[i]
+        if func(item):
+            if not isinstance(item, str_type):
+                raise TypeError("__getitem__ returned a non-string type")
+            result.append(item)
+    return str_type().join(result)
+
+def _filter_tuple(func, seq):
+    result = []
+    for i in range(len(seq)):
+        # Again, must call __getitem__, at least there are tests.
+        item = seq[i]
+        if func(item):
+            result.append(item)
+    return tuple(result)
+
+def zip(*sequences):
+    """zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
+
+Return a list of tuples, where each tuple contains the i-th element
+from each of the argument sequences.  The returned list is truncated
+in length to the length of the shortest argument sequence."""
+    if not sequences:
+        return []
+    result = []
+    iterators = [iter(seq) for seq in sequences]
+    while True:
+        try:
+            items = [next(it) for it in iterators]
+        except StopIteration:
+            return result
+        result.append(tuple(items))
diff --git a/pypy/module/__builtin__/app_io.py b/pypy/module/__builtin__/app_io.py
--- a/pypy/module/__builtin__/app_io.py
+++ b/pypy/module/__builtin__/app_io.py
@@ -27,7 +27,20 @@
     co = compile(source.rstrip()+"\n", filename, 'exec')
     exec co in glob, loc
 
-def raw_input(prompt=None):
+def _write_prompt(stdout, prompt):
+    print >> stdout, prompt,
+    try:
+        flush = stdout.flush
+    except AttributeError:
+        pass
+    else:
+        flush()
+    try:
+        stdout.softspace = 0
+    except (AttributeError, TypeError):
+        pass
+
+def raw_input(prompt=''):
     """raw_input([prompt]) -> string
 
 Read a string from standard input.  The trailing newline is stripped.
@@ -47,18 +60,10 @@
     if (hasattr(sys, '__raw_input__') and
         isinstance(stdin, file)  and stdin.fileno() == 0 and stdin.isatty() and
         isinstance(stdout, file) and stdout.fileno() == 1):
-        if prompt is None:
-            prompt = ''
-        return sys.__raw_input__(prompt)
+        _write_prompt(stdout, '')
+        return sys.__raw_input__(str(prompt))
 
-    if prompt is not None:
-        stdout.write(prompt)
-        try:
-            flush = stdout.flush
-        except AttributeError:
-            pass
-        else:
-            flush()
+    _write_prompt(stdout, prompt)
     line = stdin.readline()
     if not line:    # inputting an empty line gives line == '\n'
         raise EOFError
@@ -66,7 +71,7 @@
         return line[:-1]
     return line
 
-def input(prompt=None):
+def input(prompt=''):
     """Equivalent to eval(raw_input(prompt))."""
     return eval(raw_input(prompt))
 
diff --git a/pypy/module/__builtin__/compiling.py b/pypy/module/__builtin__/compiling.py
--- a/pypy/module/__builtin__/compiling.py
+++ b/pypy/module/__builtin__/compiling.py
@@ -84,8 +84,8 @@
         raise OperationError(space.w_TypeError,
               w('eval() arg 1 must be a string or code object'))
 
-    caller = space.getexecutioncontext().gettopframe_nohidden()
     if space.is_w(w_globals, space.w_None):
+        caller = space.getexecutioncontext().gettopframe_nohidden()
         if caller is None:
             w_globals = space.newdict()
             if space.is_w(w_locals, space.w_None):
@@ -97,13 +97,9 @@
     elif space.is_w(w_locals, space.w_None):
         w_locals = w_globals
 
-    try:
-        space.getitem(w_globals, space.wrap('__builtins__'))
-    except OperationError, e:
-        if not e.match(space, space.w_KeyError):
-            raise
-        if caller is not None:
-            w_builtin = space.builtin.pick_builtin(caller.w_globals)
-            space.setitem(w_globals, space.wrap('__builtins__'), w_builtin)
+    # xxx removed: adding '__builtins__' to the w_globals dict, if there
+    # is none.  This logic was removed as costly (it requires to get at
+    # the gettopframe_nohidden()).  I bet no test fails, and it's a really
+    # obscure case.
 
     return codeobj.exec_code(space, w_globals, w_locals)
diff --git a/pypy/module/__builtin__/functional.py b/pypy/module/__builtin__/functional.py
--- a/pypy/module/__builtin__/functional.py
+++ b/pypy/module/__builtin__/functional.py
@@ -201,223 +201,6 @@
     """
     return min_max(space, __args__, "min")
 
- at unwrap_spec(collections_w="args_w")
-def map(space, w_func, collections_w):
-    """does 3 separate things, hence this enormous docstring.
-       1.  if function is None, return a list of tuples, each with one
-           item from each collection.  If the collections have different
-           lengths,  shorter ones are padded with None.
-
-       2.  if function is not None, and there is only one collection,
-           apply function to every item in the collection and return a
-           list of the results.
-
-       3.  if function is not None, and there are several collections,
-           repeatedly call the function with one argument from each
-           collection.  If the collections have different lengths,
-           shorter ones are padded with None
-    """
-    if not collections_w:
-        msg = "map() requires at least two arguments"
-        raise OperationError(space.w_TypeError, space.wrap(msg))
-    none_func = space.is_w(w_func, space.w_None)
-    if len(collections_w) == 1:
-        w_collection = collections_w[0]
-        if none_func:
-            result_w = space.unpackiterable(w_collection)
-        else:
-            result_w = map_single_collection(space, w_func, w_collection)
-    else:
-        result_w = map_multiple_collections(space, w_func, collections_w,
-                                            none_func)
-    return space.newlist(result_w)
-
-def map_single_collection(space, w_func, w_collection):
-    """Special case for 'map(func, coll)', where 'func' is not None and there
-    is only one 'coll' argument."""
-    w_iter = space.iter(w_collection)
-    # xxx special hacks for speed
-    from pypy.interpreter import function, pycode
-    if isinstance(w_func, function.Function):
-        # xxx compatibility issue: what if func_code is modified in the
-        # middle of running map()??  That's far too obscure for me to care...
-        code = w_func.getcode()
-        fast_natural_arity = code.fast_natural_arity
-        if fast_natural_arity == (1|pycode.PyCode.FLATPYCALL):
-            assert isinstance(code, pycode.PyCode)
-            return map_single_user_function(code, w_func, w_iter)
-    # /xxx end of special hacks
-    return map_single_other_callable(space, w_func, w_iter)
-
-def map_single_other_callable(space, w_func, w_iter):
-    result_w = []
-    while True:
-        try:
-            w_item = space.next(w_iter)
-        except OperationError, e:
-            if not e.match(space, space.w_StopIteration):
-                raise
-            break
-        result_w.append(space.call_function(w_func, w_item))
-    return result_w
-map_single_other_callable._dont_inline_ = True
-
-from pypy.rlib.jit import JitDriver
-mapjitdriver = JitDriver(greens = ['code'],
-                         reds = ['w_func', 'w_iter', 'result_w'])
-def map_single_user_function(code, w_func, w_iter):
-    result_w = []
-    while True:
-        mapjitdriver.can_enter_jit(code=code, w_func=w_func,
-                                   w_iter=w_iter, result_w=result_w)
-        mapjitdriver.jit_merge_point(code=code, w_func=w_func,
-                                     w_iter=w_iter, result_w=result_w)
-        space = w_func.space
-        try:
-            w_item = space.next(w_iter)
-        except OperationError, e:
-            if not e.match(space, space.w_StopIteration):
-                raise
-            break
-        new_frame = space.createframe(code, w_func.w_func_globals,
-                                      w_func)
-        new_frame.locals_stack_w[0] = w_item
-        w_res = new_frame.run()
-        result_w.append(w_res)
-    return result_w
-
-def map_multiple_collections(space, w_func, collections_w, none_func):
-    result_w = []
-    iterators_w = [space.iter(w_seq) for w_seq in collections_w]
-    num_iterators = len(iterators_w)
-    while True:
-        cont = False
-        args_w = [space.w_None] * num_iterators
-        for i in range(num_iterators):
-            if iterators_w[i] is not None:
-                try:
-                    args_w[i] = space.next(iterators_w[i])
-                except OperationError, e:
-                    if not e.match(space, space.w_StopIteration):
-                        raise
-                    iterators_w[i] = None
-                else:
-                    cont = True
-        if not cont:
-            break
-        w_args = space.newtuple(args_w)
-        if none_func:
-            w_res = w_args
-        else:
-            w_res = space.call(w_func, w_args)
-        result_w.append(w_res)
-    return result_w
-
- at unwrap_spec(sequences_w="args_w")
-def zip(space, sequences_w):
-    """Return a list of tuples, where the nth tuple contains every nth item of
-    each collection.
-
-    If the collections have different lengths, zip returns a list as long as the
-    shortest collection, ignoring the trailing items in the other collections.
-    """
-    if not sequences_w:
-        return space.newlist([])
-    result_w = []
-    iterators_w = [space.iter(w_seq) for w_seq in sequences_w]
-    while True:
-        try:
-            items_w = [space.next(w_it) for w_it in iterators_w]
-        except OperationError, e:
-            if not e.match(space, space.w_StopIteration):
-                raise
-            return space.newlist(result_w)
-        result_w.append(space.newtuple(items_w))
-
-def reduce(space, w_func, w_sequence, w_initial=NoneNotWrapped):
-    """ Apply function of two arguments cumulatively to the items of sequence,
-        from left to right, so as to reduce the sequence to a single value.
-        Optionally begin with an initial value.
-    """
-    w_iter = space.iter(w_sequence)
-    if w_initial is None:
-        try:
-            w_initial = space.next(w_iter)
-        except OperationError, e:
-            if e.match(space, space.w_StopIteration):
-                msg = "reduce() of empty sequence with no initial value"
-                raise OperationError(space.w_TypeError, space.wrap(msg))
-            raise
-    w_result = w_initial
-    while True:
-        try:
-            w_next = space.next(w_iter)
-        except OperationError, e:
-            if not e.match(space, space.w_StopIteration):
-                raise
-            break
-        w_result = space.call_function(w_func, w_result, w_next)
-    return w_result
-
-def filter(space, w_func, w_seq):
-    """construct a list of those elements of collection for which function
-       is True.  If function is None, then return the items in the sequence
-       which are True.
-    """
-    if space.is_true(space.isinstance(w_seq, space.w_str)):
-        return _filter_string(space, w_func, w_seq, space.w_str)
-    if space.is_true(space.isinstance(w_seq, space.w_unicode)):
-        return _filter_string(space, w_func, w_seq, space.w_unicode)
-    if space.is_true(space.isinstance(w_seq, space.w_tuple)):
-        return _filter_tuple(space, w_func, w_seq)
-    w_iter = space.iter(w_seq)
-    result_w = []
-    none_func = space.is_w(w_func, space.w_None)
-    while True:
-        try:
-            w_next = space.next(w_iter)
-        except OperationError, e:
-            if not e.match(space, space.w_StopIteration):
-                raise
-            break
-        if none_func:
-            w_keep = w_next
-        else:
-            w_keep = space.call_function(w_func, w_next)
-        if space.is_true(w_keep):
-            result_w.append(w_next)
-    return space.newlist(result_w)
-
-def _filter_tuple(space, w_func, w_tuple):
-    none_func = space.is_w(w_func, space.w_None)
-    length = space.len_w(w_tuple)
-    result_w = []
-    for i in range(length):
-        w_item = space.getitem(w_tuple, space.wrap(i))
-        if none_func:
-            w_keep = w_item
-        else:
-            w_keep = space.call_function(w_func, w_item)
-        if space.is_true(w_keep):
-            result_w.append(w_item)
-    return space.newtuple(result_w)
-
-def _filter_string(space, w_func, w_string, w_str_type):
-    none_func = space.is_w(w_func, space.w_None)
-    if none_func and space.is_w(space.type(w_string), w_str_type):
-        return w_string
-    length = space.len_w(w_string)
-    result_w = []
-    for i in range(length):
-        w_item = space.getitem(w_string, space.wrap(i))
-        if none_func or space.is_true(space.call_function(w_func, w_item)):
-            if not space.is_true(space.isinstance(w_item, w_str_type)):
-                msg = "__getitem__ returned a non-string type"
-                raise OperationError(space.w_TypeError, space.wrap(msg))
-            result_w.append(w_item)
-    w_empty = space.call_function(w_str_type)
-    return space.call_method(w_empty, "join", space.newlist(result_w))
-
 class W_Enumerate(Wrappable):
 
     def __init__(self, w_iter, w_start):
diff --git a/pypy/module/__builtin__/test/test_functional.py b/pypy/module/__builtin__/test/test_functional.py
--- a/pypy/module/__builtin__/test/test_functional.py
+++ b/pypy/module/__builtin__/test/test_functional.py
@@ -147,7 +147,7 @@
        assert list(xrange(A())) == [0, 1, 2, 3, 4]
        assert list(xrange(0, A())) == [0, 1, 2, 3, 4]
        assert list(xrange(0, 10, A())) == [0, 5]
- 
+
    def test_xrange_float(self):
       assert list(xrange(0.1, 2.0, 1.1)) == [0, 1]
 
diff --git a/pypy/module/__builtin__/test/test_rawinput.py b/pypy/module/__builtin__/test/test_rawinput.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/__builtin__/test/test_rawinput.py
@@ -0,0 +1,80 @@
+import autopath
+
+
+class AppTestRawInput():
+
+    def test_input_and_raw_input(self):
+        import sys, StringIO
+        for prompt, expected in [("def:", "abc/ def:/ghi\n"),
+                                 ("", "abc/ /ghi\n"),
+                                 (42, "abc/ 42/ghi\n"),
+                                 (None, "abc/ None/ghi\n"),
+                                 (Ellipsis, "abc/ /ghi\n")]:
+            for inputfn, inputtext, gottext in [
+                    (raw_input, "foo\nbar\n", "foo"),
+                    (input, "40+2\n", 42)]:
+                save = sys.stdin, sys.stdout
+                try:
+                    sys.stdin = StringIO.StringIO(inputtext)
+                    out = sys.stdout = StringIO.StringIO()
+                    print "abc",    # softspace = 1
+                    out.write('/')
+                    if prompt is Ellipsis:
+                        got = inputfn()
+                    else:
+                        got = inputfn(prompt)
+                    out.write('/')
+                    print "ghi"
+                finally:
+                    sys.stdin, sys.stdout = save
+                assert out.getvalue() == expected
+                assert got == gottext
+
+    def test_softspace(self):
+        import sys
+        import StringIO
+        fin = StringIO.StringIO()
+        fout = StringIO.StringIO()
+
+        fin.write("Coconuts\n")
+        fin.seek(0)
+
+        sys_stdin_orig = sys.stdin
+        sys_stdout_orig = sys.stdout
+
+        sys.stdin = fin
+        sys.stdout = fout
+
+        print "test",
+        raw_input("test")
+
+        sys.stdin = sys_stdin_orig
+        sys.stdout = sys_stdout_orig
+
+        fout.seek(0)
+        assert fout.read() == "test test"
+
+    def test_softspace_carryover(self):
+        import sys
+        import StringIO
+        fin = StringIO.StringIO()
+        fout = StringIO.StringIO()
+
+        fin.write("Coconuts\n")
+        fin.seek(0)
+
+        sys_stdin_orig = sys.stdin
+        sys_stdout_orig = sys.stdout
+
+        sys.stdin = fin
+        sys.stdout = fout
+
+        print "test",
+        raw_input("test")
+        print "test",
+
+        sys.stdin = sys_stdin_orig
+        sys.stdout = sys_stdout_orig
+
+        fout.seek(0)
+        assert fout.read() == "test testtest"
diff --git a/pypy/module/_continuation/interp_continuation.py b/pypy/module/_continuation/interp_continuation.py
--- a/pypy/module/_continuation/interp_continuation.py
+++ b/pypy/module/_continuation/interp_continuation.py
@@ -19,6 +19,11 @@
         #  - normal:      self.sthread != None, not is_empty_handle(self.h)
         #  - finished:    self.sthread != None, is_empty_handle(self.h)
 
+    def __del__(self):
+        sthread = self.sthread
+        if sthread is not None and not sthread.is_empty_handle(self.h):
+            sthread.destroy(self.h)
+
     def check_sthread(self):
         ec = self.space.getexecutioncontext()
         if ec.stacklet_thread is not self.sthread:
@@ -28,6 +33,8 @@
     def descr_init(self, w_callable, __args__):
         if self.sthread is not None:
             raise geterror(self.space, "continulet already __init__ialized")
+        sthread = build_sthread(self.space)
+        workaround_disable_jit(sthread)
         #
         # hackish: build the frame "by hand", passing it the correct arguments
         space = self.space
@@ -41,7 +48,6 @@
         self.bottomframe = bottomframe
         #
         global_state.origin = self
-        sthread = build_sthread(self.space)
         self.sthread = sthread
         h = sthread.new(new_stacklet_callback)
         post_switch(sthread, h)
@@ -71,6 +77,7 @@
                 global_state.clear()
                 raise geterror(self.space, "continulet already finished")
         self.check_sthread()
+        workaround_disable_jit(self.sthread)
         #
         global_state.origin = self
         if to is None:
@@ -259,6 +266,16 @@
         sthread = ec.stacklet_thread = SThread(space, ec)
     return sthread
 
+def workaround_disable_jit(sthread):
+    # A bad workaround to kill the JIT anywhere in this thread.
+    # This forces all the frames.  It's a bad workaround because
+    # it takes O(depth) time, and it will cause some "abort:
+    # vable escape" in the JIT.  The goal is to prevent any frame
+    # from being still virtuals, because the JIT generates code
+    # to un-virtualizable them "on demand" by loading values based
+    # on FORCE_TOKEN, which is an address in the stack.
+    sthread.ec.force_all_frames()
+
 # ____________________________________________________________
 
 def permute(space, args_w):
diff --git a/pypy/module/_file/test/test_file.py b/pypy/module/_file/test/test_file.py
--- a/pypy/module/_file/test/test_file.py
+++ b/pypy/module/_file/test/test_file.py
@@ -260,8 +260,12 @@
 class AppTestNonblocking(object):
     def setup_class(cls):
         from pypy.module._file.interp_file import W_File
-        
+
         cls.old_read = os.read
+
+        if option.runappdirect:
+            py.test.skip("works with internals of _file impl on py.py")
+
         state = [0]
         def read(fd, n=None):
             if fd != 42:
@@ -281,7 +285,7 @@
 
     def teardown_class(cls):
         os.read = cls.old_read
-        
+
     def test_nonblocking_file(self):
         res = self.stream.read()
         assert res == 'xyz'
@@ -403,24 +407,24 @@
         with self.file(self.temppath, 'w') as f:
             f.write('foo')
         assert f.closed
-        
+
         with self.file(self.temppath, 'r') as f:
             s = f.readline()
 
         assert s == "foo"
         assert f.closed
-    
+
     def test_subclass_with(self):
         file = self.file
         class C(file):
             def __init__(self, *args, **kwargs):
                 self.subclass_closed = False
                 file.__init__(self, *args, **kwargs)
-            
+
             def close(self):
                 self.subclass_closed = True
                 file.close(self)
-        
+
         with C(self.temppath, 'w') as f:
             pass
         assert f.subclass_closed
diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -161,9 +161,6 @@
     @binop
     def mul(self, v1, v2):
         return v1 * v2
-    @binop
-    def div(self, v1, v2):
-        return v1 / v2
 
     @unaryop
     def pos(self, v):
@@ -217,6 +214,14 @@
         return float2string(self.for_computation(self.unbox(item)), 'g', rfloat.DTSF_STR_PRECISION)
 
     @binop
+    def div(self, v1, v2):
+        try:
+            return v1 / v2
+        except ZeroDivisionError:
+            if v1 == v2 == 0.0:
+                return rfloat.NAN
+            return rfloat.copysign(rfloat.INFINITY, v1 * v2)
+    @binop
     def mod(self, v1, v2):
         return math.fmod(v1, v2)
     @binop
@@ -295,6 +300,11 @@
         return str(widen(self.unbox(item)))
 
     @binop
+    def div(self, v1, v2):
+        if v2 == 0:
+            return 0
+        return v1 / v2
+    @binop
     def mod(self, v1, v2):
         return v1 % v2
 
@@ -426,23 +436,22 @@
     pass
 
 if LONG_BIT == 32:
-    class W_LongDtype(W_Int32Dtype):
-        pass
+    long_dtype = W_Int32Dtype
+    ulong_dtype = W_UInt32Dtype
+elif LONG_BIT == 64:
+    long_dtype = W_Int64Dtype
+    ulong_dtype = W_UInt64Dtype
+else:
+    assert False
 
-    class W_ULongDtype(W_UInt32Dtype):
-        pass
-else:
-    class W_LongDtype(W_Int64Dtype):
-        pass
+class W_LongDtype(long_dtype):
+    num = 7
+    aliases = ["l"]
+    applevel_types = ["int"]
 
-    class W_ULongDtype(W_UInt64Dtype):
-        pass
-
-W_LongDtype.num = 7
-W_LongDtype.aliases = ["l"]
-W_LongDtype.applevel_types = ["int"]
-W_ULongDtype.num = 8
-W_ULongDtype.aliases = ["L"]
+class W_ULongDtype(ulong_dtype):
+    num = 8
+    aliases = ["L"]
 
 W_Float32Dtype = create_low_level_dtype(
     num = 11, kind = FLOATINGLTR, name = "float32",
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -285,7 +285,9 @@
             assert b[i] == i * 5
 
     def test_div(self):
-        from numpy import array, dtype
+        from math import isnan
+        from numpy import array, dtype, inf
+
         a = array(range(1, 6))
         b = a / a
         for i in range(5):
@@ -297,6 +299,24 @@
         for i in range(5):
             assert b[i] == 1
 
+        a = array([-1, 0, 1])
+        b = array([0, 0, 0])
+        c = a / b
+        assert (c == [0, 0, 0]).all()
+
+        a = array([-1.0, 0.0, 1.0])
+        b = array([0.0, 0.0, 0.0])
+        c = a / b
+        assert c[0] == -inf
+        assert isnan(c[1])
+        assert c[2] == inf
+
+        b = array([-0.0, -0.0, -0.0])
+        c = a / b
+        assert c[0] == inf
+        assert isnan(c[1])
+        assert c[2] == -inf
+
     def test_div_other(self):
         from numpy import array
         a = array(range(5))
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
@@ -420,12 +420,15 @@
             import sys
             if not hasattr(os, "fork"):
                 skip("Need fork() to test execv()")
+            try:
+                output = u"caf\xe9 \u1234\n".encode(sys.getfilesystemencoding())
+            except UnicodeEncodeError:
+                skip("encoding not good enough")
             pid = os.fork()
             if pid == 0:
                 os.execv(u"/bin/sh", ["sh", "-c",
                                       u"echo caf\xe9 \u1234 > onefile"])
             os.waitpid(pid, 0)
-            output = u"caf\xe9 \u1234\n".encode(sys.getfilesystemencoding())
             assert open("onefile").read() == output
             os.unlink("onefile")
 
@@ -445,13 +448,16 @@
             import sys
             if not hasattr(os, "fork"):
                 skip("Need fork() to test execve()")
+            try:
+                output = u"caf\xe9 \u1234\n".encode(sys.getfilesystemencoding())
+            except UnicodeEncodeError:
+                skip("encoding not good enough")
             pid = os.fork()
             if pid == 0:
                 os.execve(u"/bin/sh", ["sh", "-c",
                                       u"echo caf\xe9 \u1234 > onefile"],
                           {'ddd': 'xxx'})
             os.waitpid(pid, 0)
-            output = u"caf\xe9 \u1234\n".encode(sys.getfilesystemencoding())
             assert open("onefile").read() == output
             os.unlink("onefile")
         pass # <- please, inspect.getsource(), don't crash
diff --git a/pypy/module/pyexpat/__init__.py b/pypy/module/pyexpat/__init__.py
--- a/pypy/module/pyexpat/__init__.py
+++ b/pypy/module/pyexpat/__init__.py
@@ -4,12 +4,8 @@
 
 class ErrorsModule(MixedModule):
     "Definition of pyexpat.errors module."
-
-    appleveldefs = {
-        }
-
-    interpleveldefs = {
-        }
+    appleveldefs = {}
+    interpleveldefs = {}
 
     def setup_after_space_initialization(self):
         from pypy.module.pyexpat import interp_pyexpat
@@ -18,6 +14,18 @@
                     interp_pyexpat.ErrorString(self.space,
                     getattr(interp_pyexpat, name)))
 
+class ModelModule(MixedModule):
+    "Definition of pyexpat.model module."
+    appleveldefs = {}
+    interpleveldefs = {}
+
+    def setup_after_space_initialization(self):
+        from pypy.module.pyexpat import interp_pyexpat
+        space = self.space
+        for name in interp_pyexpat.xml_model_list:
+            value = getattr(interp_pyexpat, name)
+            space.setattr(self, space.wrap(name), space.wrap(value))
+
 class Module(MixedModule):
     "Python wrapper for Expat parser."
 
@@ -39,6 +47,7 @@
 
     submodules = {
         'errors': ErrorsModule,
+        'model':  ModelModule,
     }
 
     for name in ['XML_PARAM_ENTITY_PARSING_NEVER',
diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py
--- a/pypy/module/pyexpat/interp_pyexpat.py
+++ b/pypy/module/pyexpat/interp_pyexpat.py
@@ -76,6 +76,18 @@
     "XML_ERROR_FINISHED",
     "XML_ERROR_SUSPEND_PE",
     ]
+xml_model_list = [
+    "XML_CTYPE_EMPTY",
+    "XML_CTYPE_ANY",
+    "XML_CTYPE_MIXED",
+    "XML_CTYPE_NAME",
+    "XML_CTYPE_CHOICE",
+    "XML_CTYPE_SEQ",
+    "XML_CQUANT_NONE",
+    "XML_CQUANT_OPT",
+    "XML_CQUANT_REP",
+    "XML_CQUANT_PLUS",
+    ]
 
 class CConfigure:
     _compilation_info_ = eci
@@ -104,6 +116,8 @@
 
     for name in xml_error_list:
         locals()[name] = rffi_platform.ConstantInteger(name)
+    for name in xml_model_list:
+        locals()[name] = rffi_platform.ConstantInteger(name)
 
 for k, v in rffi_platform.configure(CConfigure).items():
     globals()[k] = v
diff --git a/pypy/module/pyexpat/test/test_parser.py b/pypy/module/pyexpat/test/test_parser.py
--- a/pypy/module/pyexpat/test/test_parser.py
+++ b/pypy/module/pyexpat/test/test_parser.py
@@ -131,3 +131,7 @@
                'encoding specified in XML declaration is incorrect')
         assert (pyexpat.errors.XML_ERROR_XML_DECL ==
                 'XML declaration not well-formed')
+
+    def test_model(self):
+        import pyexpat
+        assert isinstance(pyexpat.model.XML_CTYPE_EMPTY, int)
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -137,20 +137,15 @@
 
     def jump_absolute(self, jumpto, _, ec=None):
         if we_are_jitted():
-            # Normally, the tick counter is decremented by 100 for every
-            # Python opcode.  Here, to better support JIT compilation of
-            # small loops, we decrement it by a possibly smaller constant.
-            # We get the maximum 100 when the (unoptimized) trace length
-            # is at least 3200 (a bit randomly).
-            trace_length = r_uint(current_trace_length())
-            decr_by = trace_length // 32
-            if decr_by < 1:
-                decr_by = 1
-            elif decr_by > 100:    # also if current_trace_length() returned -1
-                decr_by = 100
+            #
+            # assume that only threads are using the bytecode counter
+            decr_by = 0
+            if self.space.actionflag.has_bytecode_counter:   # constant-folded
+                if self.space.threadlocals.gil_ready:   # quasi-immutable field
+                    decr_by = _get_adapted_tick_counter()
             #
             self.last_instr = intmask(jumpto)
-            ec.bytecode_trace(self, intmask(decr_by))
+            ec.bytecode_trace(self, decr_by)
             jumpto = r_uint(self.last_instr)
         #
         pypyjitdriver.can_enter_jit(frame=self, ec=ec, next_instr=jumpto,
@@ -158,6 +153,20 @@
                                     is_being_profiled=self.is_being_profiled)
         return jumpto
 
+def _get_adapted_tick_counter():
+    # Normally, the tick counter is decremented by 100 for every
+    # Python opcode.  Here, to better support JIT compilation of
+    # small loops, we decrement it by a possibly smaller constant.
+    # We get the maximum 100 when the (unoptimized) trace length
+    # is at least 3200 (a bit randomly).
+    trace_length = r_uint(current_trace_length())
+    decr_by = trace_length // 32
+    if decr_by < 1:
+        decr_by = 1
+    elif decr_by > 100:    # also if current_trace_length() returned -1
+        decr_by = 100
+    return intmask(decr_by)
+
 
 PyCode__initialize = PyCode._initialize
 
diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py
--- a/pypy/module/pypyjit/test_pypy_c/model.py
+++ b/pypy/module/pypyjit/test_pypy_c/model.py
@@ -225,6 +225,8 @@
         # strip comment
         if '#' in line:
             line = line[:line.index('#')]
+        if line.strip() == 'guard_not_invalidated?':
+            return 'guard_not_invalidated', None, [], '...', False
         # find the resvar, if any
         if ' = ' in line:
             resvar, _, line = line.partition(' = ')
@@ -249,7 +251,7 @@
             descr = descr[len('descr='):]
         else:
             descr = None
-        return opname, resvar, args, descr
+        return opname, resvar, args, descr, True
 
     @classmethod
     def preprocess_expected_src(cls, src):
@@ -258,13 +260,23 @@
         # replaced with the corresponding operations, so that tests don't have
         # to repeat it every time
         ticker_check = """
+            guard_not_invalidated?
+            ticker0 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
+            ticker_cond0 = int_lt(ticker0, 0)
+            guard_false(ticker_cond0, descr=...)
+        """
+        src = src.replace('--TICK--', ticker_check)
+        #
+        # this is the ticker check generated if we have threads
+        thread_ticker_check = """
+            guard_not_invalidated?
             ticker0 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
             ticker1 = int_sub(ticker0, 1)
             setfield_raw(ticker_address, ticker1, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
             ticker_cond0 = int_lt(ticker1, 0)
             guard_false(ticker_cond0, descr=...)
         """
-        src = src.replace('--TICK--', ticker_check)
+        src = src.replace('--THREAD-TICK--', thread_ticker_check)
         #
         # this is the ticker check generated in PyFrame.handle_operation_error
         exc_ticker_check = """
@@ -298,7 +310,7 @@
         if not cond:
             raise InvalidMatch(message, frame=sys._getframe(1))
 
-    def match_op(self, op, (exp_opname, exp_res, exp_args, exp_descr)):
+    def match_op(self, op, (exp_opname, exp_res, exp_args, exp_descr, _)):
         self._assert(op.name == exp_opname, "operation mismatch")
         self.match_var(op.res, exp_res)
         if exp_args != ['...']:
@@ -341,7 +353,7 @@
         what is after the '...'
         """
         iter_exp_ops = iter(expected_ops)
-        iter_ops = iter(self.ops)
+        iter_ops = RevertableIterator(self.ops)
         for opindex, exp_op in enumerate(iter_exp_ops):
             try:
                 if exp_op == '...':
@@ -360,6 +372,9 @@
                             break
                 self.match_op(op, exp_op)
             except InvalidMatch, e:
+                if exp_op[4] is False:    # optional operation
+                    iter_ops.revert_one()
+                    continue       # try to match with the next exp_op
                 e.opindex = opindex
                 raise
         #
@@ -372,8 +387,8 @@
                 return ''
             text = str(py.code.Source(src).deindent().indent())
             lines = text.splitlines(True)
-            if opindex is not None and 0 <= opindex < len(lines):
-                lines[opindex] = lines[opindex].rstrip() + '\t<=====\n'
+            if opindex is not None and 0 <= opindex <= len(lines):
+                lines.insert(opindex, '\n\t===== HERE =====\n')
             return ''.join(lines)
         #
         expected_src = self.preprocess_expected_src(expected_src)
@@ -398,3 +413,18 @@
         else:
             return True
 
+
+class RevertableIterator(object):
+    def __init__(self, sequence):
+        self.sequence = sequence
+        self.index = 0
+    def __iter__(self):
+        return self
+    def next(self):
+        index = self.index
+        if index == len(self.sequence):
+            raise StopIteration
+        self.index = index + 1
+        return self.sequence[index]
+    def revert_one(self):
+        self.index -= 1
diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
--- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py
@@ -145,15 +145,17 @@
 
     def test_parse_op(self):
         res = OpMatcher.parse_op("  a =   int_add(  b,  3 ) # foo")
-        assert res == ("int_add", "a", ["b", "3"], None)
+        assert res == ("int_add", "a", ["b", "3"], None, True)
         res = OpMatcher.parse_op("guard_true(a)")
-        assert res == ("guard_true", None, ["a"], None)
+        assert res == ("guard_true", None, ["a"], None, True)
         res = OpMatcher.parse_op("setfield_gc(p0, i0, descr=<foobar>)")
-        assert res == ("setfield_gc", None, ["p0", "i0"], "<foobar>")
+        assert res == ("setfield_gc", None, ["p0", "i0"], "<foobar>", True)
         res = OpMatcher.parse_op("i1 = getfield_gc(p0, descr=<foobar>)")
-        assert res == ("getfield_gc", "i1", ["p0"], "<foobar>")
+        assert res == ("getfield_gc", "i1", ["p0"], "<foobar>", True)
         res = OpMatcher.parse_op("p0 = force_token()")
-        assert res == ("force_token", "p0", [], None)
+        assert res == ("force_token", "p0", [], None, True)
+        res = OpMatcher.parse_op("guard_not_invalidated?")
+        assert res == ("guard_not_invalidated", None, [], '...', False)
 
     def test_exact_match(self):
         loop = """
@@ -341,7 +343,7 @@
             # this is the actual loop
             'int_lt', 'guard_true', 'int_add',
             # this is the signal checking stuff
-            'getfield_raw', 'int_sub', 'setfield_raw', 'int_lt', 'guard_false',
+            'guard_not_invalidated', 'getfield_raw', 'int_lt', 'guard_false',
             'jump'
             ]
 
@@ -407,7 +409,7 @@
             # this is the actual loop
             'int_lt', 'guard_true', 'force_token', 'int_add',
             # this is the signal checking stuff
-            'getfield_raw', 'int_sub', 'setfield_raw', 'int_lt', 'guard_false',
+            'guard_not_invalidated', 'getfield_raw', 'int_lt', 'guard_false',
             'jump'
             ]
 
@@ -425,10 +427,9 @@
             guard_true(i6, descr=...)
             i8 = int_add(i4, 1)
             # signal checking stuff
+            guard_not_invalidated(descr=...)
             i10 = getfield_raw(37212896, descr=<.* pypysig_long_struct.c_value .*>)
-            i12 = int_sub(i10, 1)
-            setfield_raw(37212896, i12, descr=<.* pypysig_long_struct.c_value .*>)
-            i14 = int_lt(i12, 0)
+            i14 = int_lt(i10, 0)
             guard_false(i14, descr=...)
             jump(p0, p1, p2, p3, i8, descr=...)
         """)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_containers.py b/pypy/module/pypyjit/test_pypy_c/test_containers.py
--- a/pypy/module/pypyjit/test_pypy_c/test_containers.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_containers.py
@@ -46,7 +46,7 @@
         assert loop.match_by_id("getitem", """
             i28 = call(ConstClass(ll_dict_lookup__dicttablePtr_objectPtr_Signed), p18, p6, i25, descr=...)
             ...
-            p33 = call(ConstClass(ll_get_value__dicttablePtr_Signed), p18, i28, descr=...)
+            p33 = getinteriorfield_gc(p31, i26, descr=<InteriorFieldDescr <GcPtrFieldDescr dictentry.value .*>>)
             ...
         """)
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -329,4 +329,20 @@
             guard_false(i28, descr=...)
             i30 = int_lshift(i20, 24)
             i31 = int_or(i26, i30)
-        """ % {"32_bit_only": extra})
\ No newline at end of file
+        """ % {"32_bit_only": extra})
+
+    def test_eval(self):
+        def main():
+            i = 1
+            a = compile('x+x+x+x+x+x', 'eval', 'eval')
+            b = {'x': 7}
+            while i < 1000:
+                y = eval(a,b,b)  # ID: eval
+                i += 1
+            return y
+
+        log = self.run(main)
+        assert log.result == 42
+        # the following assertion fails if the loop was cancelled due
+        # to "abort: vable escape"
+        assert len(log.loops_by_id("eval")) == 1
diff --git a/pypy/module/pypyjit/test_pypy_c/test_string.py b/pypy/module/pypyjit/test_pypy_c/test_string.py
--- a/pypy/module/pypyjit/test_pypy_c/test_string.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_string.py
@@ -41,7 +41,7 @@
             guard_true(i32, descr=...)
             i34 = int_add(i6, 1)
             --TICK--
-            jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=<Loop4>)
+            jump(p0, p1, p2, p3, p4, p5, i34, p7, p8, i9, i10, p11, i12, p13, descr=...)
         """)
 
     def test_long(self):
@@ -93,7 +93,8 @@
             i46 = call(ConstClass(ll_startswith__rpy_stringPtr_rpy_stringPtr), p28, ConstPtr(ptr45), descr=<BoolCallDescr>)
             guard_false(i46, descr=...)
             p51 = new_with_vtable(21136408)
-            setfield_gc(p51, _, descr=...)    # 6 setfields, but the order is dict-order-dependent
+            setfield_gc(p51, _, descr=...)    # 7 setfields, but the order is dict-order-dependent
+            setfield_gc(p51, _, descr=...)
             setfield_gc(p51, _, descr=...)
             setfield_gc(p51, _, descr=...)
             setfield_gc(p51, _, descr=...)
@@ -106,7 +107,7 @@
             i58 = int_add_ovf(i6, i57)
             guard_no_overflow(descr=...)
             --TICK--
-            jump(p0, p1, p2, p3, p4, p5, i58, i7, descr=<Loop4>)
+            jump(p0, p1, p2, p3, p4, p5, i58, i7, descr=...)
         """)
 
     def test_str_mod(self):
@@ -156,4 +157,41 @@
             i40 = int_sub(i4, 1)
             --TICK--
             jump(p0, p1, p2, p3, i40, i38, descr=<Loop0>)
-        """)
\ No newline at end of file
+        """)
+
+    def test_getattr_promote(self):
+        def main(n):
+            class A(object):
+                def meth_a(self):
+                    return 1
+                def meth_b(self):
+                    return 2
+            a = A()
+
+            l = ['a', 'b']
+            s = 0
+            for i in range(n):
+                name = 'meth_' + l[i & 1]
+                meth = getattr(a, name) # ID: getattr
+                s += meth()
+            return s
+
+        log = self.run(main, [1000])
+        assert log.result == main(1000)
+        loops = log.loops_by_filename(self.filepath)
+        assert len(loops) == 2
+        for loop in loops:
+            loop.match_by_id('getattr','''
+            guard_not_invalidated(descr=...)
+            i32 = strlen(p31)
+            i34 = int_add(5, i32)
+            p35 = newstr(i34)
+            strsetitem(p35, 0, 109)
+            strsetitem(p35, 1, 101)
+            strsetitem(p35, 2, 116)
+            strsetitem(p35, 3, 104)
+            strsetitem(p35, 4, 95)
+            copystrcontent(p31, p35, 0, 5, i32)
+            i49 = call(ConstClass(_ll_2_str_eq_nonnull__rpy_stringPtr_rpy_stringPtr), p35, ConstPtr(ptr48), descr=<SignedCallDescr>)
+            guard_value(i49, 1, descr=<Guard8>)
+            ''')
diff --git a/pypy/module/pypyjit/test_pypy_c/test_thread.py b/pypy/module/pypyjit/test_pypy_c/test_thread.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/pypyjit/test_pypy_c/test_thread.py
@@ -0,0 +1,28 @@
+from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
+
+
+class TestThread(BaseTestPyPyC):
+    def test_simple(self):
+        def main(n):
+            import thread
+            def f():
+                i = 0
+                while i < n:
+                    i += 1
+                done.release()
+
+            done = thread.allocate_lock()
+            done.acquire()
+            thread.start_new_thread(f, ())
+            done.acquire()
+            return 0
+        log = self.run(main, [500])
+        assert round(log.result, 6) == round(main(500), 6)
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match("""
+            i2 = int_lt(i0, i1)
+            guard_true(i2, descr=...)
+            i3 = int_add(i0, 1)
+            --THREAD-TICK--
+            jump(..., descr=<Loop0>)
+        """)
diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -109,8 +109,11 @@
         p = pypysig_getaddr_occurred()
         value = p.c_value
         if self.has_bytecode_counter:    # this 'if' is constant-folded
-            value -= by
-            p.c_value = value
+            if jit.isconstant(by) and by == 0:
+                pass     # normally constant-folded too
+            else:
+                value -= by
+                p.c_value = value
         return value
 
 
diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py
--- a/pypy/module/sys/__init__.py
+++ b/pypy/module/sys/__init__.py
@@ -47,7 +47,7 @@
         'pypy_initial_path'     : 'state.pypy_initial_path',
 
         '_getframe'             : 'vm._getframe', 
-        '_current_frames'       : 'vm._current_frames', 
+        '_current_frames'       : 'currentframes._current_frames', 
         'setrecursionlimit'     : 'vm.setrecursionlimit', 
         'getrecursionlimit'     : 'vm.getrecursionlimit', 
         'setcheckinterval'      : 'vm.setcheckinterval', 
diff --git a/pypy/module/sys/currentframes.py b/pypy/module/sys/currentframes.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/sys/currentframes.py
@@ -0,0 +1,78 @@
+"""
+Implementation of the 'sys._current_frames()' routine.
+"""
+from pypy.interpreter import gateway
+
+app = gateway.applevel('''
+"NOT_RPYTHON"
+import __builtin__
+
+class fake_code(object):
+    co_name = "?"
+    co_filename = "?"
+    co_firstlineno = 0
+
+class fake_frame(object):
+    f_back = None
+    f_builtins = __builtin__.__dict__
+    f_code = fake_code()
+    f_exc_traceback = None
+    f_exc_type = None
+    f_exc_value = None
+    f_globals = {}
+    f_lasti = -1
+    f_lineno = 0
+    f_locals = {}
+    f_restricted = False
+    f_trace = None
+
+    def __init__(self, f):
+        if f is not None:
+            for name in ["f_builtins", "f_code", "f_globals", "f_lasti",
+                         "f_lineno"]:
+                setattr(self, name, getattr(f, name))
+''')
+
+def _current_frames(space):
+    """_current_frames() -> dictionary
+
+    Return a dictionary mapping each current thread T's thread id to T's
+    current stack "frame".  Functions in the traceback module can build the
+    call stack given such a frame.
+
+    Note that in PyPy this returns fake frame objects, to avoid a runtime
+    penalty everywhere with the JIT.  (So far these fake frames can be
+    completely uninformative depending on the JIT state; we could return
+    more with more efforts.)
+
+    This function should be used for specialized purposes only."""
+    w_result = space.newdict()
+    w_fake_frame = app.wget(space, "fake_frame")
+    w_fake_code  = app.wget(space, "fake_code")
+    ecs = space.threadlocals.getallvalues()
+    for thread_ident, ec in ecs.items():
+        vref = ec.topframeref
+        frames = []
+        while not vref.virtual:
+            f = vref()
+            if f is None:
+                break
+            frames.append(f)
+            vref = f.f_backref
+        else:
+            frames.append(None)
+        #
+        w_topframe = space.wrap(None)
+        w_prevframe = None
+        for f in frames:
+            w_nextframe = space.call_function(w_fake_frame, space.wrap(f))
+            if w_prevframe is None:
+                w_topframe = w_nextframe
+            else:
+                space.setattr(w_prevframe, space.wrap('f_back'), w_nextframe)
+            w_prevframe = w_nextframe
+        #
+        space.setitem(w_result,
+                      space.wrap(thread_ident),
+                      w_topframe)
+    return w_result
diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py
--- a/pypy/module/sys/test/test_sysmodule.py
+++ b/pypy/module/sys/test/test_sysmodule.py
@@ -556,7 +556,7 @@
             return sys._current_frames()
         frames = f()
         assert frames.keys() == [0]
-        assert frames[0].f_code.co_name == 'f'
+        assert frames[0].f_code.co_name in ('f', '?')
 
 class AppTestCurrentFramesWithThread(AppTestCurrentFrames):
     def setup_class(cls):
@@ -568,23 +568,25 @@
         import thread
 
         thread_id = thread.get_ident()
-        self.ready = False
         def other_thread():
-            self.ready = True
             print "thread started"
-            time.sleep(5)
+            lock2.release()
+            lock1.acquire()
+        lock1 = thread.allocate_lock()
+        lock2 = thread.allocate_lock()
+        lock1.acquire()
+        lock2.acquire()
         thread.start_new_thread(other_thread, ())
 
         def f():
-            for i in range(100):
-                if self.ready: break
-                time.sleep(0.1)
+            lock2.acquire()
             return sys._current_frames()
 
         frames = f()
+        lock1.release()
         thisframe = frames.pop(thread_id)
-        assert thisframe.f_code.co_name == 'f'
+        assert thisframe.f_code.co_name in ('f', '?')
 
         assert len(frames) == 1
         _, other_frame = frames.popitem()
-        assert other_frame.f_code.co_name == 'other_thread'
+        assert other_frame.f_code.co_name in ('other_thread', '?')
diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py
--- a/pypy/module/sys/vm.py
+++ b/pypy/module/sys/vm.py
@@ -45,25 +45,6 @@
     f.mark_as_escaped()
     return space.wrap(f)
 
-def _current_frames(space):
-    """_current_frames() -> dictionary
-
-    Return a dictionary mapping each current thread T's thread id to T's
-    current stack frame.
-
-    This function should be used for specialized purposes only."""
-    raise OperationError(space.w_NotImplementedError,
-        space.wrap("XXX sys._current_frames() incompatible with the JIT"))
-    w_result = space.newdict()
-    ecs = space.threadlocals.getallvalues()
-    for thread_ident, ec in ecs.items():
-        f = ec.gettopframe_nohidden()
-        f.mark_as_escaped()
-        space.setitem(w_result,
-                      space.wrap(thread_ident),
-                      space.wrap(f))
-    return w_result
-
 def setrecursionlimit(space, w_new_limit):
     """setrecursionlimit() sets the maximum number of nested calls that
 can occur before a RuntimeError is raised.  On PyPy the limit is
diff --git a/pypy/module/thread/gil.py b/pypy/module/thread/gil.py
--- a/pypy/module/thread/gil.py
+++ b/pypy/module/thread/gil.py
@@ -17,6 +17,7 @@
 class GILThreadLocals(OSThreadLocals):
     """A version of OSThreadLocals that enforces a GIL."""
     gil_ready = False
+    _immutable_fields_ = ['gil_ready?']
 
     def initialize(self, space):
         # add the GIL-releasing callback as an action on the space
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
@@ -8,9 +8,14 @@
 
     def __init__(self):
         self._valuedict = {}   # {thread_ident: ExecutionContext()}
+        self._freeze_()
+
+    def _freeze_(self):
+        self._valuedict.clear()
         self._mainthreadident = 0
         self._mostrecentkey = 0        # fast minicaching for the common case
         self._mostrecentvalue = None   # fast minicaching for the common case
+        return False
 
     def getvalue(self):
         ident = thread.get_ident()
diff --git a/pypy/objspace/std/newformat.py b/pypy/objspace/std/newformat.py
--- a/pypy/objspace/std/newformat.py
+++ b/pypy/objspace/std/newformat.py
@@ -120,6 +120,8 @@
             out.append_slice(s, last_literal, end)
             return out.build()
 
+        # This is only ever called if we're already unrolling _do_build_string
+        @jit.unroll_safe
         def _parse_field(self, start, end):
             s = self.template
             # Find ":" or "!"
@@ -149,6 +151,7 @@
                 i += 1
             return s[start:end], None, end
 
+        @jit.unroll_safe
         def _get_argument(self, name):
             # First, find the argument.
             space = self.space
@@ -207,6 +210,7 @@
                     raise OperationError(space.w_IndexError, w_msg)
             return self._resolve_lookups(w_arg, name, i, end)
 
+        @jit.unroll_safe
         def _resolve_lookups(self, w_obj, name, start, end):
             # Resolve attribute and item lookups.
             space = self.space
diff --git a/pypy/objspace/std/objecttype.py b/pypy/objspace/std/objecttype.py
--- a/pypy/objspace/std/objecttype.py
+++ b/pypy/objspace/std/objecttype.py
@@ -44,7 +44,6 @@
         raise OperationError(space.w_TypeError,
                              space.wrap("__class__ assignment: only for heap types"))
     w_oldcls = space.type(w_obj)
-    # XXX taint space should raise a TaintError here if w_oldcls is tainted
     assert isinstance(w_oldcls, W_TypeObject)
     if w_oldcls.get_full_instance_layout() == w_newcls.get_full_instance_layout():
         w_obj.setclass(space, w_newcls)
diff --git a/pypy/objspace/std/stringobject.py b/pypy/objspace/std/stringobject.py
--- a/pypy/objspace/std/stringobject.py
+++ b/pypy/objspace/std/stringobject.py
@@ -161,57 +161,59 @@
 
 def str_swapcase__String(space, w_self):
     self = w_self._value
-    res = [' '] * len(self)
+    builder = StringBuilder(len(self))
     for i in range(len(self)):
         ch = self[i]
         if ch.isupper():
             o = ord(ch) + 32
-            res[i] = chr(o)
+            builder.append(chr(o))
         elif ch.islower():
             o = ord(ch) - 32
-            res[i] = chr(o)
+            builder.append(chr(o))
         else:
-            res[i] = ch
+            builder.append(ch)
 
-    return space.wrap("".join(res))
+    return space.wrap(builder.build())
 
 
 def str_capitalize__String(space, w_self):
     input = w_self._value
-    buffer = [' '] * len(input)
+    builder = StringBuilder(len(input))
     if len(input) > 0:
         ch = input[0]
         if ch.islower():
             o = ord(ch) - 32
-            buffer[0] = chr(o)
+            builder.append(chr(o))
         else:
-            buffer[0] = ch
+            builder.append(ch)
 
         for i in range(1, len(input)):
             ch = input[i]
             if ch.isupper():
                 o = ord(ch) + 32
-                buffer[i] = chr(o)
+                builder.append(chr(o))
             else:
-                buffer[i] = ch
+                builder.append(ch)
 
-    return space.wrap("".join(buffer))
+    return space.wrap(builder.build())
 
 def str_title__String(space, w_self):
     input = w_self._value
-    buffer = [' '] * len(input)
+    builder = StringBuilder(len(input))
     prev_letter=' '
 
-    for pos in range(0, len(input)):
+    for pos in range(len(input)):
         ch = input[pos]
         if not prev_letter.isalpha():
-            buffer[pos] = _upper(ch)
+            ch = _upper(ch)
+            builder.append(ch)
         else:
-            buffer[pos] = _lower(ch)
+            ch = _lower(ch)
+            builder.append(ch)
 
-        prev_letter = buffer[pos]
+        prev_letter = ch
 
-    return space.wrap("".join(buffer))
+    return space.wrap(builder.build())
 
 def str_split__String_None_ANY(space, w_self, w_none, w_maxsplit=-1):
     maxsplit = space.int_w(w_maxsplit)
@@ -754,27 +756,21 @@
     input = w_self._value
     width = space.int_w(w_width)
 
-    if len(input) >= width:
+    num_zeros = width - len(input)
+    if num_zeros <= 0:
         # cannot return w_self, in case it is a subclass of str
         return space.wrap(input)
 
-    buf = [' '] * width
+    builder = StringBuilder(width)
     if len(input) > 0 and (input[0] == '+' or input[0] == '-'):
-        buf[0] = input[0]
+        builder.append(input[0])
         start = 1
-        middle = width - len(input) + 1
     else:
         start = 0
-        middle = width - len(input)
 
-    for i in range(start, middle):
-        buf[i] = '0'
-
-    for i in range(middle, width):
-        buf[i] = input[start]
-        start = start + 1
-
-    return space.wrap("".join(buf))
+    builder.append_multiple_char('0', num_zeros)
+    builder.append_slice(input, start, len(input))
+    return space.wrap(builder.build())
 
 
 def hash__String(space, w_str):
diff --git a/pypy/objspace/std/strutil.py b/pypy/objspace/std/strutil.py
--- a/pypy/objspace/std/strutil.py
+++ b/pypy/objspace/std/strutil.py
@@ -35,7 +35,7 @@
 
     def error(self):
         raise ParseStringError("invalid literal for %s() with base %d: '%s'" %
-                               (self.fname, self.base, self.literal))
+                               (self.fname, self.original_base, self.literal))
 
     def __init__(self, s, literal, base, fname):
         self.literal = literal
@@ -47,7 +47,8 @@
         elif s.startswith('+'):
             s = strip_spaces(s[1:])
         self.sign = sign
-        
+        self.original_base = base
+
         if base == 0:
             if s.startswith('0x') or s.startswith('0X'):
                 base = 16
diff --git a/pypy/objspace/std/test/test_strutil.py b/pypy/objspace/std/test/test_strutil.py
--- a/pypy/objspace/std/test/test_strutil.py
+++ b/pypy/objspace/std/test/test_strutil.py
@@ -89,6 +89,8 @@
 
         exc = raises(ParseStringError, string_to_int, '')
         assert exc.value.msg == "invalid literal for int() with base 10: ''"
+        exc = raises(ParseStringError, string_to_int, '', 0)
+        assert exc.value.msg == "invalid literal for int() with base 0: ''"
 
     def test_string_to_int_overflow(self):
         import sys
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -10,7 +10,8 @@
 from pypy.objspace.std import identitydict
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash
-from pypy.rlib.jit import promote, elidable_promote, we_are_jitted
+from pypy.rlib.jit import promote, elidable_promote, we_are_jitted,\
+     promote_string
 from pypy.rlib.jit import elidable, dont_look_inside, unroll_safe
 from pypy.rlib.rarithmetic import intmask, r_uint
 
@@ -101,6 +102,7 @@
                           'instancetypedef',
                           'terminator',
                           '_version_tag?',
+                          'interplevel_cls',
                           ]
 
     # for config.objspace.std.getattributeshortcut
@@ -399,6 +401,7 @@
         if version_tag is None:
             tup = w_self._lookup_where(name)
             return tup
+        name = promote_string(name)
         w_class, w_value = w_self._pure_lookup_where_with_method_cache(name, version_tag)
         return w_class, unwrap_cell(space, w_value)
 
diff --git a/pypy/objspace/std/unicodeobject.py b/pypy/objspace/std/unicodeobject.py
--- a/pypy/objspace/std/unicodeobject.py
+++ b/pypy/objspace/std/unicodeobject.py
@@ -417,54 +417,54 @@
     input = w_self._value
     if len(input) == 0:
         return W_UnicodeObject.EMPTY
-    result = [u'\0'] * len(input)
-    result[0] = unichr(unicodedb.toupper(ord(input[0])))
+    builder = UnicodeBuilder(len(input))
+    builder.append(unichr(unicodedb.toupper(ord(input[0]))))
     for i in range(1, len(input)):
-        result[i] = unichr(unicodedb.tolower(ord(input[i])))
-    return W_UnicodeObject(u''.join(result))
+        builder.append(unichr(unicodedb.tolower(ord(input[i]))))
+    return W_UnicodeObject(builder.build())
 
 def unicode_title__Unicode(space, w_self):
     input = w_self._value
     if len(input) == 0:
         return w_self
-    result = [u'\0'] * len(input)
+    builder = UnicodeBuilder(len(input))
 
     previous_is_cased = False
     for i in range(len(input)):
         unichar = ord(input[i])
         if previous_is_cased:
-            result[i] = unichr(unicodedb.tolower(unichar))
+            builder.append(unichr(unicodedb.tolower(unichar)))
         else:
-            result[i] = unichr(unicodedb.totitle(unichar))
+            builder.append(unichr(unicodedb.totitle(unichar)))
         previous_is_cased = unicodedb.iscased(unichar)
-    return W_UnicodeObject(u''.join(result))
+    return W_UnicodeObject(builder.build())
 
 def unicode_lower__Unicode(space, w_self):
     input = w_self._value
-    result = [u'\0'] * len(input)
+    builder = UnicodeBuilder(len(input))
     for i in range(len(input)):
-        result[i] = unichr(unicodedb.tolower(ord(input[i])))
-    return W_UnicodeObject(u''.join(result))
+        builder.append(unichr(unicodedb.tolower(ord(input[i]))))
+    return W_UnicodeObject(builder.build())
 
 def unicode_upper__Unicode(space, w_self):
     input = w_self._value
-    result = [u'\0'] * len(input)
+    builder = UnicodeBuilder(len(input))
     for i in range(len(input)):
-        result[i] = unichr(unicodedb.toupper(ord(input[i])))
-    return W_UnicodeObject(u''.join(result))
+        builder.append(unichr(unicodedb.toupper(ord(input[i]))))
+    return W_UnicodeObject(builder.build())
 
 def unicode_swapcase__Unicode(space, w_self):
     input = w_self._value
-    result = [u'\0'] * len(input)
+    builder = UnicodeBuilder(len(input))
     for i in range(len(input)):
         unichar = ord(input[i])
         if unicodedb.islower(unichar):
-            result[i] = unichr(unicodedb.toupper(unichar))
+            builder.append(unichr(unicodedb.toupper(unichar)))
         elif unicodedb.isupper(unichar):
-            result[i] = unichr(unicodedb.tolower(unichar))
+            builder.append(unichr(unicodedb.tolower(unichar)))
         else:
-            result[i] = input[i]
-    return W_UnicodeObject(u''.join(result))
+            builder.append(input[i])
+    return W_UnicodeObject(builder.build())
 
 def _normalize_index(length, index):
     if index < 0:
diff --git a/pypy/objspace/taint.py b/pypy/objspace/taint.py
deleted file mode 100644
--- a/pypy/objspace/taint.py
+++ /dev/null
@@ -1,294 +0,0 @@
-"""
-Just an experiment.
-"""
-import os
-from pypy.objspace.std.objspace import StdObjSpace
-from pypy.objspace.proxy import patch_space_in_place
-from pypy.objspace.thunk import nb_forcing_args
-from pypy.interpreter.error import OperationError
-from pypy.interpreter import baseobjspace, gateway, executioncontext
-from pypy.interpreter.function import Method
-from pypy.interpreter.pyframe import PyFrame
-from pypy.tool.sourcetools import func_with_new_name
-from pypy.rlib.unroll import unrolling_iterable
-
-
-class W_Tainted(baseobjspace.W_Root):
-    def __init__(self, w_obj):
-        self.w_obj = w_obj
-
-##    def getdict(self, space):
-##        return taint(self.w_obj.getdict(space))
-
-##    def getdictvalue(self, space, attr):
-##        return taint(self.w_obj.getdictvalue(space, attr))
-
-##    def setdictvalue(self, space, attr, w_value):
-##        return self.w_obj.setdictvalue(space, attr, w_value)
-
-##    ...
-
-class W_TaintBomb(baseobjspace.W_Root):
-    filename = '?'
-    codename = '?'
-    codeline = 0
-
-    def __init__(self, space, operr):
-        self.space = space
-        self.operr = operr
-        self.record_debug_info()
-
-    def record_debug_info(self):
-        ec = self.space.getexecutioncontext()
-        frame = ec.gettopframe_nohidden()
-        if isinstance(frame, PyFrame):     # and, in particular, frame != None
-            self.filename = frame.pycode.co_filename
-            self.codename = frame.pycode.co_name
-            self.codeline = frame.get_last_lineno()
-        if get_debug_level(self.space) > 0:
-            self.debug_dump()
-
-    def debug_dump(self):
-        os.write(2, 'Taint Bomb from file "%s", line %d, in %s\n    %s\n' % (
-            self.filename, self.codeline, self.codename,
-            self.operr.errorstr(self.space)))
-
-    def explode(self):
-        #msg = self.operr.errorstr(space)
-        raise OperationError(self.space.w_TaintError, self.space.w_None)
-
-
-def taint(w_obj):
-    """Return a tainted version of the argument."""
-    if w_obj is None or isinstance(w_obj, W_Tainted):
-        return w_obj
-    else:
-        return W_Tainted(w_obj)
-app_taint = gateway.interp2app(taint)
-
-def is_tainted(space, w_obj):
-    """Return whether the argument is tainted."""
-    res = isinstance(w_obj, W_Tainted) or isinstance(w_obj, W_TaintBomb)
-    return space.wrap(res)
-app_is_tainted = gateway.interp2app(is_tainted)
-
-def untaint(space, w_expectedtype, w_obj):
-    """untaint(expectedtype, tainted_obj) -> obj
-Untaint untainted_obj and return it. If the result is not of expectedtype,
-raise a type error."""
-    if (isinstance(w_expectedtype, W_Tainted) or
-        isinstance(w_expectedtype, W_TaintBomb)):
-        raise OperationError(space.w_TypeError,
-                  space.wrap("untaint() arg 1 must be an untainted type"))
-    if not space.is_true(space.isinstance(w_expectedtype, space.w_type)):
-        raise OperationError(space.w_TypeError,
-                             space.wrap("untaint() arg 1 must be a type"))
-    if isinstance(w_obj, W_Tainted):
-        w_obj = w_obj.w_obj
-    elif isinstance(w_obj, W_TaintBomb):
-        w_obj.explode()
-    #if isinstance(w_expectedtype, W_Tainted):
-    #    w_expectedtype = w_expectedtype.w_obj
-    w_realtype = space.type(w_obj)
-    if not space.is_w(w_realtype, w_expectedtype):
-        #msg = "expected an object of type '%s'" % (
-        #    w_expectedtype.getname(space),)
-        #    #w_realtype.getname(space))
-        raise OperationError(space.w_TaintError, space.w_None)
-    return w_obj
-app_untaint = gateway.interp2app(untaint)
-
-# ____________________________________________________________
-
- at gateway.unwrap_spec(args_w='args_w')
-def taint_atomic_function(space, w_func, args_w):
-    newargs_w = []
-    tainted = False
-    for w_arg in args_w:
-        if isinstance(w_arg, W_Tainted):
-            tainted = True
-            w_arg = w_arg.w_obj
-        elif isinstance(w_arg, W_TaintBomb):
-            return w_arg
-        newargs_w.append(w_arg)
-    w_newargs = space.newtuple(newargs_w)
-    try:
-        w_res = space.call(w_func, w_newargs)
-    except OperationError, operr:
-        if not tainted:
-            raise
-        return W_TaintBomb(space, operr)
-    if tainted:
-        w_res = taint(w_res)
-    return w_res
-
-app_taint_atomic_function = gateway.interp2app(taint_atomic_function)
-
-def taint_atomic(space, w_callable):
-    """decorator to make a callable "taint-atomic": if the function is called
-with tainted arguments, those are untainted. The result of the function is
-tainted again.  All exceptions that the callable raises are turned into
-taint bombs."""
-    meth = Method(space, space.w_fn_taint_atomic_function,
-                  w_callable, space.type(w_callable))
-    return space.wrap(meth)
-app_taint_atomic = gateway.interp2app(taint_atomic)
-
-# ____________________________________________________________
-
-executioncontext.ExecutionContext.taint_debug = 0
-
- at gateway.unwrap_spec(level=int)
-def taint_debug(space, level):
-    """Set the debug level. If the debug level is greater than 0, the creation
-of taint bombs will print debug information. For debugging purposes
-only!"""
-    space.getexecutioncontext().taint_debug = level
-app_taint_debug = gateway.interp2app(taint_debug)
-
-def taint_look(space, w_obj):
-    """Print some info about the taintedness of an object. For debugging
-purposes only!"""
-    if isinstance(w_obj, W_Tainted):
-        info = space.type(w_obj.w_obj).getname(space)
-        msg = space.str_w(w_obj.w_obj.getrepr(space, info))
-        msg = 'Taint Box %s\n' % msg
-        os.write(2, msg)
-    elif isinstance(w_obj, W_TaintBomb):
-        w_obj.debug_dump()
-    else:
-        os.write(2, 'not tainted\n')
-app_taint_look = gateway.interp2app(taint_look)
-
-def get_debug_level(space):
-    return space.getexecutioncontext().taint_debug
-
-def debug_bomb(space, operr):
-    ec = space.getexecutioncontext()
-    filename = '?'
-    codename = '?'
-    codeline = 0
-    frame = ec.gettopframe_nohidden()
-    if isinstance(frame, PyFrame):     # and, in particular, frame != None
-        filename = frame.pycode.co_filename
-        codename = frame.pycode.co_name
-        codeline = frame.get_last_lineno()
-    os.write(2, 'Taint Bomb in file "%s", line %d, in %s\n    %s\n' % (
-        filename, codeline, codename, operr.errorstr(space)))
-
-# ____________________________________________________________
-
-
-class TaintSpace(StdObjSpace):
-
-    def __init__(self, *args, **kwds):
-        StdObjSpace.__init__(self, *args, **kwds)
-        w_dict = self.newdict()
-        self.setitem(w_dict, self.wrap("__doc__"), self.wrap("""\
-Exception that is raised when an operation revealing information on a tainted
-object is performed."""))
-        self.w_TaintError = self.call_function(
-            self.w_type,
-            self.wrap("TaintError"),
-            self.newtuple([self.w_Exception]),
-            w_dict
-            )
-        w___pypy__ = self.getbuiltinmodule("__pypy__")
-        self.setattr(w___pypy__, self.wrap('taint'),
-                     self.wrap(app_taint))
-        self.setattr(w___pypy__, self.wrap('is_tainted'),
-                     self.wrap(app_is_tainted))
-        self.setattr(w___pypy__, self.wrap('untaint'),
-                     self.wrap(app_untaint))
-        self.w_fn_taint_atomic_function = self.wrap(app_taint_atomic_function)
-        self.setattr(w___pypy__, self.wrap('taint_atomic'),
-                     self.wrap(app_taint_atomic))
-        self.setattr(w___pypy__, self.wrap('TaintError'),
-                     self.w_TaintError)
-        self.setattr(w___pypy__, self.wrap('_taint_debug'),
-                     self.wrap(app_taint_debug))
-        self.setattr(w___pypy__, self.wrap('_taint_look'),
-                     self.wrap(app_taint_look))
-        patch_space_in_place(self, 'taint', proxymaker)
-
-        # XXX may leak info, perfomance hit, what about taint bombs?
-        from pypy.objspace.std.typeobject import W_TypeObject
-
-        def taint_lookup(w_obj, name):
-            if isinstance(w_obj, W_Tainted):
-                w_obj = w_obj.w_obj
-            w_type = self.type(w_obj)
-            assert isinstance(w_type, W_TypeObject)
-            return w_type.lookup(name)
-
-        def taint_lookup_in_type_where(w_obj, name):
-            if isinstance(w_obj, W_Tainted):
-                w_type = w_obj.w_obj
-            else:
-                w_type = w_obj
-            assert isinstance(w_type, W_TypeObject)
-            return w_type.lookup_where(name)
-
-        self.lookup = taint_lookup
-        self.lookup_in_type_where = taint_lookup_in_type_where
-
-
-Space = TaintSpace
-
-
-def tainted_error(space, name):
-    #msg = "operation '%s' forbidden on tainted object" % (name,)
-    raise OperationError(space.w_TaintError, space.w_None)# space.wrap(msg))
-
-
-RegularMethods = dict.fromkeys(
-    [name for name, _, _, _ in baseobjspace.ObjSpace.MethodTable])
-
-TaintResultIrregularMethods = dict.fromkeys(
-    ['wrap', 'call_args'] +
-    [name for name in baseobjspace.ObjSpace.IrregularOpTable
-          if name.startswith('new')])
-
-def proxymaker(space, name, parentfn):
-    arity = nb_forcing_args[name]
-    indices = unrolling_iterable(range(arity))
-    if name in RegularMethods:
-
-        def proxy(*args_w):
-            newargs_w = ()
-            tainted = False
-            for i in indices:
-                w_arg = args_w[i]
-                if isinstance(w_arg, W_Tainted):
-                    tainted = True
-                    w_arg = w_arg.w_obj
-                elif isinstance(w_arg, W_TaintBomb):
-                    return w_arg
-                newargs_w += (w_arg,)
-            newargs_w += args_w[arity:]
-            try:
-                w_res = parentfn(*newargs_w)
-            except OperationError, operr:
-                if not tainted:
-                    raise
-                return W_TaintBomb(space, operr)
-            if tainted:
-                w_res = taint(w_res)
-            return w_res
-
-    elif arity == 0:
-        return None
-
-    else:
-
-        def proxy(*args_w):
-            for i in indices:
-                w_arg = args_w[i]
-                if isinstance(w_arg, W_Tainted):
-                    tainted_error(space, name)
-                elif isinstance(w_arg, W_TaintBomb):
-                    w_arg.explode()
-            return parentfn(*args_w)
-
-    proxy = func_with_new_name(proxy, '%s_proxy' % name)
-    return proxy
diff --git a/pypy/objspace/test/test_taintobjspace.py b/pypy/objspace/test/test_taintobjspace.py
deleted file mode 100644
--- a/pypy/objspace/test/test_taintobjspace.py
+++ /dev/null
@@ -1,77 +0,0 @@
-from pypy.conftest import gettestobjspace
-
-class AppTest_Taint:
-
-    def setup_class(cls):
-        cls.space = gettestobjspace('taint')
-
-    def test_simple(self):
-        from __pypy__ import taint, untaint, TaintError
-        x = taint(6)
-        x = x * 7
-        raises(TaintError, "if x: y = 1")
-        t = type(x)
-        raises(TaintError, "if t is int: y = 1")
-        assert untaint(int, x) == 42
-        raises(TaintError, "untaint(float, x)")
-
-    def test_bomb(self):
-        from __pypy__ import taint, untaint, TaintError
-        x = taint(6)
-        x = x / 0
-        raises(TaintError, "if x: y = 1")
-        t = type(x)
-        raises(TaintError, "if t is int: y = 1")
-        raises(TaintError, "untaint(int, x)")
-        raises(TaintError, "untaint(float, x)")
-
-    def test_taint_atomic(self):
-        from __pypy__ import taint, untaint, TaintError, taint_atomic
-        x = taint(6)
-        x *= 7
-
-        def dummy(x):
-            if x > 40:
-                return 5
-            else:
-                return 3
-        dummy = taint_atomic(dummy)
-
-        y = dummy(x)
-        raises(TaintError, "if y == 3: z = 1")
-        assert untaint(int, y) == 5
-
-    def test_taint_atomic_exception(self):
-        from __pypy__ import taint, untaint, TaintError, taint_atomic
-        x = taint(6)
-        x *= 7
-
-        def dummy(x):
-            if x + "world" == "hello world":
-                return 5
-            else:
-                return 3
-        dummy = taint_atomic(dummy)
-
-        y = dummy(x)
-        raises(TaintError, "if y == 3: z = 1")
-        raises(TaintError, "untaint(int, y)")
-
-    def test_taint_atomic_incoming_bomb(self):
-        from __pypy__ import taint, untaint, TaintError, taint_atomic
-        x = taint(6)
-        x /= 0
-        lst = []
-
-        def dummy(x):
-            lst.append("running!")
-            if x > 40:
-                return 5
-            else:
-                return 3
-        dummy = taint_atomic(dummy)
-
-        y = dummy(x)
-        raises(TaintError, "if y == 3: z = 1")
-        assert lst == []
-        raises(TaintError, "untaint(int, y)")
diff --git a/pypy/rlib/_jit_vref.py b/pypy/rlib/_jit_vref.py
--- a/pypy/rlib/_jit_vref.py
+++ b/pypy/rlib/_jit_vref.py
@@ -25,6 +25,10 @@
     def simple_call(self):
         return self.s_instance
 
+    def getattr(self, s_attr):
+        assert s_attr.const == 'virtual'
+        return annmodel.s_Bool
+
     def rtyper_makerepr(self, rtyper):
         if rtyper.type_system.name == 'lltypesystem':
             return vrefrepr
@@ -61,6 +65,13 @@
                              " prebuilt virtual_ref")
         return lltype.nullptr(OBJECTPTR.TO)
 
+    def rtype_getattr(self, hop):
+        s_attr = hop.args_s[1]
+        assert s_attr.const == 'virtual'
+        v = hop.inputarg(self, arg=0)
+        hop.exception_cannot_occur()
+        return hop.genop('jit_is_virtual', [v], resulttype = lltype.Bool)
+
 from pypy.rpython.ootypesystem.rclass import OBJECT
 
 class OOVRefRepr(VRefRepr):
diff --git a/pypy/rlib/_rsocket_rffi.py b/pypy/rlib/_rsocket_rffi.py
--- a/pypy/rlib/_rsocket_rffi.py
+++ b/pypy/rlib/_rsocket_rffi.py
@@ -16,6 +16,7 @@
 _MINGW = target_platform.name == "mingw32"
 _SOLARIS = sys.platform == "sunos5"
 _MACOSX = sys.platform == "darwin"
+_HAS_AF_PACKET = sys.platform.startswith('linux')   # only Linux for now
 
 if _POSIX:
     includes = ('sys/types.h',
@@ -34,11 +35,12 @@
                 'stdint.h', 
                 'errno.h',
                 )
+    if _HAS_AF_PACKET:
+        includes += ('netpacket/packet.h',
+                     'sys/ioctl.h',
+                     'net/if.h')
 
-    cond_includes = [('AF_NETLINK', 'linux/netlink.h'),
-                     ('AF_PACKET', 'netpacket/packet.h'),
-                     ('AF_PACKET', 'sys/ioctl.h'),
-                     ('AF_PACKET', 'net/if.h')]
+    cond_includes = [('AF_NETLINK', 'linux/netlink.h')]
     
     libraries = ()
     calling_conv = 'c'
@@ -320,18 +322,18 @@
                                              ('events', rffi.SHORT),
                                              ('revents', rffi.SHORT)])
 
-    CConfig.sockaddr_ll = platform.Struct('struct sockaddr_ll',
+    if _HAS_AF_PACKET:
+        CConfig.sockaddr_ll = platform.Struct('struct sockaddr_ll',
                               [('sll_ifindex', rffi.INT),
                                ('sll_protocol', rffi.INT),
                                ('sll_pkttype', rffi.INT),
                                ('sll_hatype', rffi.INT),
                                ('sll_addr', rffi.CFixedArray(rffi.CHAR, 8)),
-                               ('sll_halen', rffi.INT)],
-                              ifdef='AF_PACKET')
+                               ('sll_halen', rffi.INT)])
 
-    CConfig.ifreq = platform.Struct('struct ifreq', [('ifr_ifindex', rffi.INT),
-                                 ('ifr_name', rffi.CFixedArray(rffi.CHAR, 8))],
-                                    ifdef='AF_PACKET')
+        CConfig.ifreq = platform.Struct('struct ifreq',
+                                [('ifr_ifindex', rffi.INT),
+                                 ('ifr_name', rffi.CFixedArray(rffi.CHAR, 8))])
 
 if _WIN32:
     CConfig.WSAEVENT = platform.SimpleType('WSAEVENT', rffi.VOIDP)
@@ -386,6 +388,8 @@
         constants[name] = value
     else:
         constants[name] = default
+if not _HAS_AF_PACKET and 'AF_PACKET' in constants:
+    del constants['AF_PACKET']
 
 constants['has_ipv6'] = True # This is a configuration option in CPython
 for name, value in constants.items():
@@ -439,21 +443,14 @@
 if _POSIX:
     nfds_t = cConfig.nfds_t
     pollfd = cConfig.pollfd
-    if cConfig.sockaddr_ll is not None:
+    if _HAS_AF_PACKET:
         sockaddr_ll = cConfig.sockaddr_ll
-    ifreq = cConfig.ifreq
+        ifreq = cConfig.ifreq
 if WIN32:
     WSAEVENT = cConfig.WSAEVENT
     WSANETWORKEVENTS = cConfig.WSANETWORKEVENTS
 timeval = cConfig.timeval
 
-#if _POSIX:
-#    includes = list(includes)
-#    for _name, _header in cond_includes:
-#        if getattr(cConfig, _name) is not None:
-#            includes.append(_header)
-#    eci = ExternalCompilationInfo(includes=includes, libraries=libraries,
-#                                  separate_module_sources=sources)
 
 def external(name, args, result, **kwds):
     return rffi.llexternal(name, args, result, compilation_info=eci,
@@ -544,7 +541,7 @@
     socketpair_t = rffi.CArray(socketfd_type)
     socketpair = external('socketpair', [rffi.INT, rffi.INT, rffi.INT,
                           lltype.Ptr(socketpair_t)], rffi.INT)
-    if ifreq is not None:
+    if _HAS_AF_PACKET:
         ioctl = external('ioctl', [socketfd_type, rffi.INT, lltype.Ptr(ifreq)],
                          rffi.INT)
 
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -8,6 +8,8 @@
 from pypy.rpython.extregistry import ExtRegistryEntry
 from pypy.tool.sourcetools import func_with_new_name
 
+DEBUG_ELIDABLE_FUNCTIONS = False
+
 
 def elidable(func):
     """ Decorate a function as "trace-elidable". This means precisely that:
@@ -24,6 +26,18 @@
     If a particular call to this function ends up raising an exception, then it
     is handled like a normal function call (this decorator is ignored).
     """
+    if DEBUG_ELIDABLE_FUNCTIONS:
+        cache = {}
+        oldfunc = func
+        def func(*args):
+            result = oldfunc(*args)    # if it raises, no caching
+            try:
+                oldresult = cache.setdefault(args, result)
+            except TypeError:
+                pass           # unhashable args
+            else:
+                assert oldresult == result
+            return result
     func._elidable_function_ = True
     return func
 
@@ -38,6 +52,7 @@
     possible arguments are:
 
     * promote - promote the argument from a variable into a constant
+    * promote_string - same, but promote string by *value*
     * access_directly - directly access a virtualizable, as a structure
                         and don't treat it as a virtualizable
     * fresh_virtualizable - means that virtualizable was just allocated.
@@ -51,6 +66,9 @@
 def promote(x):
     return hint(x, promote=True)
 
+def promote_string(x):
+    return hint(x, promote_string=True)
+
 def dont_look_inside(func):
     """ Make sure the JIT does not trace inside decorated function
     (it becomes a call instead)
@@ -313,6 +331,12 @@
             raise InvalidVirtualRef
         return self._x
 
+    @property
+    def virtual(self):
+        """A property that is True if the vref contains a virtual that would
+        be forced by the '()' operator."""
+        return self._state == 'non-forced'
+
     def _finish(self):
         if self._state == 'non-forced':
             self._state = 'invalid'
diff --git a/pypy/rlib/rerased.py b/pypy/rlib/rerased.py
--- a/pypy/rlib/rerased.py
+++ b/pypy/rlib/rerased.py
@@ -135,6 +135,8 @@
     _about_ = erase_int
 
     def compute_result_annotation(self, s_obj):
+        config = self.bookkeeper.annotator.translator.config
+        assert config.translation.taggedpointers, "need to enable tagged pointers to use erase_int"
         assert annmodel.SomeInteger().contains(s_obj)
         return SomeErased()
 
@@ -218,18 +220,18 @@
         [v_value] = hop.inputargs(lltype.Signed)
         c_one = hop.inputconst(lltype.Signed, 1)
         hop.exception_is_here()
-        v2 = hop.genop('int_lshift_ovf', [v_value, c_one],
+        v2 = hop.genop('int_add_ovf', [v_value, v_value],
                        resulttype = lltype.Signed)
         v2p1 = hop.genop('int_add', [v2, c_one],
                          resulttype = lltype.Signed)
         v_instance = hop.genop('cast_int_to_ptr', [v2p1],
                                resulttype=self.lowleveltype)
-        v = hop.genop('cast_opaque_ptr', [v_instance],
-                      resulttype=self.lowleveltype)
-        return v
+        return v_instance
 
     def convert_const(self, value):
         if value._identity is _identity_for_ints:
+            config = self.rtyper.annotator.translator.config
+            assert config.translation.taggedpointers, "need to enable tagged pointers to use erase_int"
             return lltype.cast_int_to_ptr(self.lowleveltype, value._x * 2 + 1)
         bk = self.rtyper.annotator.bookkeeper
         s_obj = value._identity.get_input_annotation(bk)
@@ -266,10 +268,10 @@
         return hop.genop('int_rshift', [v2, c_one], resulttype=lltype.Signed)
 
     def rtype_erase_int(self, hop):
-        hop.exception_is_here()
         [v_value] = hop.inputargs(lltype.Signed)
         c_one = hop.inputconst(lltype.Signed, 1)
-        v2 = hop.genop('int_lshift_ovf', [v_value, c_one],
+        hop.exception_is_here()
+        v2 = hop.genop('int_add_ovf', [v_value, v_value],
                        resulttype = lltype.Signed)
         v2p1 = hop.genop('int_add', [v2, c_one],
                          resulttype = lltype.Signed)
diff --git a/pypy/rlib/rsocket.py b/pypy/rlib/rsocket.py
--- a/pypy/rlib/rsocket.py
+++ b/pypy/rlib/rsocket.py
@@ -8,6 +8,7 @@
 # Known missing features:
 #
 #   - address families other than AF_INET, AF_INET6, AF_UNIX, AF_PACKET
+#   - AF_PACKET is only supported on Linux
 #   - methods makefile(),
 #   - SSL
 #
diff --git a/pypy/rlib/test/test__jit_vref.py b/pypy/rlib/test/test__jit_vref.py
--- a/pypy/rlib/test/test__jit_vref.py
+++ b/pypy/rlib/test/test__jit_vref.py
@@ -27,10 +27,13 @@
     x1 = X()
     vref = virtual_ref(x1)
     assert vref._state == 'non-forced'
+    assert vref.virtual is True
     assert vref() is x1
     assert vref._state == 'forced'
+    assert vref.virtual is False
     virtual_ref_finish(vref, x1)
     assert vref._state == 'forced'
+    assert vref.virtual is False
     assert vref() is x1
 
 def test_direct_invalid():
@@ -135,6 +138,13 @@
         x = self.interpret(f, [])
         assert x == 42
 
+    def test_rtype_virtualattr(self):
+        def f():
+            vref = virtual_ref(X())
+            return vref.virtual
+        x = self.interpret(f, [])
+        assert x is False
+
 
 class TestLLtype(BaseTestVRef, LLRtypeMixin):
     OBJECTTYPE = OBJECTPTR
diff --git a/pypy/rlib/test/test_jit.py b/pypy/rlib/test/test_jit.py
--- a/pypy/rlib/test/test_jit.py
+++ b/pypy/rlib/test/test_jit.py
@@ -139,12 +139,11 @@
 
     def test_isconstant(self):
         def f(n):
-            assert n >= 0
             assert isconstant(n) is False
             l = []
             l.append(n)
             return len(l)
-        res = self.interpret(f, [234])
+        res = self.interpret(f, [-234])
         assert res == 1
 
 
diff --git a/pypy/rlib/test/test_rerased.py b/pypy/rlib/test/test_rerased.py
--- a/pypy/rlib/test/test_rerased.py
+++ b/pypy/rlib/test/test_rerased.py
@@ -10,6 +10,13 @@
 
 from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
 
+def make_annotator():
+    a = RPythonAnnotator()
+    a.translator.config.translation.taggedpointers = True
+    return a
+
+
+
 class X(object):
     pass
 
@@ -55,7 +62,7 @@
 def test_annotate_1():
     def f():
         return eraseX(X())
-    a = RPythonAnnotator()
+    a = make_annotator()
     s = a.build_types(f, [])
     assert isinstance(s, SomeErased)
 
@@ -66,7 +73,7 @@
         #assert not is_integer(e)
         x2 = uneraseX(e)
         return x2
-    a = RPythonAnnotator()
+    a = make_annotator()
     s = a.build_types(f, [])
     assert isinstance(s, annmodel.SomeInstance)
     assert s.classdef == a.bookkeeper.getuniqueclassdef(X)
@@ -77,7 +84,7 @@
         #assert is_integer(e)
         x2 = unerase_int(e)
         return x2
-    a = RPythonAnnotator()
+    a = make_annotator()
     s = a.build_types(f, [])
     assert isinstance(s, annmodel.SomeInteger)
 
@@ -105,7 +112,7 @@
         x = make(n)
         return check(x, n)
     #
-    a = RPythonAnnotator()
+    a = make_annotator()
     s = a.build_types(f, [int])
     assert isinstance(s, annmodel.SomeInteger)
 
@@ -135,7 +142,7 @@
             else:
                 return inst
     #
-    a = RPythonAnnotator()
+    a = make_annotator()
     s = a.build_types(f, [])
     assert isinstance(s, annmodel.SomeInstance)
     assert s.classdef == a.bookkeeper.getuniqueclassdef(A)
@@ -155,7 +162,7 @@
             e = e2
         return unerase(e)
     #
-    a = RPythonAnnotator()
+    a = make_annotator()
     s = a.build_types(f, [int])
     assert isinstance(s, annmodel.SomeInstance)
     assert s.classdef == a.bookkeeper.getuniqueclassdef(X)
@@ -165,11 +172,14 @@
     e1 = erase_int(42)
     def f(i):
         return unerase_int(e1)
-    a = RPythonAnnotator()
+    a = make_annotator()
     s = a.build_types(f, [int])
     assert isinstance(s, annmodel.SomeInteger)
 
 class BaseTestRErased(BaseRtypingTest):
+    def interpret(self, *args, **kwargs):
+        kwargs["taggedpointers"] = True
+        return BaseRtypingTest.interpret(self, *args, **kwargs)
     def test_rtype_1(self):
         def f():
             return eraseX(X())
diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -15,12 +15,11 @@
     load_library_kwargs = {}
 
 import os
-from pypy import conftest
 from pypy.rpython.lltypesystem import lltype, llmemory
 from pypy.rpython.extfunc import ExtRegistryEntry
 from pypy.rlib.objectmodel import Symbolic, ComputedIntSymbolic
 from pypy.tool.uid import fixid
-from pypy.rlib.rarithmetic import r_uint, r_singlefloat, r_longfloat, base_int, intmask
+from pypy.rlib.rarithmetic import r_singlefloat, r_longfloat, base_int, intmask
 from pypy.annotation import model as annmodel
 from pypy.rpython.llinterp import LLInterpreter, LLException
 from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
@@ -531,6 +530,10 @@
     def __str__(self):
         return repr(self)
 
+    def _setparentstructure(self, parent, parentindex):
+        super(_parentable_mixin, self)._setparentstructure(parent, parentindex)
+        self._keepparent = parent   # always keep a strong ref
+
 class _struct_mixin(_parentable_mixin):
     """Mixin added to _struct containers when they become ctypes-based."""
     __slots__ = ()
@@ -566,7 +569,10 @@
         return 0, sys.maxint
 
     def getitem(self, index, uninitialized_ok=False):
-        return self._storage.contents._getitem(index, boundscheck=False)
+        res = self._storage.contents._getitem(index, boundscheck=False)
+        if isinstance(self._TYPE.OF, lltype.ContainerType):
+            res._obj._setparentstructure(self, index)
+        return res
 
     def setitem(self, index, value):
         self._storage.contents._setitem(index, value, boundscheck=False)
@@ -658,6 +664,8 @@
         if T == llmemory.GCREF:
             if isinstance(llobj._obj, _llgcopaque):
                 return ctypes.c_void_p(llobj._obj.intval)
+            if isinstance(llobj._obj, int):    # tagged pointer
+                return ctypes.c_void_p(llobj._obj)
             container = llobj._obj.container
             T = lltype.Ptr(lltype.typeOf(container))
             # otherwise it came from integer and we want a c_void_p with
@@ -1271,6 +1279,7 @@
 class _llgcopaque(lltype._container):
     _TYPE = llmemory.GCREF.TO
     _name = "_llgcopaque"
+    _read_directly_intval = True     # for _ptr._cast_to_int()
 
     def __init__(self, void_p):
         if isinstance(void_p, (int, long)):
@@ -1279,6 +1288,8 @@
             self.intval = intmask(void_p.value)
 
     def __eq__(self, other):
+        if not other:
+            return self.intval == 0
         if isinstance(other, _llgcopaque):
             return self.intval == other.intval
         storage = object()
@@ -1302,11 +1313,6 @@
             return _opaque_objs[self.intval // 2]
         return force_cast(PTRTYPE, self.intval)
 
-##     def _cast_to_int(self):
-##         return self.intval
-
-##     def _cast_to_adr(self):
-##         return _lladdress(self.intval)
 
 def cast_adr_to_int(addr):
     if isinstance(addr, llmemory.fakeaddress):
diff --git a/pypy/rpython/lltypesystem/llmemory.py b/pypy/rpython/lltypesystem/llmemory.py
--- a/pypy/rpython/lltypesystem/llmemory.py
+++ b/pypy/rpython/lltypesystem/llmemory.py
@@ -498,6 +498,8 @@
 
     def _cast_to_int(self, symbolic=False):
         if self:
+            if isinstance(self.ptr._obj0, int):    # tagged integer
+                return self.ptr._obj0
             if symbolic:
                 return AddressAsInt(self)
             else:
diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py
--- a/pypy/rpython/lltypesystem/lloperation.py
+++ b/pypy/rpython/lltypesystem/lloperation.py
@@ -428,6 +428,7 @@
     'jit_marker':           LLOp(),
     'jit_force_virtualizable':LLOp(canrun=True),
     'jit_force_virtual':    LLOp(canrun=True),
+    'jit_is_virtual':       LLOp(canrun=True),
     'jit_force_quasi_immutable': LLOp(canrun=True),
     'get_exception_addr':   LLOp(),
     'get_exc_value_addr':   LLOp(),
diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py
--- a/pypy/rpython/lltypesystem/lltype.py
+++ b/pypy/rpython/lltypesystem/lltype.py
@@ -1360,6 +1360,8 @@
         obj = normalizeptr(self, check)._getobj(check)
         if isinstance(obj, int):
             return obj     # special case for cast_int_to_ptr() results put into opaques
+        if getattr(obj, '_read_directly_intval', False):
+            return obj.intval   # special case for _llgcopaque
         result = intmask(obj._getid())
         # assume that id() returns an addressish value which is
         # not zero and aligned to at least a multiple of 4
@@ -1520,7 +1522,7 @@
             and parentindex in (self._parent_type._names[0], 0)
             and self._TYPE._gckind == typeOf(parent)._gckind):
             # keep strong reference to parent, we share the same allocation
-            self._keepparent = parent 
+            self._keepparent = parent
 
     def _parentstructure(self, check=True):
         if self._wrparent is not None:
@@ -1728,7 +1730,8 @@
         # Keep the parent array alive, we share the same allocation.
         # Don't do it if we are inside a GC object, though -- it's someone
         # else's job to keep the GC object alive
-        if typeOf(top_container(parent))._gckind == 'raw':
+        if (typeOf(top_container(parent))._gckind == 'raw' or
+            hasattr(top_container(parent)._storage, 'contents')):  # ll2ctypes
             self._keepparent = parent
 
     def __str__(self):
diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py
--- a/pypy/rpython/lltypesystem/opimpl.py
+++ b/pypy/rpython/lltypesystem/opimpl.py
@@ -538,6 +538,9 @@
 def op_jit_force_virtual(x):
     return x
 
+def op_jit_is_virtual(x):
+    return False
+
 def op_jit_force_quasi_immutable(*args):
     pass
 
diff --git a/pypy/rpython/lltypesystem/rbuilder.py b/pypy/rpython/lltypesystem/rbuilder.py
--- a/pypy/rpython/lltypesystem/rbuilder.py
+++ b/pypy/rpython/lltypesystem/rbuilder.py
@@ -29,7 +29,7 @@
         except OverflowError:
             raise MemoryError
         newbuf = mallocfn(new_allocated)
-        copycontentsfn(ll_builder.buf, newbuf, 0, 0, ll_builder.allocated)
+        copycontentsfn(ll_builder.buf, newbuf, 0, 0, ll_builder.used)
         ll_builder.buf = newbuf
         ll_builder.allocated = new_allocated
     return func_with_new_name(stringbuilder_grow, name)
@@ -56,7 +56,7 @@
 class BaseStringBuilderRepr(AbstractStringBuilderRepr):
     def empty(self):
         return nullptr(self.lowleveltype.TO)
-    
+
     @classmethod
     def ll_new(cls, init_size):
         if init_size < 0 or init_size > MAX:
diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py
--- a/pypy/rpython/lltypesystem/rdict.py
+++ b/pypy/rpython/lltypesystem/rdict.py
@@ -1,16 +1,14 @@
 from pypy.tool.pairtype import pairtype
-from pypy.annotation import model as annmodel
 from pypy.objspace.flow.model import Constant
-from pypy.rpython.rdict import AbstractDictRepr, AbstractDictIteratorRepr,\
-     rtype_newdict
+from pypy.rpython.rdict import (AbstractDictRepr, AbstractDictIteratorRepr,
+     rtype_newdict)
 from pypy.rpython.lltypesystem import lltype
+from pypy.rlib import objectmodel, jit
 from pypy.rlib.rarithmetic import r_uint, intmask, LONG_BIT
-from pypy.rlib.objectmodel import hlinvoke
-from pypy.rpython import robject
-from pypy.rlib import objectmodel, jit
 from pypy.rpython import rmodel
 from pypy.rpython.error import TyperError
 
+
 HIGHEST_BIT = intmask(1 << (LONG_BIT - 1))
 MASK = intmask(HIGHEST_BIT - 1)
 
@@ -417,17 +415,16 @@
     ENTRIES = lltype.typeOf(entries).TO
     return ENTRIES.fasthashfn(entries[i].key)
 
- at jit.dont_look_inside
 def ll_get_value(d, i):
     return d.entries[i].value
 
 def ll_keyhash_custom(d, key):
     DICT = lltype.typeOf(d).TO
-    return hlinvoke(DICT.r_rdict_hashfn, d.fnkeyhash, key)
+    return objectmodel.hlinvoke(DICT.r_rdict_hashfn, d.fnkeyhash, key)
 
 def ll_keyeq_custom(d, key1, key2):
     DICT = lltype.typeOf(d).TO
-    return hlinvoke(DICT.r_rdict_eqfn, d.fnkeyeq, key1, key2)
+    return objectmodel.hlinvoke(DICT.r_rdict_eqfn, d.fnkeyeq, key1, key2)
 
 def ll_dict_len(d):
     return d.num_items
@@ -448,6 +445,8 @@
     i = ll_dict_lookup(d, key, hash)
     return _ll_dict_setitem_lookup_done(d, key, value, hash, i)
 
+# Leaving as dont_look_inside ATM, it has a few branches which could lead to
+# many bridges if we don't consider their possible frequency.
 @jit.dont_look_inside
 def _ll_dict_setitem_lookup_done(d, key, value, hash, i):
     valid = (i & HIGHEST_BIT) == 0
@@ -492,6 +491,8 @@
         raise KeyError
     _ll_dict_del(d, i)
 
+# XXX: Move the size checking and resize into a single call which is opauqe to
+# the JIT to avoid extra branches.
 @jit.dont_look_inside
 def _ll_dict_del(d, i):
     d.entries.mark_deleted(i)
@@ -532,6 +533,7 @@
 # ------- a port of CPython's dictobject.c's lookdict implementation -------
 PERTURB_SHIFT = 5
 
+ at jit.dont_look_inside
 def ll_dict_lookup(d, key, hash):
     entries = d.entries
     ENTRIES = lltype.typeOf(entries).TO
@@ -621,7 +623,6 @@
     d.num_items = 0
     d.resize_counter = DICT_INITSIZE * 2
     return d
-ll_newdict.oopspec = 'newdict()'
 
 def ll_newdict_size(DICT, length_estimate):
     length_estimate = (length_estimate // 2) * 3
@@ -633,7 +634,6 @@
     d.num_items = 0
     d.resize_counter = n * 2
     return d
-ll_newdict_size.oopspec = 'newdict()'
 
 # pypy.rpython.memory.lldict uses a dict based on Struct and Array
 # instead of GcStruct and GcArray, which is done by using different
@@ -866,7 +866,6 @@
         global_popitem_index.nextindex = base + counter
     return i
 
- at jit.dont_look_inside
 def ll_popitem(ELEM, dic):
     i = _ll_getnextitem(dic)
     entry = dic.entries[i]
diff --git a/pypy/rpython/lltypesystem/rtagged.py b/pypy/rpython/lltypesystem/rtagged.py
--- a/pypy/rpython/lltypesystem/rtagged.py
+++ b/pypy/rpython/lltypesystem/rtagged.py
@@ -43,7 +43,7 @@
         v_value = hop.inputarg(lltype.Signed, arg=1)
         c_one = hop.inputconst(lltype.Signed, 1)
         hop.exception_is_here()
-        v2 = hop.genop('int_lshift_ovf', [v_value, c_one],
+        v2 = hop.genop('int_add_ovf', [v_value, v_value],
                        resulttype = lltype.Signed)
         v2p1 = hop.genop('int_add', [v2, c_one],
                          resulttype = lltype.Signed)
diff --git a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
--- a/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
@@ -8,6 +8,7 @@
 from pypy.rpython.lltypesystem.ll2ctypes import uninitialized2ctypes
 from pypy.rpython.lltypesystem.ll2ctypes import ALLOCATED, force_cast
 from pypy.rpython.lltypesystem.ll2ctypes import cast_adr_to_int, get_ctypes_type
+from pypy.rpython.lltypesystem.ll2ctypes import _llgcopaque
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rlib import rposix
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -1123,6 +1124,9 @@
 
         #assert lltype.cast_ptr_to_int(ref1) == intval
 
+        x = rffi.cast(llmemory.GCREF, -17)
+        assert lltype.cast_ptr_to_int(x) == -17
+
     def test_ptr_truth(self):
         abc = rffi.cast(lltype.Ptr(lltype.FuncType([], lltype.Void)), 0)
         assert not abc
@@ -1346,6 +1350,11 @@
         round = ctypes2lltype(llmemory.GCREF, lltype2ctypes(opaque.hide()))
         assert Opaque.show(round) is opaque
 
+    def test_array_of_structs(self):
+        A = lltype.GcArray(lltype.Struct('x', ('v', lltype.Signed)))
+        a = lltype.malloc(A, 5)
+        a2 = ctypes2lltype(lltype.Ptr(A), lltype2ctypes(a))
+        assert a2._obj.getitem(0)._obj._parentstructure() is a2._obj
 
 class TestPlatform(object):
     def test_lib_on_libpaths(self):
@@ -1387,3 +1396,7 @@
         f = rffi.llexternal('f', [rffi.INT, rffi.INT], rffi.INT,
                             compilation_info=eci)
         assert f(3, 4) == 7
+
+    def test_llgcopaque_eq(self):
+        assert _llgcopaque(1) != None
+        assert _llgcopaque(0) == None
diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py
--- a/pypy/rpython/memory/gc/minimark.py
+++ b/pypy/rpython/memory/gc/minimark.py
@@ -1292,10 +1292,12 @@
         # if a prebuilt GcStruct contains a pointer to a young object,
         # then the write_barrier must have ensured that the prebuilt
         # GcStruct is in the list self.old_objects_pointing_to_young.
+        debug_start("gc-minor-walkroots")
         self.root_walker.walk_roots(
             MiniMarkGC._trace_drag_out1,  # stack roots
             MiniMarkGC._trace_drag_out1,  # static in prebuilt non-gc
             None)                         # static in prebuilt gc
+        debug_stop("gc-minor-walkroots")
 
     def collect_cardrefs_to_nursery(self):
         size_gc_header = self.gcheaderbuilder.size_gc_header
diff --git a/pypy/rpython/rclass.py b/pypy/rpython/rclass.py
--- a/pypy/rpython/rclass.py
+++ b/pypy/rpython/rclass.py
@@ -191,6 +191,10 @@
                     "class %r inherits from its parent _immutable_=True, "
                     "so it should also declare _immutable_=True" % (
                     self.classdef,))
+            if loc.classdict.get('_immutable_').value is not True:
+                raise TyperError(
+                    "class %r: _immutable_ = something else than True" % (
+                    self.classdef,))
             hints = hints.copy()
             hints['immutable'] = True
         self.immutable_field_set = set()  # unless overwritten below
diff --git a/pypy/tool/logparser.py b/pypy/tool/logparser.py
--- a/pypy/tool/logparser.py
+++ b/pypy/tool/logparser.py
@@ -298,6 +298,8 @@
         image.paste(textpercent, (t1x, 5), textpercent)
         image.paste(textlabel,   (t2x, 5), textlabel)
         images.append(image)
+    if not images:
+        return None
     return combine(images, spacing=0, border=1, horizontal=False)
 
 def get_timesummary_single_image(totaltimes, totaltime0, componentdict,
@@ -333,6 +335,8 @@
         del totaltimes[None]
     img2 = render_histogram(totaltimes, totaltime0, {},
                             width, summarybarheight)
+    if img2 is None:
+        return img1
     return combine([img1, img2], spacing=spacing, horizontal=True)
 
 # ----------
diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -56,8 +56,8 @@
     binaries = [(pypy_c, rename_pypy_c)]
     #
     if sys.platform == 'win32':
-        # Can't rename a DLL: it is always called 'libpypy_c.dll'
-        for extra in ['libpypy_c.dll',
+        # Can't rename a DLL: it is always called 'libpypy-c.dll'
+        for extra in ['libpypy-c.dll',
                       'libexpat.dll', 'sqlite3.dll', 'msvcr90.dll']:
             p = pypy_c.dirpath().join(extra)
             if not p.check():
diff --git a/pypy/translator/c/database.py b/pypy/translator/c/database.py
--- a/pypy/translator/c/database.py
+++ b/pypy/translator/c/database.py
@@ -176,7 +176,7 @@
                      # introduced by the GC transformer, or the type_info_table
         return node
 
-    def get(self, obj):
+    def get(self, obj, funcgen=None):
         if isinstance(obj, CConstant):
             return obj.c_name  # without further checks
         T = typeOf(obj)
@@ -228,6 +228,8 @@
                     return '((%s) %d)' % (cdecl(self.gettype(T), ''),
                                           obj._obj)
                 node = self.getcontainernode(container)
+                if node._funccodegen_owner is None:
+                    node._funccodegen_owner = funcgen
                 return node.getptrname()
             else:
                 return '((%s) NULL)' % (cdecl(self.gettype(T), ''), )
@@ -284,14 +286,16 @@
             finish_callbacks.append(('GC transformer: finished tables',
                                      self.gctransformer.get_finish_tables()))
 
-        def add_dependencies(newdependencies):
+        def add_dependencies(newdependencies, parent=None):
             for value in newdependencies:
                 #if isinstance(value, _uninitialized):
                 #    continue
                 if isinstance(typeOf(value), ContainerType):
-                    self.getcontainernode(value)
+                    node = self.getcontainernode(value)
+                    if parent and node._funccodegen_owner is not None:
+                        node._funccodegen_owner = parent._funccodegen_owner
                 else:
-                    self.get(value)
+                    self.get(value, parent and parent._funccodegen_owner)
 
         while True:
             while True:
@@ -303,7 +307,7 @@
                 if i == len(self.containerlist):
                     break
                 node = self.containerlist[i]
-                add_dependencies(node.enum_dependencies())
+                add_dependencies(node.enum_dependencies(), node)
                 i += 1
                 self.completedcontainers = i
                 if i == show_i:
diff --git a/pypy/translator/c/funcgen.py b/pypy/translator/c/funcgen.py
--- a/pypy/translator/c/funcgen.py
+++ b/pypy/translator/c/funcgen.py
@@ -833,7 +833,7 @@
         return 'INSTRUMENT_COUNT(%s);' % counter_label
             
     def OP_IS_EARLY_CONSTANT(self, op):
-        return self.expr(op.result)  + ' = 0;' # Allways false
+        return '%s = 0; /* IS_EARLY_CONSTANT */' % (self.expr(op.result),)
 
     def OP_JIT_MARKER(self, op):
         return '/* JIT_MARKER %s */' % op
@@ -845,6 +845,9 @@
         return '%s = %s; /* JIT_FORCE_VIRTUAL */' % (self.expr(op.result),
                                                      self.expr(op.args[0]))
 
+    def OP_JIT_IS_VIRTUAL(self, op):
+        return '%s = 0; /* JIT_IS_VIRTUAL */' % (self.expr(op.result),)
+
     def OP_JIT_FORCE_QUASI_IMMUTABLE(self, op):
         return '/* JIT_FORCE_QUASI_IMMUTABLE %s */' % op
 
diff --git a/pypy/translator/c/gc.py b/pypy/translator/c/gc.py
--- a/pypy/translator/c/gc.py
+++ b/pypy/translator/c/gc.py
@@ -170,6 +170,7 @@
     nodekind = 'refcnt rtti'
     globalcontainer = True
     typename = 'void (@)(void *)'
+    _funccodegen_owner = None
 
     def __init__(self, db, T, obj):
         assert T == RuntimeTypeInfo
@@ -266,6 +267,7 @@
     nodekind = 'boehm rtti'
     globalcontainer = True
     typename = 'char @'
+    _funccodegen_owner = None
 
     def __init__(self, db, T, obj):
         assert T == RuntimeTypeInfo
diff --git a/pypy/translator/c/gcc/test/test_asmgcroot.py b/pypy/translator/c/gcc/test/test_asmgcroot.py
--- a/pypy/translator/c/gcc/test/test_asmgcroot.py
+++ b/pypy/translator/c/gcc/test/test_asmgcroot.py
@@ -21,6 +21,7 @@
         config = get_pypy_config(translating=True)
         config.translation.gc = cls.gcpolicy
         config.translation.gcrootfinder = "asmgcc"
+        config.translation.taggedpointers = getattr(cls, "taggedpointers", False)
         return config
 
     @classmethod
diff --git a/pypy/translator/c/genc.py b/pypy/translator/c/genc.py
--- a/pypy/translator/c/genc.py
+++ b/pypy/translator/c/genc.py
@@ -682,8 +682,7 @@
     def getbasecfilefornode(self, node, basecname):
         # For FuncNode instances, use the python source filename (relative to
         # the top directory):
-        if hasattr(node.obj, 'graph'):
-            g = node.obj.graph
+        def invent_nice_name(g):
             # Lookup the filename from the function.
             # However, not all FunctionGraph objs actually have a "func":
             if hasattr(g, 'func'):
@@ -693,6 +692,15 @@
                     if pypkgpath:
                         relpypath =  localpath.relto(pypkgpath)
                         return relpypath.replace('.py', '.c')
+            return None
+        if hasattr(node.obj, 'graph'):
+            name = invent_nice_name(node.obj.graph)
+            if name is not None:
+                return name
+        elif node._funccodegen_owner is not None:
+            name = invent_nice_name(node._funccodegen_owner.graph)
+            if name is not None:
+                return "data_" + name
         return basecname
 
     def splitnodesimpl(self, basecname, nodes, nextra, nbetween,
diff --git a/pypy/translator/c/node.py b/pypy/translator/c/node.py
--- a/pypy/translator/c/node.py
+++ b/pypy/translator/c/node.py
@@ -485,6 +485,7 @@
         __slots__ = """db obj 
                        typename implementationtypename
                         name
+                        _funccodegen_owner
                         globalcontainer""".split()
     eci_name = '_compilation_info'
 
@@ -509,6 +510,7 @@
         if self.typename != self.implementationtypename:
             if db.gettypedefnode(T).extra_union_for_varlength:
                 self.name += '.b'
+        self._funccodegen_owner = None
 
     def getptrname(self):
         return '(&%s)' % self.name
@@ -842,6 +844,9 @@
         if self.funcgens:
             argnames = self.funcgens[0].argnames()  #Assume identical for all funcgens
             self.implementationtypename = self.db.gettype(self.T, argnames=argnames)
+            self._funccodegen_owner = self.funcgens[0]
+        else:
+            self._funccodegen_owner = None
 
     def basename(self):
         return self.obj._name
@@ -1005,6 +1010,7 @@
     globalcontainer = True
     typename = 'PyObject @'
     implementationtypename = 'PyObject *@'
+    _funccodegen_owner = None
 
     def __init__(self, db, T, obj):
         # obj is a _pyobject here; obj.value is the underlying CPython object
diff --git a/pypy/translator/c/primitive.py b/pypy/translator/c/primitive.py
--- a/pypy/translator/c/primitive.py
+++ b/pypy/translator/c/primitive.py
@@ -141,7 +141,12 @@
 
 def name_gcref(value, db):
     if value:
-        realobj = value._obj.container
+        obj = value._obj
+        if isinstance(obj, int):
+            # a tagged pointer
+            assert obj & 1 == 1
+            return '((%s) %d)' % (cdecl("void*", ''), obj)
+        realobj = obj.container
         realvalue = cast_opaque_ptr(Ptr(typeOf(realobj)), value)
         return db.get(realvalue)
     else:
diff --git a/pypy/translator/c/src/thread_nt.h b/pypy/translator/c/src/thread_nt.h
--- a/pypy/translator/c/src/thread_nt.h
+++ b/pypy/translator/c/src/thread_nt.h
@@ -245,7 +245,7 @@
     if (pending_acquires <= 0)
         return 0;
     InterlockedIncrement(&pending_acquires);
-    PulseEvent(&cond_gil);
+    PulseEvent(cond_gil);
 
     /* hack: the three following lines do a pthread_cond_wait(), and
        normally specifying a timeout of INFINITE would be fine.  But the
@@ -253,7 +253,7 @@
        (small) risk that PulseEvent misses the WaitForSingleObject().
        In this case the process will just sleep a few milliseconds. */
     LeaveCriticalSection(&mutex_gil);
-    WaitForSingleObject(&cond_gil, 15);
+    WaitForSingleObject(cond_gil, 15);
     EnterCriticalSection(&mutex_gil);
 
     InterlockedDecrement(&pending_acquires);
@@ -263,7 +263,7 @@
 void RPyGilRelease(void)
 {
     LeaveCriticalSection(&mutex_gil);
-    PulseEvent(&cond_gil);
+    PulseEvent(cond_gil);
 }
 
 void RPyGilAcquire(void)
diff --git a/pypy/translator/c/test/test_newgc.py b/pypy/translator/c/test/test_newgc.py
--- a/pypy/translator/c/test/test_newgc.py
+++ b/pypy/translator/c/test/test_newgc.py
@@ -1487,6 +1487,43 @@
         res = self.run("tagged")
         assert res == expected
 
+    def define_erased(cls):
+        from pypy.rlib import rerased
+        erase, unerase = rerased.new_erasing_pair("test")
+        class Unrelated(object):
+            pass
+
+        u = Unrelated()
+        u.tagged = True
+        u.x = rerased.erase_int(41)
+        class A(object):
+            pass
+        def fn():
+            n = 1
+            while n >= 0:
+                if u.tagged:
+                    n = rerased.unerase_int(u.x)
+                    a = A()
+                    a.n = n - 1
+                    u.x = erase(a)
+                    u.tagged = False
+                else:
+                    n = unerase(u.x).n
+                    u.x = rerased.erase_int(n - 1)
+                    u.tagged = True
+        def func():
+            rgc.collect() # check that a prebuilt erased integer doesn't explode
+            u.x = rerased.erase_int(1000)
+            u.tagged = True
+            fn()
+            return 1
+        return func
+
+    def test_erased(self):
+        expected = self.run_orig("erased")
+        res = self.run("erased")
+        assert res == expected
+
 from pypy.rlib.objectmodel import UnboxedValue
 
 class TaggedBase(object):
diff --git a/pypy/translator/platform/linux.py b/pypy/translator/platform/linux.py
--- a/pypy/translator/platform/linux.py
+++ b/pypy/translator/platform/linux.py
@@ -1,5 +1,6 @@
 """Support for Linux."""
 
+import sys
 from pypy.translator.platform.posix import BasePosix
 
 class BaseLinux(BasePosix):
@@ -24,15 +25,18 @@
         return self._pkg_config("libffi", "--libs-only-L",
                                 ['/usr/lib/libffi'])
 
+    def library_dirs_for_libffi_a(self):
+        # places where we need to look for libffi.a
+        # XXX obscuuure!  only look for libffi.a if run with translate.py
+        if 'translate' in sys.modules:
+            return self.library_dirs_for_libffi() + ['/usr/lib']
+        else:
+            return []
+
 
 class Linux(BaseLinux):
     shared_only = ()    # it seems that on 32-bit linux, compiling with -fPIC
                         # gives assembler that asmgcc is not happy about.
 
-    def library_dirs_for_libffi_a(self):
-        # places where we need to look for libffi.a
-        return self.library_dirs_for_libffi() + ['/usr/lib']
-
-
 class Linux64(BaseLinux):
     pass
diff --git a/pypy/translator/platform/posix.py b/pypy/translator/platform/posix.py
--- a/pypy/translator/platform/posix.py
+++ b/pypy/translator/platform/posix.py
@@ -157,7 +157,7 @@
 
         rules = [
             ('all', '$(DEFAULT_TARGET)', []),
-            ('$(TARGET)', '$(OBJECTS)', '$(CC_LINK) $(LDFLAGS) $(LDFLAGSEXTRA) -o $@ $(OBJECTS) $(LIBDIRS) $(LIBS) $(LINKFILES)'),
+            ('$(TARGET)', '$(OBJECTS)', '$(CC_LINK) $(LDFLAGSEXTRA) -o $@ $(OBJECTS) $(LIBDIRS) $(LIBS) $(LINKFILES) $(LDFLAGS)'),
             ('%.o', '%.c', '$(CC) $(CFLAGS) $(CFLAGSEXTRA) -o $@ -c $< $(INCLUDEDIRS)'),
             ]
 


More information about the pypy-commit mailing list