[pypy-commit] pypy py3k: hg merge default

amauryfa noreply at buildbot.pypy.org
Mon Nov 7 22:35:00 CET 2011


Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch: py3k
Changeset: r48886:df486c370688
Date: 2011-11-07 22:05 +0100
http://bitbucket.org/pypy/pypy/changeset/df486c370688/

Log:	hg merge default

diff too long, truncating to 10000 out of 10765 lines

diff --git a/lib-python/conftest.py b/lib-python/conftest.py
--- a/lib-python/conftest.py
+++ b/lib-python/conftest.py
@@ -189,7 +189,7 @@
     RegrTest('test_dictviews.py', core=True),
     RegrTest('test_difflib.py'),
     RegrTest('test_dis.py'),
-    RegrTest('test_distutils.py'),
+    RegrTest('test_distutils.py', skip=True),
     RegrTest('test_doctest.py', usemodules="thread"),
     RegrTest('test_doctest2.py'),
     RegrTest('test_docxmlrpc.py'),
diff --git a/lib-python/modified-2.7/ctypes/test/test_simplesubclasses.py b/lib-python/modified-2.7/ctypes/test/test_simplesubclasses.py
--- a/lib-python/modified-2.7/ctypes/test/test_simplesubclasses.py
+++ b/lib-python/modified-2.7/ctypes/test/test_simplesubclasses.py
@@ -1,6 +1,5 @@
 import unittest
 from ctypes import *
-from ctypes.test import xfail
 
 class MyInt(c_int):
     def __cmp__(self, other):
@@ -27,7 +26,6 @@
         self.assertEqual(None, cb())
 
 
-    @xfail
     def test_int_callback(self):
         args = []
         def func(arg):
diff --git a/lib-python/modified-2.7/heapq.py b/lib-python/modified-2.7/heapq.py
new file mode 100644
--- /dev/null
+++ b/lib-python/modified-2.7/heapq.py
@@ -0,0 +1,442 @@
+# -*- coding: latin-1 -*-
+
+"""Heap queue algorithm (a.k.a. priority queue).
+
+Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for
+all k, counting elements from 0.  For the sake of comparison,
+non-existing elements are considered to be infinite.  The interesting
+property of a heap is that a[0] is always its smallest element.
+
+Usage:
+
+heap = []            # creates an empty heap
+heappush(heap, item) # pushes a new item on the heap
+item = heappop(heap) # pops the smallest item from the heap
+item = heap[0]       # smallest item on the heap without popping it
+heapify(x)           # transforms list into a heap, in-place, in linear time
+item = heapreplace(heap, item) # pops and returns smallest item, and adds
+                               # new item; the heap size is unchanged
+
+Our API differs from textbook heap algorithms as follows:
+
+- We use 0-based indexing.  This makes the relationship between the
+  index for a node and the indexes for its children slightly less
+  obvious, but is more suitable since Python uses 0-based indexing.
+
+- Our heappop() method returns the smallest item, not the largest.
+
+These two make it possible to view the heap as a regular Python list
+without surprises: heap[0] is the smallest item, and heap.sort()
+maintains the heap invariant!
+"""
+
+# Original code by Kevin O'Connor, augmented by Tim Peters and Raymond Hettinger
+
+__about__ = """Heap queues
+
+[explanation by Fran&#65533;ois Pinard]
+
+Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for
+all k, counting elements from 0.  For the sake of comparison,
+non-existing elements are considered to be infinite.  The interesting
+property of a heap is that a[0] is always its smallest element.
+
+The strange invariant above is meant to be an efficient memory
+representation for a tournament.  The numbers below are `k', not a[k]:
+
+                                   0
+
+                  1                                 2
+
+          3               4                5               6
+
+      7       8       9       10      11      12      13      14
+
+    15 16   17 18   19 20   21 22   23 24   25 26   27 28   29 30
+
+
+In the tree above, each cell `k' is topping `2*k+1' and `2*k+2'.  In
+an usual binary tournament we see in sports, each cell is the winner
+over the two cells it tops, and we can trace the winner down the tree
+to see all opponents s/he had.  However, in many computer applications
+of such tournaments, we do not need to trace the history of a winner.
+To be more memory efficient, when a winner is promoted, we try to
+replace it by something else at a lower level, and the rule becomes
+that a cell and the two cells it tops contain three different items,
+but the top cell "wins" over the two topped cells.
+
+If this heap invariant is protected at all time, index 0 is clearly
+the overall winner.  The simplest algorithmic way to remove it and
+find the "next" winner is to move some loser (let's say cell 30 in the
+diagram above) into the 0 position, and then percolate this new 0 down
+the tree, exchanging values, until the invariant is re-established.
+This is clearly logarithmic on the total number of items in the tree.
+By iterating over all items, you get an O(n ln n) sort.
+
+A nice feature of this sort is that you can efficiently insert new
+items while the sort is going on, provided that the inserted items are
+not "better" than the last 0'th element you extracted.  This is
+especially useful in simulation contexts, where the tree holds all
+incoming events, and the "win" condition means the smallest scheduled
+time.  When an event schedule other events for execution, they are
+scheduled into the future, so they can easily go into the heap.  So, a
+heap is a good structure for implementing schedulers (this is what I
+used for my MIDI sequencer :-).
+
+Various structures for implementing schedulers have been extensively
+studied, and heaps are good for this, as they are reasonably speedy,
+the speed is almost constant, and the worst case is not much different
+than the average case.  However, there are other representations which
+are more efficient overall, yet the worst cases might be terrible.
+
+Heaps are also very useful in big disk sorts.  You most probably all
+know that a big sort implies producing "runs" (which are pre-sorted
+sequences, which size is usually related to the amount of CPU memory),
+followed by a merging passes for these runs, which merging is often
+very cleverly organised[1].  It is very important that the initial
+sort produces the longest runs possible.  Tournaments are a good way
+to that.  If, using all the memory available to hold a tournament, you
+replace and percolate items that happen to fit the current run, you'll
+produce runs which are twice the size of the memory for random input,
+and much better for input fuzzily ordered.
+
+Moreover, if you output the 0'th item on disk and get an input which
+may not fit in the current tournament (because the value "wins" over
+the last output value), it cannot fit in the heap, so the size of the
+heap decreases.  The freed memory could be cleverly reused immediately
+for progressively building a second heap, which grows at exactly the
+same rate the first heap is melting.  When the first heap completely
+vanishes, you switch heaps and start a new run.  Clever and quite
+effective!
+
+In a word, heaps are useful memory structures to know.  I use them in
+a few applications, and I think it is good to keep a `heap' module
+around. :-)
+
+--------------------
+[1] The disk balancing algorithms which are current, nowadays, are
+more annoying than clever, and this is a consequence of the seeking
+capabilities of the disks.  On devices which cannot seek, like big
+tape drives, the story was quite different, and one had to be very
+clever to ensure (far in advance) that each tape movement will be the
+most effective possible (that is, will best participate at
+"progressing" the merge).  Some tapes were even able to read
+backwards, and this was also used to avoid the rewinding time.
+Believe me, real good tape sorts were quite spectacular to watch!
+From all times, sorting has always been a Great Art! :-)
+"""
+
+__all__ = ['heappush', 'heappop', 'heapify', 'heapreplace', 'merge',
+           'nlargest', 'nsmallest', 'heappushpop']
+
+from itertools import islice, repeat, count, imap, izip, tee, chain
+from operator import itemgetter
+import bisect
+
+def heappush(heap, item):
+    """Push item onto heap, maintaining the heap invariant."""
+    heap.append(item)
+    _siftdown(heap, 0, len(heap)-1)
+
+def heappop(heap):
+    """Pop the smallest item off the heap, maintaining the heap invariant."""
+    lastelt = heap.pop()    # raises appropriate IndexError if heap is empty
+    if heap:
+        returnitem = heap[0]
+        heap[0] = lastelt
+        _siftup(heap, 0)
+    else:
+        returnitem = lastelt
+    return returnitem
+
+def heapreplace(heap, item):
+    """Pop and return the current smallest value, and add the new item.
+
+    This is more efficient than heappop() followed by heappush(), and can be
+    more appropriate when using a fixed-size heap.  Note that the value
+    returned may be larger than item!  That constrains reasonable uses of
+    this routine unless written as part of a conditional replacement:
+
+        if item > heap[0]:
+            item = heapreplace(heap, item)
+    """
+    returnitem = heap[0]    # raises appropriate IndexError if heap is empty
+    heap[0] = item
+    _siftup(heap, 0)
+    return returnitem
+
+def heappushpop(heap, item):
+    """Fast version of a heappush followed by a heappop."""
+    if heap and heap[0] < item:
+        item, heap[0] = heap[0], item
+        _siftup(heap, 0)
+    return item
+
+def heapify(x):
+    """Transform list into a heap, in-place, in O(len(heap)) time."""
+    n = len(x)
+    # Transform bottom-up.  The largest index there's any point to looking at
+    # is the largest with a child index in-range, so must have 2*i + 1 < n,
+    # or i < (n-1)/2.  If n is even = 2*j, this is (2*j-1)/2 = j-1/2 so
+    # j-1 is the largest, which is n//2 - 1.  If n is odd = 2*j+1, this is
+    # (2*j+1-1)/2 = j so j-1 is the largest, and that's again n//2-1.
+    for i in reversed(xrange(n//2)):
+        _siftup(x, i)
+
+def nlargest(n, iterable):
+    """Find the n largest elements in a dataset.
+
+    Equivalent to:  sorted(iterable, reverse=True)[:n]
+    """
+    if n < 0: # for consistency with the c impl
+        return []
+    it = iter(iterable)
+    result = list(islice(it, n))
+    if not result:
+        return result
+    heapify(result)
+    _heappushpop = heappushpop
+    for elem in it:
+        _heappushpop(result, elem)
+    result.sort(reverse=True)
+    return result
+
+def nsmallest(n, iterable):
+    """Find the n smallest elements in a dataset.
+
+    Equivalent to:  sorted(iterable)[:n]
+    """
+    if n < 0: # for consistency with the c impl
+        return []
+    if hasattr(iterable, '__len__') and n * 10 <= len(iterable):
+        # For smaller values of n, the bisect method is faster than a minheap.
+        # It is also memory efficient, consuming only n elements of space.
+        it = iter(iterable)
+        result = sorted(islice(it, 0, n))
+        if not result:
+            return result
+        insort = bisect.insort
+        pop = result.pop
+        los = result[-1]    # los --> Largest of the nsmallest
+        for elem in it:
+            if los <= elem:
+                continue
+            insort(result, elem)
+            pop()
+            los = result[-1]
+        return result
+    # An alternative approach manifests the whole iterable in memory but
+    # saves comparisons by heapifying all at once.  Also, saves time
+    # over bisect.insort() which has O(n) data movement time for every
+    # insertion.  Finding the n smallest of an m length iterable requires
+    #    O(m) + O(n log m) comparisons.
+    h = list(iterable)
+    heapify(h)
+    return map(heappop, repeat(h, min(n, len(h))))
+
+# 'heap' is a heap at all indices >= startpos, except possibly for pos.  pos
+# is the index of a leaf with a possibly out-of-order value.  Restore the
+# heap invariant.
+def _siftdown(heap, startpos, pos):
+    newitem = heap[pos]
+    # Follow the path to the root, moving parents down until finding a place
+    # newitem fits.
+    while pos > startpos:
+        parentpos = (pos - 1) >> 1
+        parent = heap[parentpos]
+        if newitem < parent:
+            heap[pos] = parent
+            pos = parentpos
+            continue
+        break
+    heap[pos] = newitem
+
+# The child indices of heap index pos are already heaps, and we want to make
+# a heap at index pos too.  We do this by bubbling the smaller child of
+# pos up (and so on with that child's children, etc) until hitting a leaf,
+# then using _siftdown to move the oddball originally at index pos into place.
+#
+# We *could* break out of the loop as soon as we find a pos where newitem <=
+# both its children, but turns out that's not a good idea, and despite that
+# many books write the algorithm that way.  During a heap pop, the last array
+# element is sifted in, and that tends to be large, so that comparing it
+# against values starting from the root usually doesn't pay (= usually doesn't
+# get us out of the loop early).  See Knuth, Volume 3, where this is
+# explained and quantified in an exercise.
+#
+# Cutting the # of comparisons is important, since these routines have no
+# way to extract "the priority" from an array element, so that intelligence
+# is likely to be hiding in custom __cmp__ methods, or in array elements
+# storing (priority, record) tuples.  Comparisons are thus potentially
+# expensive.
+#
+# On random arrays of length 1000, making this change cut the number of
+# comparisons made by heapify() a little, and those made by exhaustive
+# heappop() a lot, in accord with theory.  Here are typical results from 3
+# runs (3 just to demonstrate how small the variance is):
+#
+# Compares needed by heapify     Compares needed by 1000 heappops
+# --------------------------     --------------------------------
+# 1837 cut to 1663               14996 cut to 8680
+# 1855 cut to 1659               14966 cut to 8678
+# 1847 cut to 1660               15024 cut to 8703
+#
+# Building the heap by using heappush() 1000 times instead required
+# 2198, 2148, and 2219 compares:  heapify() is more efficient, when
+# you can use it.
+#
+# The total compares needed by list.sort() on the same lists were 8627,
+# 8627, and 8632 (this should be compared to the sum of heapify() and
+# heappop() compares):  list.sort() is (unsurprisingly!) more efficient
+# for sorting.
+
+def _siftup(heap, pos):
+    endpos = len(heap)
+    startpos = pos
+    newitem = heap[pos]
+    # Bubble up the smaller child until hitting a leaf.
+    childpos = 2*pos + 1    # leftmost child position
+    while childpos < endpos:
+        # Set childpos to index of smaller child.
+        rightpos = childpos + 1
+        if rightpos < endpos and not heap[childpos] < heap[rightpos]:
+            childpos = rightpos
+        # Move the smaller child up.
+        heap[pos] = heap[childpos]
+        pos = childpos
+        childpos = 2*pos + 1
+    # The leaf at pos is empty now.  Put newitem there, and bubble it up
+    # to its final resting place (by sifting its parents down).
+    heap[pos] = newitem
+    _siftdown(heap, startpos, pos)
+
+# If available, use C implementation
+try:
+    from _heapq import *
+except ImportError:
+    pass
+
+def merge(*iterables):
+    '''Merge multiple sorted inputs into a single sorted output.
+
+    Similar to sorted(itertools.chain(*iterables)) but returns a generator,
+    does not pull the data into memory all at once, and assumes that each of
+    the input streams is already sorted (smallest to largest).
+
+    >>> list(merge([1,3,5,7], [0,2,4,8], [5,10,15,20], [], [25]))
+    [0, 1, 2, 3, 4, 5, 5, 7, 8, 10, 15, 20, 25]
+
+    '''
+    _heappop, _heapreplace, _StopIteration = heappop, heapreplace, StopIteration
+
+    h = []
+    h_append = h.append
+    for itnum, it in enumerate(map(iter, iterables)):
+        try:
+            next = it.next
+            h_append([next(), itnum, next])
+        except _StopIteration:
+            pass
+    heapify(h)
+
+    while 1:
+        try:
+            while 1:
+                v, itnum, next = s = h[0]   # raises IndexError when h is empty
+                yield v
+                s[0] = next()               # raises StopIteration when exhausted
+                _heapreplace(h, s)          # restore heap condition
+        except _StopIteration:
+            _heappop(h)                     # remove empty iterator
+        except IndexError:
+            return
+
+# Extend the implementations of nsmallest and nlargest to use a key= argument
+_nsmallest = nsmallest
+def nsmallest(n, iterable, key=None):
+    """Find the n smallest elements in a dataset.
+
+    Equivalent to:  sorted(iterable, key=key)[:n]
+    """
+    # Short-cut for n==1 is to use min() when len(iterable)>0
+    if n == 1:
+        it = iter(iterable)
+        head = list(islice(it, 1))
+        if not head:
+            return []
+        if key is None:
+            return [min(chain(head, it))]
+        return [min(chain(head, it), key=key)]
+
+    # When n>=size, it's faster to use sort()
+    try:
+        size = len(iterable)
+    except (TypeError, AttributeError):
+        pass
+    else:
+        if n >= size:
+            return sorted(iterable, key=key)[:n]
+
+    # When key is none, use simpler decoration
+    if key is None:
+        it = izip(iterable, count())                        # decorate
+        result = _nsmallest(n, it)
+        return map(itemgetter(0), result)                   # undecorate
+
+    # General case, slowest method
+    in1, in2 = tee(iterable)
+    it = izip(imap(key, in1), count(), in2)                 # decorate
+    result = _nsmallest(n, it)
+    return map(itemgetter(2), result)                       # undecorate
+
+_nlargest = nlargest
+def nlargest(n, iterable, key=None):
+    """Find the n largest elements in a dataset.
+
+    Equivalent to:  sorted(iterable, key=key, reverse=True)[:n]
+    """
+
+    # Short-cut for n==1 is to use max() when len(iterable)>0
+    if n == 1:
+        it = iter(iterable)
+        head = list(islice(it, 1))
+        if not head:
+            return []
+        if key is None:
+            return [max(chain(head, it))]
+        return [max(chain(head, it), key=key)]
+
+    # When n>=size, it's faster to use sort()
+    try:
+        size = len(iterable)
+    except (TypeError, AttributeError):
+        pass
+    else:
+        if n >= size:
+            return sorted(iterable, key=key, reverse=True)[:n]
+
+    # When key is none, use simpler decoration
+    if key is None:
+        it = izip(iterable, count(0,-1))                    # decorate
+        result = _nlargest(n, it)
+        return map(itemgetter(0), result)                   # undecorate
+
+    # General case, slowest method
+    in1, in2 = tee(iterable)
+    it = izip(imap(key, in1), count(0,-1), in2)             # decorate
+    result = _nlargest(n, it)
+    return map(itemgetter(2), result)                       # undecorate
+
+if __name__ == "__main__":
+    # Simple sanity test
+    heap = []
+    data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
+    for item in data:
+        heappush(heap, item)
+    sort = []
+    while heap:
+        sort.append(heappop(heap))
+    print sort
+
+    import doctest
+    doctest.testmod()
diff --git a/lib-python/modified-2.7/test/test_heapq.py b/lib-python/modified-2.7/test/test_heapq.py
--- a/lib-python/modified-2.7/test/test_heapq.py
+++ b/lib-python/modified-2.7/test/test_heapq.py
@@ -186,6 +186,11 @@
         self.assertFalse(sys.modules['heapq'] is self.module)
         self.assertTrue(hasattr(self.module.heapify, 'func_code'))
 
+    def test_islice_protection(self):
+        m = self.module
+        self.assertFalse(m.nsmallest(-1, [1]))
+        self.assertFalse(m.nlargest(-1, [1]))
+
 
 class TestHeapC(TestHeap):
     module = c_heapq
diff --git a/lib-python/modified-2.7/urllib2.py b/lib-python/modified-2.7/urllib2.py
--- a/lib-python/modified-2.7/urllib2.py
+++ b/lib-python/modified-2.7/urllib2.py
@@ -395,11 +395,7 @@
         meth_name = protocol+"_response"
         for processor in self.process_response.get(protocol, []):
             meth = getattr(processor, meth_name)
-            try:
-                response = meth(req, response)
-            except:
-                response.close()
-                raise
+            response = meth(req, response)
 
         return response
 
diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py
--- a/lib_pypy/_ctypes/structure.py
+++ b/lib_pypy/_ctypes/structure.py
@@ -17,7 +17,7 @@
         if len(f) == 3:
             if (not hasattr(tp, '_type_')
                 or not isinstance(tp._type_, str)
-                or tp._type_ not in "iIhHbBlL"):
+                or tp._type_ not in "iIhHbBlLqQ"):
                 #XXX: are those all types?
                 #     we just dont get the type name
                 #     in the interp levle thrown TypeError
diff --git a/lib_pypy/_pypy_irc_topic.py b/lib_pypy/_pypy_irc_topic.py
--- a/lib_pypy/_pypy_irc_topic.py
+++ b/lib_pypy/_pypy_irc_topic.py
@@ -1,117 +1,6 @@
-"""qvfgbcvna naq hgbcvna punvef
-qlfgbcvna naq hgbcvna punvef
-V'z fbeel, pbhyq lbh cyrnfr abg nterr jvgu gur png nf jryy?
-V'z fbeel, pbhyq lbh cyrnfr abg nterr jvgu gur punve nf jryy?
-jr cnffrq gur RH erivrj
-cbfg RhebClguba fcevag fgnegf 12.IVV.2007, 10nz
-RhebClguba raqrq
-n Pyrna Ragrecevfrf cebqhpgvba
-npnqrzl vf n pbzcyvpngrq ebyr tnzr
-npnqrzvn vf n pbzcyvpngrq ebyr tnzr
-jbexvat pbqr vf crn fbhc
-abg lbhe snhyg, zber yvxr vg'f n zbivat gnetrg
-guvf fragrapr vf snyfr
-abguvat vf gehr
-Yncfnat Fbhpubat
-Oenpunzhgnaqn
-fbeel, V'yy grnpu gur pnpghf ubj gb fjvz yngre
-Jul fb znal znal znal znal znal ivbyvaf?
-Jul fb znal znal znal znal znal bowrpgf?
-"eha njnl naq yvir ba n snez" nccebnpu gb fbsgjner qrirybczrag
-"va snpg, lbh zvtug xabj zber nobhg gur genafyngvba gbbypunva nsgre znfgrevat eclguba guna fbzr angvir fcrnxre xabjf nobhg uvf zbgure gbathr" - kbeNkNk
-"jurer qvq nyy gur ivbyvaf tb?"
-- ClCl fgnghf oybt: uggc://zberclcl.oybtfcbg.pbz/
-uggc://kxpq.pbz/353/
-pnfhnyvgl ivbyngvbaf naq sylvat
-wrgmg abpu fpubxbynqvtre
-R09 2X @PNN:85?
-vs lbh'er gelvat gb oybj hc fghss, jub pnerf?
-vs fghss oybjf hc, lbh pner
-2008 jvyy or gur lrne bs clcl ba gur qrfxgbc
-2008 jvyy or gur lrne bs gur qrfxgbc ba #clcl
-2008 jvyy or gur lrne bs gur qrfxgbc ba #clcl, Wnahnel jvyy or gur zbagu bs gur nyc gbcf
-lrf, ohg jung'g gur frafr bs 0 < "qhena qhena"
-eclguba: flagnk naq frznagvpf bs clguba, fcrrq bs p, erfgevpgvbaf bs wnin naq pbzcvyre reebe zrffntrf nf crargenoyr nf ZHZCF
+"""eclguba: flagnk naq frznagvpf bs clguba, fcrrq bs p, erfgevpgvbaf bs wnin naq pbzcvyre reebe zrffntrf nf crargenoyr nf ZHZCF
 pglcrf unf n fcva bs 1/3
 ' ' vf n fcnpr gbb
-2009 jvyy or gur lrne bs WVG ba gur qrfxgbc
-N ynathntr vf n qvnyrpg jvgu na nezl naq anil
-gbcvpf ner sbe gur srroyr zvaqrq
-2009 vf gur lrne bs ersyrpgvba ba gur qrfxgbc
-gur tybor vf bhe cbal, gur pbfzbf bhe erny ubefr
-jub nz V naq vs lrf, ubj znal?
-cebtenzzvat va orq vf n cresrpgyl svar npgvivgl
-zbber'f ynj vf n qeht jvgu gur jbefg pbzr qbja
-EClguba: jr hfr vg fb lbh qba'g unir gb
-Zbber'f ynj vf n qeht jvgu gur jbefg pbzr qbja. EClguba: haqrpvqrq.
-guvatf jvyy or avpr naq fghss
-qba'g cbfg yvaxf gb cngragf urer
-Abg lbhe hfhny nanylfrf.
-Gur Neg bs gur Punaary
-Clguba 300
-V fhccbfr ZO bs UGZY cre frpbaq vf abg gur hfhny fcrrq zrnfher crbcyr jbhyq rkcrpg sbe n wvg
-gur fha arire frgf ba gur ClCl rzcver
-ghegyrf ner snfgre guna lbh guvax
-cebtenzzvat vf na nrfgrguvp raqrnibhe
-P vf tbbq sbe fbzrguvat, whfg abg sbe jevgvat fbsgjner
-trezna vf tbbq sbe fbzrguvat, whfg abg sbe jevgvat fbsgjner
-trezna vf tbbq sbe artngvbaf, whfg abg sbe jevgvat fbsgjner
-# nffreg qvq abg penfu
-lbh fubhyq fgneg n cresrpg fbsgjner zbirzrag
-lbh fubhyq fgneg n cresrpg punaary gbcvp zbirzrag
-guvf vf n cresrpg punaary gbcvp
-guvf vf n frys-ersreragvny punaary gbcvp
-crrcubcr bcgvzvmngvbaf ner jung n Fhssvpvragyl Fzneg Pbzcvyre hfrf
-"crrcubcr" bcgvzvmngvbaf ner jung na bcgvzvfgvp Pbzcvyre hfrf
-pubbfr lbhe unpx
-gur 'fhcre' xrljbeq vf abg gung uhttnoyr
-wlguba cngpurf ner abg rabhtu sbe clcl
-- qb lbh xabj oreyva? - nyy bs vg? - jryy, whfg oreyva
-- ubj jvyy gur snpg gung gurl ner hfrq va bhe ercy punatr bhe gbcvpf?
-- ubj pna vg rire unir jbexrq?
-- jurer fubhyq gur unpx or fgberq?
-- Vg'f uneq gb fnl rknpgyl jung pbafgvghgrf erfrnepu va gur pbzchgre jbeyq, ohg nf n svefg nccebkvzngvba, vg'f fbsgjner gung qbrfa'g unir hfref.
-- Cebtenzzvat vf nyy nobhg xabjvat jura gb obvy gur benatr fcbatr qbaxrl npebff gur cuvyyvcvarf
-- Jul fb znal, znal, znal, znal, znal, znal qhpxyvatf?
-- ab qrgnvy vf bofpher rabhtu gb abg unir fbzr pbqr qrcraqvat ba vg.
-- jung V trarenyyl jnag vf serr fcrrqhcf
-- nyy bs ClCl vf kv-dhnyvgl
-"lbh pna nyjnlf xvyy -9 be bf._rkvg() vs lbh'er va n uheel"
-Ohernhpengf ohvyq npnqrzvp rzcverf juvpu puhea bhg zrnavatyrff fbyhgvbaf gb veeryrinag ceboyrzf.
-vg'f abg n unpx, vg'f n jbexnebhaq
-ClCl qbrfa'g unir pbcbylinevnqvp qrcraqragyl-zbabzbecurq ulcresyhknqf
-ClCl qbrfa'g punatr gur shaqnzragny culfvpf pbafgnagf
-Qnapr bs gur Fhtnecyhz Snvel
-Wnin vf whfg tbbq rabhtu gb or cenpgvpny, ohg abg tbbq rabhtu gb or hfnoyr.
-RhebClguba vf unccravat, qba'g rkcrpg nal dhvpx erfcbafr gvzrf.
-"V jbhyq yvxr gb fgnl njnl sebz ernyvgl gura"
-"gung'f jul gur 'be' vf ernyyl na 'naq' "
-jvgu nyy nccebcevngr pbagrkghnyvfngvbavat
-qba'g gevc ba gur cbjre pbeq
-vzcyrzragvat YBTB va YBTB: "ghegyrf nyy gur jnl qbja"
-gur ohooyrfbeg jbhyq or gur jebat jnl gb tb
-gur cevapvcyr bs pbafreingvba bs zrff
-gb fnir n gerr, rng n ornire
-Qre Ovore znpugf evpugvt: Antg nyyrf xnchgg.
-"Nal jbeyqivrj gung vfag jenpxrq ol frys-qbhog naq pbashfvba bire vgf bja vqragvgl vf abg n jbeyqivrj sbe zr." - Fpbgg Nnebafba
-jr oryvrir va cnapnxrf, znlor
-jr oryvrir va ghegyrf, znlor
-jr qrsvavgryl oryvrir va zrgn
-gur zngevk unf lbh
-"Yvsr vf uneq, gura lbh anc" - n png
-Vf Nezva ubzr jura gur havirefr prnfrf gb rkvfg?
-Qhrffryqbes fcevag fgnegrq
-frys.nobeeg("pnaabg ybnq negvpyrf")
-QRAGVFGEL FLZOBY YVTUG IREGVPNY NAQ JNIR
-"Gur UUH pnzchf vf n tbbq Dhnxr yriry" - Nezva
-"Gur UUH pnzchf jbhyq or n greevoyr dhnxr yriry - lbh'q arire unir n pyhr jurer lbh ner" - zvpunry
-N enqvbnpgvir png unf 18 unys-yvirf.
-<rfp> : j  [fvtu] <onpxfcnpr> <onpxfcnpr> <pgey>-f
-pbybe-pbqrq oyhrf
-"Neebtnapr va pbzchgre fpvrapr vf zrnfherq va anab-Qvwxfgenf."
-ClCl arrqf n Whfg-va-Gvzr WVG
-"Lbh pna'g gvzr geniry whfg ol frggvat lbhe pybpxf jebat"
-Gjb guernqf jnyx vagb n one. Gur onexrrcre ybbxf hc naq lryyf, "url, V jnag qba'g nal pbaqvgvbaf enpr yvxr gvzr ynfg!"
 Clguba 2.k rfg cerfdhr zbeg, ivir Clguba!
 Clguba 2.k vf abg qrnq
 Riregvzr fbzrbar nethrf jvgu "Fznyygnyx unf nyjnlf qbar K", vg vf  nyjnlf n tbbq uvag gung fbzrguvat arrqf gb or punatrq snfg. - Znephf Qraxre
@@ -119,7 +8,6 @@
 __kkk__ naq __ekkk__ if bcrengvba fybgf: cnegvpyr dhnaghz fhcrecbfvgvba xvaq bs sha
 ClCl vf na rkpvgvat grpuabybtl gung yrgf lbh gb jevgr snfg, cbegnoyr, zhygv-cyngsbez vagrecergref jvgu yrff rssbeg
 Nezva: "Cebybt vf n zrff.", PS: "Ab, vg'f irel pbby!", Nezva: "Vfa'g guvf jung V fnvq?"
-<nevtngb> tbbq, grfgf ner hfrshy fbzrgvzrf :-)
 ClCl vf yvxr nofheq gurngre
 jr unir ab nagv-vzcbffvoyr fgvpx gung znxrf fher gung nyy lbhe cebtenzf unyg
 clcl vf n enpr orgjrra crbcyr funivat lnxf naq gur havirefr cebqhpvat zber orneqrq lnxf. Fb sne, gur havirefr vf jvaavat
@@ -136,14 +24,14 @@
 ClCl 1.1.0orgn eryrnfrq: uggc://pbqrfcrnx.arg/clcl/qvfg/clcl/qbp/eryrnfr-1.1.0.ugzy
 "gurer fubhyq or bar naq bayl bar boivbhf jnl gb qb vg". ClCl inevnag: "gurer pna or A unys-ohttl jnlf gb qb vg"
 1.1 svany eryrnfrq: uggc://pbqrfcrnx.arg/clcl/qvfg/clcl/qbp/eryrnfr-1.1.0.ugzy
-1.1 svany eryrnfrq | <svwny> nzq64 naq ccp ner bayl ninvynoyr va ragrecevfr irefvba
+<svwny> nzq64 naq ccp ner bayl ninvynoyr va ragrecevfr irefvba
 Vf gurer n clcl gvzr? - vs lbh pna srry vg (?) gura gurer vf
 <nevtngb> ab, abezny jbex vf fhpu zhpu yrff gvevat guna inpngvbaf
 <nevtngb> ab, abezny jbex vf fb zhpu yrff gvevat guna inpngvbaf
-SVEFG gurl vtaber lbh, gura gurl ynhtu ng lbh, gura gurl svtug lbh, gura lbh jva.
+-SVEFG gurl vtaber lbh, gura gurl ynhtu ng lbh, gura gurl svtug lbh, gura lbh jva.-
 vg'f Fhaqnl, znlor
 vg'f Fhaqnl, ntnva
-"3 + 3 = 8"  Nagb va gur WVG gnyx
+"3 + 3 = 8" - Nagb va gur WVG gnyx
 RPBBC vf unccravat
 RPBBC vf svavfurq
 cflpb rngf bar oenva cre vapu bs cebterff
@@ -175,10 +63,108 @@
 "nu, whfg va gvzr qbphzragngvba" (__nc__)
 ClCl vf abg n erny IZ: ab frtsnhyg unaqyref gb qb gur ener pnfrf
 lbh pna'g unir obgu pbairavrapr naq fcrrq
-gur WVG qbrfa'g jbex ba BF/K (abi'09)
-ab fhccbeg sbe BF/K evtug abj! (abi'09)
 fyvccref urvtug pna or zrnfherq va k86 ertvfgref
 clcl vf n enpr orgjrra gur vaqhfgel gelvat gb ohvyq znpuvarf jvgu zber naq zber erfbheprf, naq gur clcl qrirybcref gelvat gb rng nyy bs gurz. Fb sne, gur jvaare vf fgvyy hapyrne
+"znl pbagnva ahgf naq/be lbhat cbvagref"
+vg'f nyy irel fvzcyr, yvxr gur ubyvqnlf
+unccl ClCl'f lrne 2010!
+fnzhryr fnlf gung jr ybfg n enmbe. fb jr pna'g funir lnxf
+"yrg'f abg or bofpher, hayrff jr ernyyl arrq gb"
+<nevtngb> (abg guernq-fnsr, ohg jryy, abguvat vf)
+clcl unf znal ceboyrzf, ohg rnpu bar unf znal fbyhgvbaf
+whfg nabgure vgrz (1.333...) ba bhe erny-ahzorerq gbqb yvfg
+ClCl vf Fuveg Bevtnzv erfrnepu
+<svwny> nafjrevat n dhrfgvba: "ab -- sbe ng yrnfg bar cbffvoyr vagrecergngvba bs lbhe fragrapr"
+eryrnfr 1.2 hcpbzvat
+ClCl 1.2 eryrnfrq - uggc://clcl.bet/
+AB IPF QVFPHFFVBAF
+EClguba vf n svar pnzry unve oehfu
+ClCl vf n npghnyyl n ivfhnyvmngvba cebwrpg, jr whfg ohvyq vagrecergref gb unir vagrerfgvat qngn gb ivfhnyvmr
+clcl vf yvxr fnhfntrf
+naq abj sbe fbzrguvat pbzcyrgryl qvssrerag
+n 10gu bs sberire vf 1u45
+pbeerpg pbqr qbrfag arrq nal grfgf <qhpx>
+cbfgfgehpghenyvfz rgp.
+clcl UVG trarengbe
+gur arj clcl fcbeg vf gb cnff clcl ohtf nf pclguba ohtf
+jr unir zhpu zber vagrecergref guna hfref
+ClCl 1.3 njnvgvat eryrnfr
+ClCl 1.3 eryrnfrq
+vg frrzf gb zr gung bapr lbh frggyr ba na rkrphgvba / bowrpg zbqry naq / be olgrpbqr sbezng, lbh'ir nyernql qrpvqrq jung ynathntrf (jurer gur 'f' frrzf fhcresyhbhf) fhccbeg vf tbvat gb or svefg pynff sbe
+"Nyy ceboyrzf va ClCl pna or fbyirq ol nabgure yriry bs vagrecergngvba"
+ClCl 1.3 eryrnfrq (jvaqbjf ovanevrf vapyhqrq)
+jul qvq lbh thlf unir gb znxr gur ohvygva sbeghar zber vagrerfgvat guna npghny jbex? v whfg pngpurq zlfrys erfgnegvat clcl 20 gvzrf
+"jr hfrq gb unir n zrff jvgu na bofpher vagresnpr, abj jr unir zrff urer naq bofpher vagresnpr gurer. cebterff" crqebavf ba n clcl fcevag
+"phcf bs pbssrr ner yvxr nanybtvrf va gung V'z znxvat bar evtug abj"
+"vg'f nyjnlf hc gb hf, va n jnl be gur bgure"
+ClCl vf infg, naq pbagnvaf zhygvghqrf
+qravny vf eneryl n tbbq qrohttvat grpuavdhr
+"Yrg'f tb." - "Jr pna'g" - "Jul abg?" - "Jr'er jnvgvat sbe n Genafyngvba." - (qrfcnvevatyl) "Nu!"
+'gung'f qrsvavgryl n pnfr bs "hu????"'
+va gurbel gurer vf gur Ybbc, va cenpgvpr gurer ner oevqtrf
+gur uneqqevir - pbafgnag qngn cvytevzntr
+ClCl vf n gbby gb xrrc bgurejvfr qnatrebhf zvaqf fnsryl bpphcvrq.
+jr ner n trareny senzrjbex ohvyg ba pbafvfgrag nccyvpngvba bs nqubp-arff
+gur jnl gb nibvq n jbexnebhaq vf gb vagebqhpr n fgebatre jbexnebhaq fbzrjurer ryfr
+pnyyvat gur genafyngvba gbby punva n 'fpevcg' vf xvaq bs bssrafvir
+ehaavat clcl-p genafyngr.cl vf n ovg yvxr jngpuvat n guevyyre zbivr, vg pbhyq pbafhzr nyy gur zrzbel ng nal gvzr
+ehaavat clcl-p genafyngr.cl vf n ovg yvxr jngpuvat n guevyyre zbivr, vg pbhyq qvr ng nal gvzr orpnhfr bs gur 32-ovg 4TO yvzvg bs ENZ
+Qh jvefg rora tranh qnf reervpura, jbena xrvare tynhog
+vs fjvgmreynaq jrer jurer terrpr vf (ba vfynaqf) jbhyq gurl nyy or pbaarpgrq ol oevqtrf?
+genafyngvat clcl jvgu pclguba vf fbbbbbb fybj
+ClCl 1.4 eryrnfrq!
+Jr ner abg urebrf, whfg irel cngvrag.
+QBAR zrnaf vg'f qbar
+jul gurer vf ab "ClCl 1.4 eryrnfrq" va gbcvp nal zber?
+fabj! fabj!
+svanyyl, zrephevny zvtengvba vf unccravat!
+Gur zvtengvba gb zrephevny vf pbzcyrgrq! uggc://ovgohpxrg.bet/clcl/clcl
+fabj! fabj! (gre)
+unccl arj lrne
+naq anaanaw gb lbh nf jryy
+Frrvat nf gur ynjf bs culfvpf ner ntnvafg lbh, lbh unir gb pnershyyl pbafvqre lbhe fpbcr fb gung lbhe tbnyf ner ernfbanoyr.
+nf hfhny va clcl, gur fbyhgvba nccrnef pbzcyrgryl qvfcebcbegvbangr gb gur ceboyrz naq vafgrnq jr'yy tb sbe n pbzcyrgryl qvssrerag fvzcyre nccebnpu gb gur bevtvany ceboyrz
+fabj, fabj!
+va clcl lbh ner nyjnlf ng gur jebat yriry, va bar jnl be gur bgure
+jryy, vg'f jebat ohg abg fb "irel jebat" nf vg ybbxrq
+<svwny> V ybir clcl
+ynmvarff vzcngvrapr naq uhoevf
+fabj, fabj
+EClguba: guvatf lbh jbhyqa'g qb va Clguba, naq pna'g qb va P.
+vg vf gur rkcrpgrq orunivbe, rkprcg jura lbh qba'g rkcrpg vg
+erqrsvavat lryybj frrzf yvxr n orggre vqrn
+"gung'f ubjrire whfg ratvarrevat" (svwny)
+"[vg] whfg fubjf ntnva gung eclguba vf bofpher" (psobym)
+"naljnl, clguba vf n infg ynathntr" (svwny)
+bhg-bs-yvr-thneqf
+"gurer ner qnlf ba juvpu lbh ybbx nebhaq naq abguvat fubhyq unir rire jbexrq" (svwny)
+clcl vf n orggre xvaq bs sbbyvfuarff - ynp
+ehaavat grfgf vf rffragvny sbe qrirybcvat clcl -- hu? qvq V oernx gur grfg? (svwny)
+V'ir tbg guvf sybbe jnk gung'f nyfb n TERNG qrffreg gbccvat!!
+rknexha: "gur cneg gung V gubhtug jnf tbvat gb or uneq jnf gevivny, fb abj V whfg unir guvf cneg gung V qvqa'g rira guvax bs gung vf uneq"
+V fhccbfr jr pna yvir jvgu gur bofphevgl, nf ybat nf gurer vf n pbzzrag znxvat vg yvtugre
+V nz n ovt oryvrire va ernfbaf. ohg gur nccnerag xvaq ner zl snibevgr.
+clcl: trg n WVG sbe serr (jryy gur svefg qnl lbh jba'g znantr naq vg jvyy or irel sehfgengvat)
+<Nyrk_Tnlabe> thgjbegu: bu, jr fubhyq znxr gur WVG zntvpnyyl orggre, jvgu qrpbengbef naq fghss
+vg'f n pbzcyrgr unpx, ohg n irel zvavzny bar (nevtngb)
+svefg gurl ynhtu ng lbh, gura gurl vtaber lbh, gura gurl svtug lbh, gura lbh jva
+ClCl vf snzvyl sevraqyl
+jr yvxr pbzcynvagf
+gbqnl jr'er snfgre guna lrfgreqnl (hfhnyyl)
+ClCl naq PClguba: gurl ner zbegny rarzvrf vagrag ba xvyyvat rnpu bgure
+nethnoyl, rirelguvat vf n avpur
+clcl unf ynlref yvxr bavbaf: crryvat gurz onpx jvyy znxr lbh pel
+EClguba zntvpnyyl znxrf lbh evpu naq snzbhf (fnlf fb ba gur gva)
+Vf evtbobg nebhaq jura gur havirefr prnfrf gb rkvfg?
+ClCl vf gbb pbby sbe dhrelfgevatf.
+< nevtngb> gura jung bpphef? < svwny> tbbq fghss V oryvrir
+ClCl 1.6 eryrnfrq!
+<psobym> jurer ner gur grfgf?
+uggc://gjvgcvp.pbz/52nr8s
+N enaqbz dhbgr
+Nyy rkprcgoybpxf frrz fnar.
+N cvax tyvggrel ebgngvat ynzoqn
+"vg'f yvxryl grzcbenel hagvy sberire" nevtb
 """
 
 from string import ascii_uppercase, ascii_lowercase
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
@@ -231,7 +231,11 @@
         return ''.join(chars)
 
     def _histline(self, line):
-        return unicode(line.rstrip('\n'), ENCODING)
+        line = line.rstrip('\n')
+        try:
+            return unicode(line, ENCODING)
+        except UnicodeDecodeError:   # bah, silently fall back...
+            return unicode(line, 'utf-8')
 
     def get_history_length(self):
         return self.saved_history_length
@@ -268,7 +272,10 @@
         f = open(os.path.expanduser(filename), 'w')
         for entry in history:
             if isinstance(entry, unicode):
-                entry = entry.encode(ENCODING)
+                try:
+                    entry = entry.encode(ENCODING)
+                except UnicodeEncodeError:   # bah, silently fall back...
+                    entry = entry.encode('utf-8')
             entry = entry.replace('\n', '\r\n')   # multiline history support
             f.write(entry + '\n')
         f.close()
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -98,7 +98,7 @@
 
 module_import_dependencies = {
     # no _rawffi if importing pypy.rlib.clibffi raises ImportError
-    # or CompilationError
+    # or CompilationError or py.test.skip.Exception
     "_rawffi"   : ["pypy.rlib.clibffi"],
     "_ffi"      : ["pypy.rlib.clibffi"],
 
@@ -119,7 +119,7 @@
             try:
                 for name in modlist:
                     __import__(name)
-            except (ImportError, CompilationError), e:
+            except (ImportError, CompilationError, py.test.skip.Exception), e:
                 errcls = e.__class__.__name__
                 config.add_warning(
                     "The module %r is disabled\n" % (modname,) +
diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst
--- a/pypy/doc/project-ideas.rst
+++ b/pypy/doc/project-ideas.rst
@@ -17,6 +17,12 @@
 projects, or anything else in PyPy, pop up on IRC or write to us on the
 `mailing list`_.
 
+Make big integers faster
+-------------------------
+
+PyPy's implementation of the Python ``long`` type is slower than CPython's.
+Find out why and optimize them.
+
 Numpy improvements
 ------------------
 
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -782,22 +782,63 @@
         """Unpack an iterable object into a real (interpreter-level) list.
         Raise an OperationError(w_ValueError) if the length is wrong."""
         w_iterator = self.iter(w_iterable)
-        # If we know the expected length we can preallocate.
         if expected_length == -1:
+            # xxx special hack for speed
+            from pypy.interpreter.generator import GeneratorIterator
+            if isinstance(w_iterator, GeneratorIterator):
+                lst_w = []
+                w_iterator.unpack_into(lst_w)
+                return lst_w
+            # /xxx
+            return self._unpackiterable_unknown_length(w_iterator, w_iterable)
+        else:
+            lst_w = self._unpackiterable_known_length(w_iterator,
+                                                      expected_length)
+            return lst_w[:]     # make the resulting list resizable
+
+    @jit.dont_look_inside
+    def _unpackiterable_unknown_length(self, w_iterator, w_iterable):
+        # Unpack a variable-size list of unknown length.
+        # The JIT does not look inside this function because it
+        # contains a loop (made explicit with the decorator above).
+        #
+        # If we can guess the expected length we can preallocate.
+        try:
+            lgt_estimate = self.len_w(w_iterable)
+        except OperationError, o:
+            if (not o.match(self, self.w_AttributeError) and
+                not o.match(self, self.w_TypeError)):
+                raise
+            items = []
+        else:
             try:
-                lgt_estimate = self.len_w(w_iterable)
-            except OperationError, o:
-                if (not o.match(self, self.w_AttributeError) and
-                    not o.match(self, self.w_TypeError)):
+                items = newlist(lgt_estimate)
+            except MemoryError:
+                items = [] # it might have lied
+        #
+        while True:
+            try:
+                w_item = self.next(w_iterator)
+            except OperationError, e:
+                if not e.match(self, self.w_StopIteration):
                     raise
-                items = []
-            else:
-                try:
-                    items = newlist(lgt_estimate)
-                except MemoryError:
-                    items = [] # it might have lied
-        else:
-            items = [None] * expected_length
+                break  # done
+            items.append(w_item)
+        #
+        return items
+
+    @jit.dont_look_inside
+    def _unpackiterable_known_length(self, w_iterator, expected_length):
+        # Unpack a known length list, without letting the JIT look inside.
+        # Implemented by just calling the @jit.unroll_safe version, but
+        # the JIT stopped looking inside already.
+        return self._unpackiterable_known_length_jitlook(w_iterator,
+                                                         expected_length)
+
+    @jit.unroll_safe
+    def _unpackiterable_known_length_jitlook(self, w_iterator,
+                                             expected_length):
+        items = [None] * expected_length
         idx = 0
         while True:
             try:
@@ -806,26 +847,29 @@
                 if not e.match(self, self.w_StopIteration):
                     raise
                 break  # done
-            if expected_length != -1 and idx == expected_length:
+            if idx == expected_length:
                 raise OperationError(self.w_ValueError,
-                                     self.wrap("too many values to unpack"))
-            if expected_length == -1:
-                items.append(w_item)
-            else:
-                items[idx] = w_item
+                                    self.wrap("too many values to unpack"))
+            items[idx] = w_item
             idx += 1
-        if expected_length != -1 and idx < expected_length:
+        if idx < expected_length:
             if idx == 1:
                 plural = ""
             else:
                 plural = "s"
-            raise OperationError(self.w_ValueError,
-                      self.wrap("need more than %d value%s to unpack" %
-                                (idx, plural)))
+            raise operationerrfmt(self.w_ValueError,
+                                  "need more than %d value%s to unpack",
+                                  idx, plural)
         return items
 
-    unpackiterable_unroll = jit.unroll_safe(func_with_new_name(unpackiterable,
-                                            'unpackiterable_unroll'))
+    def unpackiterable_unroll(self, w_iterable, expected_length):
+        # Like unpackiterable(), but for the cases where we have
+        # an expected_length and want to unroll when JITted.
+        # Returns a fixed-size list.
+        w_iterator = self.iter(w_iterable)
+        assert expected_length != -1
+        return self._unpackiterable_known_length_jitlook(w_iterator,
+                                                         expected_length)
 
     def fixedview(self, w_iterable, expected_length=-1):
         """ A fixed list view of w_iterable. Don't modify the result
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -8,7 +8,7 @@
 class GeneratorIterator(Wrappable):
     "An iterator created by a generator."
     _immutable_fields_ = ['pycode']
-    
+
     def __init__(self, frame):
         self.space = frame.space
         self.frame = frame     # turned into None when frame_finished_execution
@@ -81,7 +81,7 @@
             # if the frame is now marked as finished, it was RETURNed from
             if frame.frame_finished_execution:
                 self.frame = None
-                raise OperationError(space.w_StopIteration, space.w_None) 
+                raise OperationError(space.w_StopIteration, space.w_None)
             else:
                 return w_result     # YIELDed
         finally:
@@ -97,21 +97,21 @@
     def throw(self, w_type, w_val, w_tb):
         from pypy.interpreter.pytraceback import check_traceback
         space = self.space
-        
+
         msg = "throw() third argument must be a traceback object"
         if space.is_w(w_tb, space.w_None):
             tb = None
         else:
             tb = check_traceback(space, w_tb, msg)
-       
+
         operr = OperationError(w_type, w_val, tb)
         operr.normalize_exception(space)
         return self.send_ex(space.w_None, operr)
-             
+
     def descr_next(self):
         """x.next() -> the next value, or raise StopIteration"""
         return self.send_ex(self.space.w_None)
- 
+
     def descr_close(self):
         """x.close(arg) -> raise GeneratorExit inside generator."""
         assert isinstance(self, GeneratorIterator)
@@ -124,7 +124,7 @@
                     e.match(space, space.w_GeneratorExit):
                 return space.w_None
             raise
-        
+
         if w_retval is not None:
             msg = "generator ignored GeneratorExit"
             raise OperationError(space.w_RuntimeError, space.wrap(msg))
@@ -155,3 +155,39 @@
                                                  "interrupting generator of ")
                     break
                 block = block.previous
+
+    def unpack_into(self, results_w):
+        """This is a hack for performance: runs the generator and collects
+        all produced items in a list."""
+        # XXX copied and simplified version of send_ex()
+        space = self.space
+        if self.running:
+            raise OperationError(space.w_ValueError,
+                                 space.wrap('generator already executing'))
+        frame = self.frame
+        if frame is None:    # already finished
+            return
+        self.running = True
+        try:
+            pycode = self.pycode
+            while True:
+                jitdriver.jit_merge_point(self=self, frame=frame,
+                                          results_w=results_w,
+                                          pycode=pycode)
+                try:
+                    w_result = frame.execute_frame(space.w_None)
+                except OperationError, e:
+                    if not e.match(space, space.w_StopIteration):
+                        raise
+                    break
+                # if the frame is now marked as finished, it was RETURNed from
+                if frame.frame_finished_execution:
+                    break
+                results_w.append(w_result)     # YIELDed
+        finally:
+            frame.f_backref = jit.vref_None
+            self.running = False
+            self.frame = None
+
+jitdriver = jit.JitDriver(greens=['pycode'],
+                          reds=['self', 'frame', 'results_w'])
diff --git a/pypy/interpreter/test/test_generator.py b/pypy/interpreter/test/test_generator.py
--- a/pypy/interpreter/test/test_generator.py
+++ b/pypy/interpreter/test/test_generator.py
@@ -117,7 +117,7 @@
         g = f()
         raises(NameError, g.throw, NameError, "Error", None)
 
-    
+
     def test_throw_fail(self):
         def f():
             yield 1
@@ -129,7 +129,7 @@
             yield 1
         g = f()
         raises(TypeError, g.throw, list())
- 
+
     def test_throw_fail3(self):
         def f():
             yield 1
@@ -188,7 +188,7 @@
         g = f()
         g.next()
         raises(NameError, g.close)
- 
+
     def test_close_fail(self):
         def f():
             try:
@@ -267,3 +267,15 @@
         assert r.startswith("<generator object myFunc at 0x")
         assert list(g) == [1]
         assert repr(g) == r
+
+    def test_unpackiterable_gen(self):
+        g = (i*i for i in range(-5, 3))
+        assert set(g) == set([0, 1, 4, 9, 16, 25])
+        assert set(g) == set()
+        assert set(i for i in range(0)) == set()
+
+    def test_explicit_stop_iteration_unpackiterable(self):
+        def f():
+            yield 1
+            raise StopIteration
+        assert tuple(f()) == (1,)
\ No newline at end of file
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
@@ -1114,7 +1114,9 @@
     if isinstance(TYPE, lltype.Ptr):
         if isinstance(x, (int, long, llmemory.AddressAsInt)):
             x = llmemory.cast_int_to_adr(x)
-        if TYPE is rffi.VOIDP or TYPE.TO._hints.get("uncast_on_llgraph"):
+        if TYPE is rffi.VOIDP or (
+                hasattr(TYPE.TO, '_hints') and
+                TYPE.TO._hints.get("uncast_on_llgraph")):
             # assume that we want a "C-style" cast, without typechecking the value
             return rffi.cast(TYPE, x)
         return llmemory.cast_adr_to_ptr(x, TYPE)
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
@@ -8,7 +8,7 @@
 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 rop
 from pypy.jit.backend import model
@@ -60,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
 
@@ -362,9 +365,12 @@
 
     def arraydescrof(self, A):
         assert A.OF != lltype.Void
+        assert isinstance(A, lltype.GcArray) or A._hints.get('nolength', False)
         size = symbolic.get_size(A)
         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)
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
@@ -164,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):
@@ -172,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
 
@@ -196,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
@@ -215,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')
@@ -266,6 +281,9 @@
     def is_float_field(self):
         return self.fielddescr.is_float_field()
 
+    def sort_key(self):
+        return self.fielddescr.sort_key()
+
     def repr_of_descr(self):
         return '<InteriorFieldDescr %s>' % self.fielddescr.repr_of_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
@@ -649,10 +649,13 @@
         def malloc_basic(size, tid):
             type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
             has_finalizer = bool(tid & (1<<llgroup.HALFSHIFT))
+            has_light_finalizer = bool(tid & (1<<(llgroup.HALFSHIFT + 1)))
             check_typeid(type_id)
             res = llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
                                                   type_id, size,
-                                                  has_finalizer, False)
+                                                  has_finalizer,
+                                                  has_light_finalizer,
+                                                  False)
             # In case the operation above failed, we are returning NULL
             # from this function to assembler.  There is also an RPython
             # exception set, typically MemoryError; but it's easier and
@@ -723,7 +726,7 @@
             # also use it to allocate varsized objects.  The tid
             # and possibly the length are both set afterward.
             gcref = llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
-                                        0, size, False, False)
+                                        0, size, False, False, False)
             return rffi.cast(lltype.Signed, gcref)
         self.malloc_slowpath = malloc_slowpath
         self.MALLOC_SLOWPATH = lltype.FuncType([lltype.Signed], lltype.Signed)
@@ -747,7 +750,9 @@
         type_id = self.layoutbuilder.get_type_id(S)
         assert not self.layoutbuilder.is_weakref_type(S)
         has_finalizer = bool(self.layoutbuilder.has_finalizer(S))
-        flags = int(has_finalizer) << llgroup.HALFSHIFT
+        has_light_finalizer = bool(self.layoutbuilder.has_light_finalizer(S))
+        flags = (int(has_finalizer) << llgroup.HALFSHIFT |
+                 int(has_light_finalizer) << (llgroup.HALFSHIFT + 1))
         descr.tid = llop.combine_ushort(lltype.Signed, type_id, flags)
 
     def init_array_descr(self, A, descr):
diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py
--- a/pypy/jit/backend/llsupport/test/test_gc.py
+++ b/pypy/jit/backend/llsupport/test/test_gc.py
@@ -247,12 +247,14 @@
         self.record = []
 
     def do_malloc_fixedsize_clear(self, RESTYPE, type_id, size,
-                                  has_finalizer, contains_weakptr):
+                                  has_finalizer, has_light_finalizer,
+                                  contains_weakptr):
         assert not contains_weakptr
+        assert not has_finalizer           # in these tests
+        assert not has_light_finalizer     # in these tests
         p = llmemory.raw_malloc(size)
         p = llmemory.cast_adr_to_ptr(p, RESTYPE)
-        flags = int(has_finalizer) << 16
-        tid = llop.combine_ushort(lltype.Signed, type_id, flags)
+        tid = llop.combine_ushort(lltype.Signed, type_id, 0)
         self.record.append(("fixedsize", repr(size), tid, p))
         return p
 
diff --git a/pypy/jit/backend/test/test_ll_random.py b/pypy/jit/backend/test/test_ll_random.py
--- a/pypy/jit/backend/test/test_ll_random.py
+++ b/pypy/jit/backend/test/test_ll_random.py
@@ -28,16 +28,27 @@
         fork.structure_types_and_vtables = self.structure_types_and_vtables
         return fork
 
-    def get_structptr_var(self, r, must_have_vtable=False, type=lltype.Struct):
+    def _choose_ptr_vars(self, from_, type, array_of_structs):
+        ptrvars = []
+        for i in range(len(from_)):
+            v, S = from_[i][:2]
+            if not isinstance(S, type):
+                continue
+            if ((isinstance(S, lltype.Array) and
+                 isinstance(S.OF, lltype.Struct)) == array_of_structs):
+                ptrvars.append((v, S))
+        return ptrvars
+
+    def get_structptr_var(self, r, must_have_vtable=False, type=lltype.Struct,
+                          array_of_structs=False):
         while True:
-            ptrvars = [(v, S) for (v, S) in self.ptrvars
-                              if isinstance(S, type)]
+            ptrvars = self._choose_ptr_vars(self.ptrvars, type,
+                                            array_of_structs)
             if ptrvars and r.random() < 0.8:
                 v, S = r.choice(ptrvars)
             else:
-                prebuilt_ptr_consts = [(v, S)
-                                 for (v, S, _) in self.prebuilt_ptr_consts
-                                 if isinstance(S, type)]
+                prebuilt_ptr_consts = self._choose_ptr_vars(
+                    self.prebuilt_ptr_consts, type, array_of_structs)
                 if prebuilt_ptr_consts and r.random() < 0.7:
                     v, S = r.choice(prebuilt_ptr_consts)
                 else:
@@ -48,7 +59,8 @@
                                                 has_vtable=must_have_vtable)
                     else:
                         # create a new constant array
-                        p = self.get_random_array(r)
+                        p = self.get_random_array(r,
+                                    must_be_array_of_structs=array_of_structs)
                     S = lltype.typeOf(p).TO
                     v = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, p))
                     self.prebuilt_ptr_consts.append((v, S,
@@ -74,7 +86,8 @@
                 TYPE = lltype.Signed
         return TYPE
 
-    def get_random_structure_type(self, r, with_vtable=None, cache=True):
+    def get_random_structure_type(self, r, with_vtable=None, cache=True,
+                                  type=lltype.GcStruct):
         if cache and self.structure_types and r.random() < 0.5:
             return r.choice(self.structure_types)
         fields = []
@@ -85,7 +98,7 @@
         for i in range(r.randrange(1, 5)):
             TYPE = self.get_random_primitive_type(r)
             fields.append(('f%d' % i, TYPE))
-        S = lltype.GcStruct('S%d' % self.counter, *fields, **kwds)
+        S = type('S%d' % self.counter, *fields, **kwds)
         self.counter += 1
         if cache:
             self.structure_types.append(S)
@@ -125,17 +138,29 @@
                 setattr(p, fieldname, rffi.cast(TYPE, r.random_integer()))
         return p
 
-    def get_random_array_type(self, r):
-        TYPE = self.get_random_primitive_type(r)
+    def get_random_array_type(self, r, can_be_array_of_struct=False,
+                              must_be_array_of_structs=False):
+        if ((can_be_array_of_struct and r.random() < 0.1) or
+            must_be_array_of_structs):
+            TYPE = self.get_random_structure_type(r, cache=False,
+                                                  type=lltype.Struct)
+        else:
+            TYPE = self.get_random_primitive_type(r)
         return lltype.GcArray(TYPE)
 
-    def get_random_array(self, r):
-        A = self.get_random_array_type(r)
+    def get_random_array(self, r, must_be_array_of_structs=False):
+        A = self.get_random_array_type(r,
+                           must_be_array_of_structs=must_be_array_of_structs)
         length = (r.random_integer() // 15) % 300  # length: between 0 and 299
                                                    # likely to be small
         p = lltype.malloc(A, length)
-        for i in range(length):
-            p[i] = rffi.cast(A.OF, r.random_integer())
+        if isinstance(A.OF, lltype.Primitive):
+            for i in range(length):
+                p[i] = rffi.cast(A.OF, r.random_integer())
+        else:
+            for i in range(length):
+                for fname, TP in A.OF._flds.iteritems():
+                    setattr(p[i], fname, rffi.cast(TP, r.random_integer()))
         return p
 
     def get_index(self, length, r):
@@ -155,8 +180,16 @@
                     dic[fieldname] = getattr(p, fieldname)
         else:
             assert isinstance(S, lltype.Array)
-            for i in range(len(p)):
-                dic[i] = p[i]
+            if isinstance(S.OF, lltype.Struct):
+                for i in range(len(p)):
+                    item = p[i]
+                    s1 = {}
+                    for fieldname in S.OF._names:
+                        s1[fieldname] = getattr(item, fieldname)
+                    dic[i] = s1
+            else:
+                for i in range(len(p)):
+                    dic[i] = p[i]
         return dic
 
     def print_loop_prebuilt(self, names, writevar, s):
@@ -220,7 +253,7 @@
 
 class GetFieldOperation(test_random.AbstractOperation):
     def field_descr(self, builder, r):
-        v, S = builder.get_structptr_var(r)
+        v, S = builder.get_structptr_var(r, )
         names = S._names
         if names[0] == 'parent':
             names = names[1:]
@@ -239,6 +272,28 @@
                 continue
             break
 
+class GetInteriorFieldOperation(test_random.AbstractOperation):
+    def field_descr(self, builder, r):
+        v, A = builder.get_structptr_var(r, type=lltype.Array,
+                                         array_of_structs=True)
+        array = v.getref(lltype.Ptr(A))
+        v_index = builder.get_index(len(array), r)
+        name = r.choice(A.OF._names)
+        descr = builder.cpu.interiorfielddescrof(A, name)
+        descr._random_info = 'cpu.interiorfielddescrof(%s, %r)' % (A.OF._name,
+                                                                   name)
+        TYPE = getattr(A.OF, name)
+        return v, v_index, descr, TYPE
+
+    def produce_into(self, builder, r):
+        while True:
+            try:
+                v, v_index, descr, _ = self.field_descr(builder, r)
+                self.put(builder, [v, v_index], descr)
+            except lltype.UninitializedMemoryAccess:
+                continue
+            break
+
 class SetFieldOperation(GetFieldOperation):
     def produce_into(self, builder, r):
         v, descr, TYPE = self.field_descr(builder, r)
@@ -251,6 +306,18 @@
                 break
         builder.do(self.opnum, [v, w], descr)
 
+class SetInteriorFieldOperation(GetInteriorFieldOperation):
+    def produce_into(self, builder, r):
+        v, v_index, descr, TYPE = self.field_descr(builder, r)
+        while True:
+            if r.random() < 0.3:
+                w = ConstInt(r.random_integer())
+            else:
+                w = r.choice(builder.intvars)
+            if rffi.cast(lltype.Signed, rffi.cast(TYPE, w.value)) == w.value:
+                break
+        builder.do(self.opnum, [v, v_index, w], descr)
+
 class NewOperation(test_random.AbstractOperation):
     def size_descr(self, builder, S):
         descr = builder.cpu.sizeof(S)
@@ -306,7 +373,7 @@
 
 class NewArrayOperation(ArrayOperation):
     def produce_into(self, builder, r):
-        A = builder.get_random_array_type(r)
+        A = builder.get_random_array_type(r, can_be_array_of_struct=True)
         v_size = builder.get_index(300, r)
         v_ptr = builder.do(self.opnum, [v_size], self.array_descr(builder, A))
         builder.ptrvars.append((v_ptr, A))
@@ -586,7 +653,9 @@
 for i in range(4):      # make more common
     OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC))
     OPERATIONS.append(GetFieldOperation(rop.GETFIELD_GC))
+    OPERATIONS.append(GetInteriorFieldOperation(rop.GETINTERIORFIELD_GC))
     OPERATIONS.append(SetFieldOperation(rop.SETFIELD_GC))
+    OPERATIONS.append(SetInteriorFieldOperation(rop.SETINTERIORFIELD_GC))
     OPERATIONS.append(NewOperation(rop.NEW))
     OPERATIONS.append(NewOperation(rop.NEW_WITH_VTABLE))
 
diff --git a/pypy/jit/backend/test/test_random.py b/pypy/jit/backend/test/test_random.py
--- a/pypy/jit/backend/test/test_random.py
+++ b/pypy/jit/backend/test/test_random.py
@@ -595,6 +595,10 @@
             for name, value in fields.items():
                 if isinstance(name, str):
                     setattr(container, name, value)
+                elif isinstance(value, dict):
+                    item = container.getitem(name)
+                    for key1, value1 in value.items():
+                        setattr(item, key1, value1)
                 else:
                     container.setitem(name, value)
 
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
@@ -1276,8 +1276,8 @@
     genop_int_ne = _cmpop("NE", "NE")
     genop_int_gt = _cmpop("G", "L")
     genop_int_ge = _cmpop("GE", "LE")
-    genop_ptr_eq = genop_int_eq
-    genop_ptr_ne = genop_int_ne
+    genop_ptr_eq = genop_instance_ptr_eq = genop_int_eq
+    genop_ptr_ne = genop_instance_ptr_ne = genop_int_ne
 
     genop_float_lt = _cmpop_float('B', 'A')
     genop_float_le = _cmpop_float('BE', 'AE')
@@ -1297,8 +1297,8 @@
     genop_guard_int_ne = _cmpop_guard("NE", "NE", "E", "E")
     genop_guard_int_gt = _cmpop_guard("G", "L", "LE", "GE")
     genop_guard_int_ge = _cmpop_guard("GE", "LE", "L", "G")
-    genop_guard_ptr_eq = genop_guard_int_eq
-    genop_guard_ptr_ne = genop_guard_int_ne
+    genop_guard_ptr_eq = genop_guard_instance_ptr_eq = genop_guard_int_eq
+    genop_guard_ptr_ne = genop_guard_instance_ptr_ne = genop_guard_int_ne
 
     genop_guard_uint_gt = _cmpop_guard("A", "B", "BE", "AE")
     genop_guard_uint_lt = _cmpop_guard("B", "A", "AE", "BE")
@@ -1596,11 +1596,27 @@
     genop_getarrayitem_gc_pure = genop_getarrayitem_gc
     genop_getarrayitem_raw = genop_getarrayitem_gc
 
+    def _get_interiorfield_addr(self, temp_loc, index_loc, itemsize_loc,
+                                base_loc, ofs_loc):
+        assert isinstance(itemsize_loc, ImmedLoc)
+        if isinstance(index_loc, ImmedLoc):
+            temp_loc = imm(index_loc.value * itemsize_loc.value)
+        else:
+            # XXX should not use IMUL in most cases
+            assert isinstance(temp_loc, RegLoc)
+            assert isinstance(index_loc, RegLoc)
+            assert not temp_loc.is_xmm
+            self.mc.IMUL_rri(temp_loc.value, index_loc.value,
+                             itemsize_loc.value)
+        assert isinstance(ofs_loc, ImmedLoc)
+        return AddressLoc(base_loc, temp_loc, 0, ofs_loc.value)
+
     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)
+        (base_loc, ofs_loc, itemsize_loc, fieldsize_loc,
+            index_loc, temp_loc, sign_loc) = arglocs
+        src_addr = self._get_interiorfield_addr(temp_loc, index_loc,
+                                                itemsize_loc, base_loc,
+                                                ofs_loc)
         self.load_from_mem(resloc, src_addr, fieldsize_loc, sign_loc)
 
 
@@ -1611,10 +1627,11 @@
         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)
+        (base_loc, ofs_loc, itemsize_loc, fieldsize_loc,
+            index_loc, temp_loc, value_loc) = arglocs
+        dest_addr = self._get_interiorfield_addr(temp_loc, index_loc,
+                                                 itemsize_loc, base_loc,
+                                                 ofs_loc)
         self.save_into_mem(dest_addr, value_loc, fieldsize_loc)
 
     def genop_discard_setarrayitem_gc(self, op, arglocs):
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
@@ -651,8 +651,8 @@
     consider_uint_lt = _consider_compop
     consider_uint_le = _consider_compop
     consider_uint_ge = _consider_compop
-    consider_ptr_eq = _consider_compop
-    consider_ptr_ne = _consider_compop
+    consider_ptr_eq = consider_instance_ptr_eq = _consider_compop
+    consider_ptr_ne = consider_instance_ptr_ne = _consider_compop
 
     def _consider_float_op(self, op):
         loc1 = self.xrm.loc(op.getarg(1))
@@ -1042,16 +1042,30 @@
         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)
+        if fieldsize.value == 1:
+            need_lower_byte = True
+        else:
+            need_lower_byte = False
+        box_base, box_index, box_value = args
+        base_loc = self.rm.make_sure_var_in_reg(box_base, args)
+        index_loc = self.rm.make_sure_var_in_reg(box_index, args)
+        value_loc = self.make_sure_var_in_reg(box_value, args,
+                                              need_lower_byte=need_lower_byte)
+        # If 'index_loc' is not an immediate, then we need a 'temp_loc' that
+        # is a register whose value will be destroyed.  It's fine to destroy
+        # the same register as 'index_loc', but not the other ones.
+        self.rm.possibly_free_var(box_index)
+        if not isinstance(index_loc, ImmedLoc):
+            tempvar = TempBox()
+            temp_loc = self.rm.force_allocate_reg(tempvar, [box_base,
+                                                            box_value])
+            self.rm.possibly_free_var(tempvar)
+        else:
+            temp_loc = None
+        self.rm.possibly_free_var(box_base)
+        self.possibly_free_var(box_value)
         self.PerformDiscard(op, [base_loc, ofs, itemsize, fieldsize,
-                                 index_loc, value_loc])
+                                 index_loc, temp_loc, value_loc])
 
     def consider_strsetitem(self, op):
         args = op.getarglist()
@@ -1122,15 +1136,27 @@
         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)
+        index_loc = self.rm.make_sure_var_in_reg(op.getarg(1), args)
+        # 'base' and 'index' are put in two registers (or one if 'index'
+        # is an immediate).  'result' can be in the same register as
+        # 'index' but must be in a different register than 'base'.
+        self.rm.possibly_free_var(op.getarg(1))
+        result_loc = self.force_allocate_reg(op.result, [op.getarg(0)])
+        assert isinstance(result_loc, RegLoc)
+        # two cases: 1) if result_loc is a normal register, use it as temp_loc
+        if not result_loc.is_xmm:
+            temp_loc = result_loc
+        else:
+            # 2) if result_loc is an xmm register, we (likely) need another
+            # temp_loc that is a normal register.  It can be in the same
+            # register as 'index' but not 'base'.
+            tempvar = TempBox()
+            temp_loc = self.rm.force_allocate_reg(tempvar, [op.getarg(0)])
+            self.rm.possibly_free_var(tempvar)
+        self.rm.possibly_free_var(op.getarg(0))
         self.Perform(op, [base_loc, ofs, itemsize, fieldsize,
-                          index_loc, sign_loc], result_loc)
+                          index_loc, temp_loc, sign_loc], result_loc)
 
     def consider_int_is_true(self, op, guard_op):
         # doesn't need arg to be in a register
diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py
--- a/pypy/jit/backend/x86/regloc.py
+++ b/pypy/jit/backend/x86/regloc.py
@@ -17,7 +17,7 @@
 
 class AssemblerLocation(object):
     # XXX: Is adding "width" here correct?
-    __slots__ = ('value', 'width')
+    _attrs_ = ('value', 'width', '_location_code')
     _immutable_ = True
     def _getregkey(self):
         return self.value
@@ -25,6 +25,9 @@
     def is_memory_reference(self):
         return self.location_code() in ('b', 's', 'j', 'a', 'm')
 
+    def location_code(self):
+        return self._location_code
+
     def value_r(self): return self.value
     def value_b(self): return self.value
     def value_s(self): return self.value
@@ -38,6 +41,8 @@
 
 class StackLoc(AssemblerLocation):
     _immutable_ = True
+    _location_code = 'b'
+
     def __init__(self, position, ebp_offset, num_words, type):
         assert ebp_offset < 0   # so no confusion with RegLoc.value
         self.position = position
@@ -49,9 +54,6 @@
     def __repr__(self):
         return '%d(%%ebp)' % (self.value,)
 
-    def location_code(self):
-        return 'b'
-
     def assembler(self):
         return repr(self)
 
@@ -63,8 +65,10 @@
         self.is_xmm = is_xmm
         if self.is_xmm:
             self.width = 8
+            self._location_code = 'x'
         else:
             self.width = WORD
+            self._location_code = 'r'
     def __repr__(self):
         if self.is_xmm:
             return rx86.R.xmmnames[self.value]
@@ -79,12 +83,6 @@
         assert not self.is_xmm
         return RegLoc(rx86.high_byte(self.value), False)
 
-    def location_code(self):
-        if self.is_xmm:
-            return 'x'
-        else:
-            return 'r'
-
     def assembler(self):
         return '%' + repr(self)
 
@@ -97,14 +95,13 @@
 class ImmedLoc(AssemblerLocation):
     _immutable_ = True
     width = WORD
+    _location_code = 'i'
+
     def __init__(self, value):
         from pypy.rpython.lltypesystem import rffi, lltype
         # force as a real int
         self.value = rffi.cast(lltype.Signed, value)
 
-    def location_code(self):
-        return 'i'
-
     def getint(self):
         return self.value
 
@@ -149,9 +146,6 @@
         info = getattr(self, attr, '?')
         return '<AddressLoc %r: %s>' % (self._location_code, info)
 
-    def location_code(self):
-        return self._location_code
-
     def value_a(self):
         return self.loc_a
 
@@ -191,6 +185,7 @@
     # we want a width of 8  (... I think.  Check this!)
     _immutable_ = True
     width = 8
+    _location_code = 'j'
 
     def __init__(self, address):
         self.value = address
@@ -198,9 +193,6 @@
     def __repr__(self):
         return '<ConstFloatLoc @%s>' % (self.value,)
 
-    def location_code(self):
-        return 'j'
-
 if IS_X86_32:
     class FloatImmedLoc(AssemblerLocation):
         # This stands for an immediate float.  It cannot be directly used in
@@ -209,6 +201,7 @@
         # instead; see below.
         _immutable_ = True
         width = 8
+        _location_code = '#'     # don't use me
 
         def __init__(self, floatstorage):
             self.aslonglong = floatstorage
@@ -229,9 +222,6 @@
             floatvalue = longlong.getrealfloat(self.aslonglong)
             return '<FloatImmedLoc(%s)>' % (floatvalue,)
 
-        def location_code(self):
-            raise NotImplementedError
-
 if IS_X86_64:
     def FloatImmedLoc(floatstorage):
         from pypy.rlib.longlong2float import float2longlong
@@ -270,6 +260,11 @@
     else:
         raise AssertionError(methname + " undefined")
 
+def _missing_binary_insn(name, code1, code2):
+    raise AssertionError(name + "_" + code1 + code2 + " missing")
+_missing_binary_insn._dont_inline_ = True
+
+
 class LocationCodeBuilder(object):
     _mixin_ = True
 
@@ -303,6 +298,8 @@
             else:
                 # For this case, we should not need the scratch register more than here.
                 self._load_scratch(val2)
+                if name == 'MOV' and loc1 is X86_64_SCRATCH_REG:
+                    return     # don't need a dummy "MOV r11, r11"
                 INSN(self, loc1, X86_64_SCRATCH_REG)
 
         def invoke(self, codes, val1, val2):
@@ -310,6 +307,23 @@
             _rx86_getattr(self, methname)(val1, val2)
         invoke._annspecialcase_ = 'specialize:arg(1)'
 
+        def has_implementation_for(loc1, loc2):
+            # A memo function that returns True if there is any NAME_xy that could match.
+            # If it returns False we know the whole subcase can be omitted from translated
+            # code.  Without this hack, the size of most _binaryop INSN functions ends up
+            # quite large in C code.
+            if loc1 == '?':
+                return any([has_implementation_for(loc1, loc2)
+                            for loc1 in unrolling_location_codes])
+            methname = name + "_" + loc1 + loc2
+            if not hasattr(rx86.AbstractX86CodeBuilder, methname):
+                return False
+            # any NAME_j should have a NAME_m as a fallback, too.  Check it
+            if loc1 == 'j': assert has_implementation_for('m', loc2), methname
+            if loc2 == 'j': assert has_implementation_for(loc1, 'm'), methname
+            return True
+        has_implementation_for._annspecialcase_ = 'specialize:memo'
+
         def INSN(self, loc1, loc2):
             code1 = loc1.location_code()
             code2 = loc2.location_code()
@@ -325,6 +339,8 @@
                 assert code2 not in ('j', 'i')
 
             for possible_code2 in unrolling_location_codes:
+                if not has_implementation_for('?', possible_code2):
+                    continue
                 if code2 == possible_code2:
                     val2 = getattr(loc2, "value_" + possible_code2)()
                     #
@@ -335,28 +351,32 @@
                     #
                     # Regular case
                     for possible_code1 in unrolling_location_codes:
+                        if not has_implementation_for(possible_code1,
+                                                      possible_code2):
+                            continue
                         if code1 == possible_code1:
                             val1 = getattr(loc1, "value_" + possible_code1)()
                             # More faking out of certain operations for x86_64
-                            if possible_code1 == 'j' and not rx86.fits_in_32bits(val1):
+                            fits32 = rx86.fits_in_32bits
+                            if possible_code1 == 'j' and not fits32(val1):
                                 val1 = self._addr_as_reg_offset(val1)
                                 invoke(self, "m" + possible_code2, val1, val2)
-                            elif possible_code2 == 'j' and not rx86.fits_in_32bits(val2):
+                                return
+                            if possible_code2 == 'j' and not fits32(val2):
                                 val2 = self._addr_as_reg_offset(val2)
                                 invoke(self, possible_code1 + "m", val1, val2)
-                            elif possible_code1 == 'm' and not rx86.fits_in_32bits(val1[1]):
+                                return
+                            if possible_code1 == 'm' and not fits32(val1[1]):
                                 val1 = self._fix_static_offset_64_m(val1)
-                                invoke(self, "a" + possible_code2, val1, val2)
-                            elif possible_code2 == 'm' and not rx86.fits_in_32bits(val2[1]):
+                            if possible_code2 == 'm' and not fits32(val2[1]):
                                 val2 = self._fix_static_offset_64_m(val2)
-                                invoke(self, possible_code1 + "a", val1, val2)
-                            else:
-                                if possible_code1 == 'a' and not rx86.fits_in_32bits(val1[3]):
-                                    val1 = self._fix_static_offset_64_a(val1)
-                                if possible_code2 == 'a' and not rx86.fits_in_32bits(val2[3]):
-                                    val2 = self._fix_static_offset_64_a(val2)
-                                invoke(self, possible_code1 + possible_code2, val1, val2)
+                            if possible_code1 == 'a' and not fits32(val1[3]):
+                                val1 = self._fix_static_offset_64_a(val1)
+                            if possible_code2 == 'a' and not fits32(val2[3]):
+                                val2 = self._fix_static_offset_64_a(val2)
+                            invoke(self, possible_code1 + possible_code2, val1, val2)
                             return
+            _missing_binary_insn(name, code1, code2)
 
         return func_with_new_name(INSN, "INSN_" + name)
 
@@ -431,12 +451,14 @@
     def _fix_static_offset_64_m(self, (basereg, static_offset)):
         # For cases where an AddressLoc has the location_code 'm', but
         # where the static offset does not fit in 32-bits.  We have to fall
-        # back to the X86_64_SCRATCH_REG.  Note that this returns a location
-        # encoded as mode 'a'.  These are all possibly rare cases; don't try
+        # back to the X86_64_SCRATCH_REG.  Returns a new location encoded
+        # as mode 'm' too.  These are all possibly rare cases; don't try
         # to reuse a past value of the scratch register at all.
         self._scratch_register_known = False
         self.MOV_ri(X86_64_SCRATCH_REG.value, static_offset)
-        return (basereg, X86_64_SCRATCH_REG.value, 0, 0)
+        self.LEA_ra(X86_64_SCRATCH_REG.value,
+                    (basereg, X86_64_SCRATCH_REG.value, 0, 0))
+        return (X86_64_SCRATCH_REG.value, 0)
 
     def _fix_static_offset_64_a(self, (basereg, scalereg,
                                        scale, static_offset)):
diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py
--- a/pypy/jit/backend/x86/rx86.py
+++ b/pypy/jit/backend/x86/rx86.py
@@ -745,6 +745,7 @@
     assert insnname_template.count('*') == 1
     add_insn('x', register(2), '\xC0')
     add_insn('j', abs_, immediate(2))
+    add_insn('m', mem_reg_plus_const(2))
 
 define_pxmm_insn('PADDQ_x*',     '\xD4')
 define_pxmm_insn('PSUBQ_x*',     '\xFB')
diff --git a/pypy/jit/backend/x86/test/test_regloc.py b/pypy/jit/backend/x86/test/test_regloc.py
--- a/pypy/jit/backend/x86/test/test_regloc.py
+++ b/pypy/jit/backend/x86/test/test_regloc.py
@@ -146,8 +146,10 @@
         expected_instructions = (
                 # mov r11, 0xFEDCBA9876543210
                 '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
-                # mov rcx, [rdx+r11]
-                '\x4A\x8B\x0C\x1A'
+                # lea r11, [rdx+r11]
+                '\x4E\x8D\x1C\x1A'
+                # mov rcx, [r11]
+                '\x49\x8B\x0B'
         )
         assert cb.getvalue() == expected_instructions
 
@@ -174,6 +176,30 @@
 
     # ------------------------------------------------------------
 
+    def test_MOV_64bit_constant_into_r11(self):
+        base_constant = 0xFEDCBA9876543210
+        cb = LocationCodeBuilder64()
+        cb.MOV(r11, imm(base_constant))
+
+        expected_instructions = (
+                # mov r11, 0xFEDCBA9876543210
+                '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
+        )
+        assert cb.getvalue() == expected_instructions
+
+    def test_MOV_64bit_address_into_r11(self):
+        base_addr = 0xFEDCBA9876543210
+        cb = LocationCodeBuilder64()
+        cb.MOV(r11, heap(base_addr))
+
+        expected_instructions = (
+                # mov r11, 0xFEDCBA9876543210
+                '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE' +
+                # mov r11, [r11]
+                '\x4D\x8B\x1B'
+        )
+        assert cb.getvalue() == expected_instructions
+
     def test_MOV_immed32_into_64bit_address_1(self):
         immed = -0x01234567
         base_addr = 0xFEDCBA9876543210
@@ -217,8 +243,10 @@
         expected_instructions = (
                 # mov r11, 0xFEDCBA9876543210
                 '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
-                # mov [rdx+r11], -0x01234567
-                '\x4A\xC7\x04\x1A\x99\xBA\xDC\xFE'
+                # lea r11, [rdx+r11]
+                '\x4E\x8D\x1C\x1A'
+                # mov [r11], -0x01234567
+                '\x49\xC7\x03\x99\xBA\xDC\xFE'
         )
         assert cb.getvalue() == expected_instructions
 
@@ -300,8 +328,10 @@
                 '\x48\xBA\xEF\xCD\xAB\x89\x67\x45\x23\x01'
                 # mov r11, 0xFEDCBA9876543210
                 '\x49\xBB\x10\x32\x54\x76\x98\xBA\xDC\xFE'
-                # mov [rax+r11], rdx
-                '\x4A\x89\x14\x18'
+                # lea r11, [rax+r11]
+                '\x4E\x8D\x1C\x18'
+                # mov [r11], rdx
+                '\x49\x89\x13'
                 # pop rdx
                 '\x5A'
         )
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
@@ -58,7 +58,7 @@
     assert not p.returncode, ('Encountered an error running objdump: %s' %
                               stderr)
     # drop some objdump cruft
-    lines = stdout.splitlines()[6:]
+    lines = stdout.splitlines(True)[6:]     # drop some objdump cruft
     return format_code_dump_with_labels(originaddr, lines, label_list)
 
 def format_code_dump_with_labels(originaddr, lines, label_list):
@@ -97,7 +97,7 @@
     stdout, stderr = p.communicate()
     assert not p.returncode, ('Encountered an error running nm: %s' %
                               stderr)
-    for line in stdout.splitlines():
+    for line in stdout.splitlines(True):
         match = re_symbolentry.match(line)
         if match:
             addr = long(match.group(1), 16)
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
@@ -443,6 +443,8 @@
     rewrite_op_gc_identityhash = _do_builtin_call
     rewrite_op_gc_id           = _do_builtin_call
     rewrite_op_uint_mod        = _do_builtin_call
+    rewrite_op_cast_float_to_uint = _do_builtin_call
+    rewrite_op_cast_uint_to_float = _do_builtin_call
 
     # ----------
     # getfield/setfield/mallocs etc.
@@ -798,6 +800,9 @@
     def _is_gc(self, v):
         return getattr(getattr(v.concretetype, "TO", None), "_gckind", "?") == 'gc'
 
+    def _is_rclass_instance(self, v):
+        return lltype._castdepth(v.concretetype.TO, rclass.OBJECT) >= 0
+
     def _rewrite_cmp_ptrs(self, op):
         if self._is_gc(op.args[0]):
             return op
@@ -815,11 +820,21 @@
         return self._rewrite_equality(op, 'int_is_true')
 
     def rewrite_op_ptr_eq(self, op):
-        op1 = self._rewrite_equality(op, 'ptr_iszero')
+        prefix = ''
+        if self._is_rclass_instance(op.args[0]):
+            assert self._is_rclass_instance(op.args[1])
+            op = SpaceOperation('instance_ptr_eq', op.args, op.result)
+            prefix = 'instance_'
+        op1 = self._rewrite_equality(op, prefix + 'ptr_iszero')
         return self._rewrite_cmp_ptrs(op1)
 
     def rewrite_op_ptr_ne(self, op):
-        op1 = self._rewrite_equality(op, 'ptr_nonzero')
+        prefix = ''
+        if self._is_rclass_instance(op.args[0]):
+            assert self._is_rclass_instance(op.args[1])
+            op = SpaceOperation('instance_ptr_ne', op.args, op.result)
+            prefix = 'instance_'
+        op1 = self._rewrite_equality(op, prefix + 'ptr_nonzero')
         return self._rewrite_cmp_ptrs(op1)
 
     rewrite_op_ptr_iszero = _rewrite_cmp_ptrs
@@ -829,6 +844,10 @@
         if self._is_gc(op.args[0]):
             return op
 
+    def rewrite_op_cast_opaque_ptr(self, op):
+        # None causes the result of this op to get aliased to op.args[0]
+        return [SpaceOperation('mark_opaque_ptr', op.args, None), None]
+
     def rewrite_op_force_cast(self, op):
         v_arg = op.args[0]
         v_result = op.result
@@ -848,26 +867,44 @@
         elif not float_arg and float_res:
             # some int -> some float
             ops = []
-            v1 = varoftype(lltype.Signed)
-            oplist = self.rewrite_operation(
-                SpaceOperation('force_cast', [v_arg], v1)
-            )
-            if oplist:
-                ops.extend(oplist)
+            v2 = varoftype(lltype.Float)
+            sizesign = rffi.size_and_sign(v_arg.concretetype)
+            if sizesign <= rffi.size_and_sign(lltype.Signed):
+                # cast from a type that fits in an int: either the size is
+                # smaller, or it is equal and it is not unsigned
+                v1 = varoftype(lltype.Signed)
+                oplist = self.rewrite_operation(
+                    SpaceOperation('force_cast', [v_arg], v1)
+                )
+                if oplist:
+                    ops.extend(oplist)
+                else:
+                    v1 = v_arg
+                op = self.rewrite_operation(
+                    SpaceOperation('cast_int_to_float', [v1], v2)
+                )
+                ops.append(op)
             else:
-                v1 = v_arg
-            v2 = varoftype(lltype.Float)
-            op = self.rewrite_operation(
-                SpaceOperation('cast_int_to_float', [v1], v2)
-            )
-            ops.append(op)
+                if sizesign == rffi.size_and_sign(lltype.Unsigned):
+                    opname = 'cast_uint_to_float'
+                elif sizesign == rffi.size_and_sign(lltype.SignedLongLong):
+                    opname = 'cast_longlong_to_float'
+                elif sizesign == rffi.size_and_sign(lltype.UnsignedLongLong):
+                    opname = 'cast_ulonglong_to_float'
+                else:
+                    raise AssertionError('cast_x_to_float: %r' % (sizesign,))
+                ops1 = self.rewrite_operation(
+                    SpaceOperation(opname, [v_arg], v2)
+                )
+                if not isinstance(ops1, list): ops1 = [ops1]
+                ops.extend(ops1)
             op2 = self.rewrite_operation(
                 SpaceOperation('force_cast', [v2], v_result)
             )
             if op2:
                 ops.append(op2)
             else:
-                op.result = v_result
+                ops[-1].result = v_result
             return ops
         elif float_arg and not float_res:
             # some float -> some int
@@ -880,18 +917,36 @@
                 ops.append(op1)
             else:
                 v1 = v_arg
-            v2 = varoftype(lltype.Signed)
-            op = self.rewrite_operation(
-                SpaceOperation('cast_float_to_int', [v1], v2)
-            )
-            ops.append(op)
-            oplist = self.rewrite_operation(
-                SpaceOperation('force_cast', [v2], v_result)
-            )
-            if oplist:
-                ops.extend(oplist)
+            sizesign = rffi.size_and_sign(v_result.concretetype)
+            if sizesign <= rffi.size_and_sign(lltype.Signed):
+                # cast to a type that fits in an int: either the size is
+                # smaller, or it is equal and it is not unsigned
+                v2 = varoftype(lltype.Signed)
+                op = self.rewrite_operation(
+                    SpaceOperation('cast_float_to_int', [v1], v2)
+                )
+                ops.append(op)
+                oplist = self.rewrite_operation(
+                    SpaceOperation('force_cast', [v2], v_result)
+                )
+                if oplist:
+                    ops.extend(oplist)
+                else:
+                    op.result = v_result
             else:
-                op.result = v_result
+                if sizesign == rffi.size_and_sign(lltype.Unsigned):
+                    opname = 'cast_float_to_uint'
+                elif sizesign == rffi.size_and_sign(lltype.SignedLongLong):
+                    opname = 'cast_float_to_longlong'
+                elif sizesign == rffi.size_and_sign(lltype.UnsignedLongLong):
+                    opname = 'cast_float_to_ulonglong'
+                else:
+                    raise AssertionError('cast_float_to_x: %r' % (sizesign,))
+                ops1 = self.rewrite_operation(
+                    SpaceOperation(opname, [v1], v_result)
+                )
+                if not isinstance(ops1, list): ops1 = [ops1]
+                ops.extend(ops1)
             return ops
         else:
             assert False
@@ -1097,8 +1152,6 @@
     # The new operation is optionally further processed by rewrite_operation().
     for _old, _new in [('bool_not', 'int_is_zero'),
                        ('cast_bool_to_float', 'cast_int_to_float'),
-                       ('cast_uint_to_float', 'cast_int_to_float'),
-                       ('cast_float_to_uint', 'cast_float_to_int'),
 
                        ('int_add_nonneg_ovf', 'int_add_ovf'),
                        ('keepalive', '-live-'),
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
@@ -37,9 +37,11 @@
     return a.typeannotation(t)
 
 def annotate(func, values, inline=None, backendoptimize=True,
-             type_system="lltype"):
+             type_system="lltype", translationoptions={}):
     # build the normal ll graphs for ll_function
     t = TranslationContext()
+    for key, value in translationoptions.items():
+        setattr(t.config.translation, key, value)
     annpolicy = AnnotatorPolicy()
     annpolicy.allow_someobjects = False
     a = t.buildannotator(policy=annpolicy)
@@ -229,6 +231,17 @@
     else:
         return x
 
+def _ll_1_cast_uint_to_float(x):
+    # XXX on 32-bit platforms, this should be done using cast_longlong_to_float
+    # (which is a residual call right now in the x86 backend)
+    return llop.cast_uint_to_float(lltype.Float, x)
+
+def _ll_1_cast_float_to_uint(x):
+    # XXX on 32-bit platforms, this should be done using cast_float_to_longlong
+    # (which is a residual call right now in the x86 backend)
+    return llop.cast_float_to_uint(lltype.Unsigned, x)
+
+
 # math support
 # ------------
 
diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py
--- a/pypy/jit/codewriter/test/test_flatten.py
+++ b/pypy/jit/codewriter/test/test_flatten.py
@@ -8,7 +8,7 @@
 from pypy.rpython.lltypesystem import lltype, rclass, rstr
 from pypy.objspace.flow.model import SpaceOperation, Variable, Constant
 from pypy.translator.unsimplify import varoftype
-from pypy.rlib.rarithmetic import ovfcheck, r_uint
+from pypy.rlib.rarithmetic import ovfcheck, r_uint, r_longlong, r_ulonglong
 from pypy.rlib.jit import dont_look_inside, _we_are_jitted, JitDriver
 from pypy.rlib.objectmodel import keepalive_until_here
 from pypy.rlib import jit
@@ -70,7 +70,8 @@
         return 'residual'
     def getcalldescr(self, op, oopspecindex=None, extraeffect=None):
         try:
-            if 'cannot_raise' in op.args[0].value._obj.graph.name:
+            name = op.args[0].value._obj._name
+            if 'cannot_raise' in name or name.startswith('cast_'):
                 return self._descr_cannot_raise
         except AttributeError:
             pass
@@ -900,6 +901,67 @@
             int_return %i4
         """, transform=True)
 
+        def f(dbl):
+            return rffi.cast(rffi.UCHAR, dbl)
+        self.encoding_test(f, [12.456], """
+            cast_float_to_int %f0 -> %i0
+            int_and %i0, $255 -> %i1
+            int_return %i1
+        """, transform=True)
+
+        def f(dbl):
+            return rffi.cast(lltype.Unsigned, dbl)
+        self.encoding_test(f, [12.456], """
+            residual_call_irf_i $<* fn cast_float_to_uint>, <Descr>, I[], R[], F[%f0] -> %i0
+            int_return %i0
+        """, transform=True)
+
+        def f(i):
+            return rffi.cast(lltype.Float, chr(i))    # "char -> float"
+        self.encoding_test(f, [12], """
+            cast_int_to_float %i0 -> %f0
+            float_return %f0
+        """, transform=True)
+
+        def f(i):
+            return rffi.cast(lltype.Float, r_uint(i))    # "uint -> float"
+        self.encoding_test(f, [12], """
+            residual_call_irf_f $<* fn cast_uint_to_float>, <Descr>, I[%i0], R[], F[] -> %f0
+            float_return %f0
+        """, transform=True)
+
+        if not longlong.is_64_bit:
+            def f(dbl):
+                return rffi.cast(lltype.SignedLongLong, dbl)
+            self.encoding_test(f, [12.3], """
+                residual_call_irf_f $<* fn llong_from_float>, <Descr>, I[], R[], F[%f0] -> %f1
+                float_return %f1
+            """, transform=True)
+
+            def f(dbl):
+                return rffi.cast(lltype.UnsignedLongLong, dbl)
+            self.encoding_test(f, [12.3], """
+                residual_call_irf_f $<* fn ullong_from_float>, <Descr>, I[], R[], F[%f0] -> %f1
+                float_return %f1
+            """, transform=True)
+
+            def f(x):
+                ll = r_longlong(x)
+                return rffi.cast(lltype.Float, ll)
+            self.encoding_test(f, [12], """
+                residual_call_irf_f $<* fn llong_from_int>, <Descr>, I[%i0], R[], F[] -> %f0
+                residual_call_irf_f $<* fn llong_to_float>, <Descr>, I[], R[], F[%f0] -> %f1
+                float_return %f1
+            """, transform=True)
+
+            def f(x):
+                ll = r_ulonglong(x)
+                return rffi.cast(lltype.Float, ll)
+            self.encoding_test(f, [12], """
+                residual_call_irf_f $<* fn ullong_from_int>, <Descr>, I[%i0], R[], F[] -> %f0
+                residual_call_irf_f $<* fn ullong_u_to_float>, <Descr>, I[], R[], F[%f0] -> %f1
+                float_return %f1
+            """, transform=True)
 
     def test_direct_ptradd(self):
         from pypy.rpython.lltypesystem import rffi
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
@@ -576,10 +576,10 @@
         assert op1.args == [v2]
 
 def test_ptr_eq():
-    v1 = varoftype(rclass.OBJECTPTR)
-    v2 = varoftype(rclass.OBJECTPTR)
+    v1 = varoftype(lltype.Ptr(rstr.STR))
+    v2 = varoftype(lltype.Ptr(rstr.STR))
     v3 = varoftype(lltype.Bool)
-    c0 = const(lltype.nullptr(rclass.OBJECT))
+    c0 = const(lltype.nullptr(rstr.STR))
     #
     for opname, reducedname in [('ptr_eq', 'ptr_iszero'),
                                 ('ptr_ne', 'ptr_nonzero')]:
@@ -598,6 +598,31 @@
         assert op1.opname == reducedname
         assert op1.args == [v2]
 
+def test_instance_ptr_eq():
+    v1 = varoftype(rclass.OBJECTPTR)
+    v2 = varoftype(rclass.OBJECTPTR)
+    v3 = varoftype(lltype.Bool)
+    c0 = const(lltype.nullptr(rclass.OBJECT))
+
+    for opname, newopname, reducedname in [
+        ('ptr_eq', 'instance_ptr_eq', 'instance_ptr_iszero'),
+        ('ptr_ne', 'instance_ptr_ne', 'instance_ptr_nonzero')
+    ]:
+        op = SpaceOperation(opname, [v1, v2], v3)
+        op1 = Transformer().rewrite_operation(op)
+        assert op1.opname == newopname
+        assert op1.args == [v1, v2]
+
+        op = SpaceOperation(opname, [v1, c0], v3)
+        op1 = Transformer().rewrite_operation(op)
+        assert op1.opname == reducedname
+        assert op1.args == [v1]
+
+        op = SpaceOperation(opname, [c0, v1], v3)
+        op1 = Transformer().rewrite_operation(op)
+        assert op1.opname == reducedname
+        assert op1.args == [v1]
+
 def test_nongc_ptr_eq():
     v1 = varoftype(rclass.NONGCOBJECTPTR)
     v2 = varoftype(rclass.NONGCOBJECTPTR)
@@ -1103,3 +1128,16 @@
                         varoftype(lltype.Signed))
     tr = Transformer(None, None)
     raises(NotImplementedError, tr.rewrite_operation, op)
+
+def test_cast_opaque_ptr():
+    S = lltype.GcStruct("S", ("x", lltype.Signed))
+    v1 = varoftype(lltype.Ptr(S))
+    v2 = varoftype(lltype.Ptr(rclass.OBJECT))
+
+    op = SpaceOperation('cast_opaque_ptr', [v1], v2)
+    tr = Transformer()
+    [op1, op2] = tr.rewrite_operation(op)
+    assert op1.opname == 'mark_opaque_ptr'
+    assert op1.args == [v1]
+    assert op1.result is None
+    assert op2 is None
\ No newline at end of file
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
@@ -499,9 +499,12 @@
     @arguments("r", returns="i")
     def bhimpl_ptr_nonzero(a):
         return bool(a)
-    @arguments("r", returns="r")
-    def bhimpl_cast_opaque_ptr(a):
-        return a
+    @arguments("r", "r", returns="i")
+    def bhimpl_instance_ptr_eq(a, b):
+        return a == b
+    @arguments("r", "r", returns="i")
+    def bhimpl_instance_ptr_ne(a, b):
+        return a != b
     @arguments("r", returns="i")
     def bhimpl_cast_ptr_to_int(a):
         i = lltype.cast_ptr_to_int(a)
@@ -512,6 +515,10 @@
         ll_assert((i & 1) == 1, "bhimpl_cast_int_to_ptr: not an odd int")
         return lltype.cast_int_to_ptr(llmemory.GCREF, i)
 
+    @arguments("r")
+    def bhimpl_mark_opaque_ptr(a):
+        pass
+
     @arguments("i", returns="i")
     def bhimpl_int_copy(a):
         return a
@@ -630,6 +637,9 @@
         a = longlong.getrealfloat(a)
         # note: we need to call int() twice to care for the fact that
         # int(-2147483648.0) returns a long :-(
+        # we could also call intmask() instead of the outermost int(), but
+        # it's probably better to explicitly crash (by getting a long) if a
+        # non-translated version tries to cast a too large float to an int.
         return int(int(a))
 
     @arguments("i", returns="f")
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
@@ -34,7 +34,6 @@
         self.clear_caches(opnum, descr, argboxes)
 
     def mark_escaped(self, opnum, argboxes):
-        idx = 0
         if opnum == rop.SETFIELD_GC:
             assert len(argboxes) == 2
             box, valuebox = argboxes
@@ -42,8 +41,20 @@
                 self.dependencies.setdefault(box, []).append(valuebox)
             else:
                 self._escape(valuebox)
-        # GETFIELD_GC doesn't escape it's argument
-        elif opnum != rop.GETFIELD_GC:
+        elif opnum == rop.SETARRAYITEM_GC:
+            assert len(argboxes) == 3
+            box, indexbox, valuebox = argboxes
+            if self.is_unescaped(box) and self.is_unescaped(valuebox):
+                self.dependencies.setdefault(box, []).append(valuebox)
+            else:
+                self._escape(valuebox)
+        # GETFIELD_GC, MARK_OPAQUE_PTR, PTR_EQ, and PTR_NE don't escape their
+        # arguments
+        elif (opnum != rop.GETFIELD_GC and
+              opnum != rop.MARK_OPAQUE_PTR and
+              opnum != rop.PTR_EQ and
+              opnum != rop.PTR_NE):
+            idx = 0
             for box in argboxes:
                 # setarrayitem_gc don't escape its first argument
                 if not (idx == 0 and opnum in [rop.SETARRAYITEM_GC]):
@@ -60,13 +71,13 @@
                 self._escape(dep)
 
     def clear_caches(self, opnum, descr, argboxes):
-        if opnum == rop.SETFIELD_GC:
-            return
-        if opnum == rop.SETARRAYITEM_GC:
-            return
-        if opnum == rop.SETFIELD_RAW:
-            return
-        if opnum == rop.SETARRAYITEM_RAW:
+        if (opnum == rop.SETFIELD_GC or
+            opnum == rop.SETARRAYITEM_GC or
+            opnum == rop.SETFIELD_RAW or
+            opnum == rop.SETARRAYITEM_RAW or
+            opnum == rop.SETINTERIORFIELD_GC or
+            opnum == rop.COPYSTRCONTENT or
+            opnum == rop.COPYUNICODECONTENT):
             return
         if rop._OVF_FIRST <= opnum <= rop._OVF_LAST:
             return
@@ -75,9 +86,9 @@
         if opnum == rop.CALL or opnum == rop.CALL_LOOPINVARIANT:
             effectinfo = descr.get_extra_info()
             ef = effectinfo.extraeffect
-            if ef == effectinfo.EF_LOOPINVARIANT or \
-               ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or \
-               ef == effectinfo.EF_ELIDABLE_CAN_RAISE:
+            if (ef == effectinfo.EF_LOOPINVARIANT or
+                ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or
+                ef == effectinfo.EF_ELIDABLE_CAN_RAISE):
                 return
             # A special case for ll_arraycopy, because it is so common, and its
             # effects are so well defined.
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
@@ -16,6 +16,7 @@
 INT   = 'i'
 REF   = 'r'
 FLOAT = 'f'
+STRUCT = 's'
 HOLE  = '_'
 VOID  = 'v'
 
@@ -172,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
         """
@@ -923,6 +929,9 @@
     def view(self, **kwds):
         pass
 
+    def clear(self):
+        pass
+
 class Stats(object):
     """For tests."""
 
@@ -937,6 +946,15 @@
         self.aborted_keys = []
         self.invalidated_token_numbers = set()
 
+    def clear(self):
+        del self.loops[:]
+        del self.locations[:]
+        del self.aborted_keys[:]
+        self.invalidated_token_numbers.clear()
+        self.compiled_count = 0
+        self.enter_count = 0
+        self.aborted_count = 0
+
     def set_history(self, history):
         self.operations = history.operations
 
diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py
--- a/pypy/jit/metainterp/optimizeopt/__init__.py
+++ b/pypy/jit/metainterp/optimizeopt/__init__.py
@@ -55,7 +55,7 @@
 
 
 def optimize_loop_1(metainterp_sd, loop, enable_opts,
-                    inline_short_preamble=True, retraced=False, bridge=False):
+                    inline_short_preamble=True, retraced=False):
     """Optimize loop.operations to remove internal overheadish operations.
     """
 
@@ -64,7 +64,7 @@
     if unroll:
         optimize_unroll(metainterp_sd, loop, optimizations)
     else:
-        optimizer = Optimizer(metainterp_sd, loop, optimizations, bridge)
+        optimizer = Optimizer(metainterp_sd, loop, optimizations)
         optimizer.propagate_all_forward()
 
 def optimize_bridge_1(metainterp_sd, bridge, enable_opts,
@@ -76,7 +76,7 @@
     except KeyError:
         pass
     optimize_loop_1(metainterp_sd, bridge, enable_opts,
-                    inline_short_preamble, retraced, bridge=True)
+                    inline_short_preamble, retraced)
 
 if __name__ == '__main__':
     print ALL_OPTS_NAMES
diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -43,7 +43,7 @@
             optheap.optimizer.ensure_imported(cached_fieldvalue)
             cached_fieldvalue = self._cached_fields.get(structvalue, None)
 
-        if cached_fieldvalue is not fieldvalue:
+        if not fieldvalue.same_value(cached_fieldvalue):
             # common case: store the 'op' as lazy_setfield, and register
             # myself in the optheap's _lazy_setfields_and_arrayitems list
             self._lazy_setfield = op
@@ -140,6 +140,15 @@
                     getop = ResOperation(rop.GETFIELD_GC, [op.getarg(0)],
                                          result, op.getdescr())
                     shortboxes.add_potential(getop, synthetic=True)
+                if op.getopnum() == rop.SETARRAYITEM_GC:
+                    result = op.getarg(2)
+                    if isinstance(result, Const):
+                        newresult = result.clonebox()
+                        optimizer.make_constant(newresult, result)
+                        result = newresult
+                    getop = ResOperation(rop.GETARRAYITEM_GC, [op.getarg(0), op.getarg(1)],
+                                         result, op.getdescr())
+                    shortboxes.add_potential(getop, synthetic=True)
                 elif op.result is not None:
                     shortboxes.add_potential(op)
 
@@ -225,7 +234,7 @@
             or op.is_ovf()):
             self.posponedop = op
         else:
-            self.next_optimization.propagate_forward(op)
+            Optimization.emit_operation(self, op)
 
     def emitting_operation(self, op):
         if op.has_no_side_effect():
diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py
--- a/pypy/jit/metainterp/optimizeopt/intbounds.py
+++ b/pypy/jit/metainterp/optimizeopt/intbounds.py
@@ -1,3 +1,4 @@
+import sys
 from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, CONST_1, CONST_0, \
                                                   MODE_ARRAY, MODE_STR, MODE_UNICODE
 from pypy.jit.metainterp.history import ConstInt
@@ -5,36 +6,18 @@
     IntUpperBound)
 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
 from pypy.jit.metainterp.resoperation import rop
+from pypy.jit.metainterp.optimize import InvalidLoop
+from pypy.rlib.rarithmetic import LONG_BIT
 
 
 class OptIntBounds(Optimization):
     """Keeps track of the bounds placed on integers by guards and remove
        redundant guards"""
 
-    def setup(self):
-        self.posponedop = None
-        self.nextop = None
-
     def new(self):
-        assert self.posponedop is None
         return OptIntBounds()
-        
-    def flush(self):
-        assert self.posponedop is None
-
-    def setup(self):
-        self.posponedop = None
-        self.nextop = None
 
     def propagate_forward(self, op):
-        if op.is_ovf():
-            self.posponedop = op
-            return
-        if self.posponedop:
-            self.nextop = op
-            op = self.posponedop
-            self.posponedop = None
-
         dispatch_opt(self, op)
 
     def opt_default(self, op):
@@ -126,14 +109,29 @@
         r.intbound.intersect(v1.intbound.div_bound(v2.intbound))
 
     def optimize_INT_MOD(self, op):
+        v1 = self.getvalue(op.getarg(0))
+        v2 = self.getvalue(op.getarg(1))
+        known_nonneg = (v1.intbound.known_ge(IntBound(0, 0)) and 
+                        v2.intbound.known_ge(IntBound(0, 0)))
+        if known_nonneg and v2.is_constant():
+            val = v2.box.getint()
+            if (val & (val-1)) == 0:
+                # nonneg % power-of-two ==> nonneg & (power-of-two - 1)
+                arg1 = op.getarg(0)
+                arg2 = ConstInt(val-1)
+                op = op.copy_and_change(rop.INT_AND, args=[arg1, arg2])
         self.emit_operation(op)
-        v2 = self.getvalue(op.getarg(1))
         if v2.is_constant():
             val = v2.box.getint()
             r = self.getvalue(op.result)
             if val < 0:
+                if val == -sys.maxint-1:
+                    return     # give up
                 val = -val
-            r.intbound.make_gt(IntBound(-val, -val))
+            if known_nonneg:
+                r.intbound.make_ge(IntBound(0, 0))
+            else:
+                r.intbound.make_gt(IntBound(-val, -val))
             r.intbound.make_lt(IntBound(val, val))
 
     def optimize_INT_LSHIFT(self, op):
@@ -153,72 +151,84 @@
     def optimize_INT_RSHIFT(self, op):
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))
+        b = v1.intbound.rshift_bound(v2.intbound)
+        if b.has_lower and b.has_upper and b.lower == b.upper:
+            # constant result (likely 0, for rshifts that kill all bits)
+            self.make_constant_int(op.result, b.lower)
+        else:
+            self.emit_operation(op)
+            r = self.getvalue(op.result)
+            r.intbound.intersect(b)
+
+    def optimize_GUARD_NO_OVERFLOW(self, op):
+        lastop = self.last_emitted_operation
+        if lastop is not None:
+            opnum = lastop.getopnum()
+            args = lastop.getarglist()
+            result = lastop.result
+            # If the INT_xxx_OVF was replaced with INT_xxx, then we can kill
+            # the GUARD_NO_OVERFLOW.
+            if (opnum == rop.INT_ADD or
+                opnum == rop.INT_SUB or
+                opnum == rop.INT_MUL):
+                return
+            # Else, synthesize the non overflowing op for optimize_default to
+            # reuse, as well as the reverse op
+            elif opnum == rop.INT_ADD_OVF:
+                self.pure(rop.INT_ADD, args[:], result)
+                self.pure(rop.INT_SUB, [result, args[1]], args[0])
+                self.pure(rop.INT_SUB, [result, args[0]], args[1])
+            elif opnum == rop.INT_SUB_OVF:
+                self.pure(rop.INT_SUB, args[:], result)
+                self.pure(rop.INT_ADD, [result, args[1]], args[0])
+                self.pure(rop.INT_SUB, [args[0], result], args[1])
+            elif opnum == rop.INT_MUL_OVF:
+                self.pure(rop.INT_MUL, args[:], result)
         self.emit_operation(op)
-        r = self.getvalue(op.result)
-        r.intbound.intersect(v1.intbound.rshift_bound(v2.intbound))
+
+    def optimize_GUARD_OVERFLOW(self, op):
+        # If INT_xxx_OVF was replaced by INT_xxx, *but* we still see
+        # GUARD_OVERFLOW, then the loop is invalid.
+        lastop = self.last_emitted_operation
+        if lastop is None:
+            raise InvalidLoop
+        opnum = lastop.getopnum()
+        if opnum not in (rop.INT_ADD_OVF, rop.INT_SUB_OVF, rop.INT_MUL_OVF):
+            raise InvalidLoop
+        self.emit_operation(op)
 
     def optimize_INT_ADD_OVF(self, op):
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))
         resbound = v1.intbound.add_bound(v2.intbound)
-        if resbound.has_lower and resbound.has_upper and \
-           self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
-            # Transform into INT_ADD and remove guard
+        if resbound.bounded():
+            # Transform into INT_ADD.  The following guard will be killed
+            # by optimize_GUARD_NO_OVERFLOW; if we see instead an
+            # optimize_GUARD_OVERFLOW, then InvalidLoop.
             op = op.copy_and_change(rop.INT_ADD)
-            self.optimize_INT_ADD(op) # emit the op
-        else:
-            self.emit_operation(op)
-            r = self.getvalue(op.result)
-            r.intbound.intersect(resbound)
-            self.emit_operation(self.nextop)
-            if self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
-                # Synthesize the non overflowing op for optimize_default to reuse
-                self.pure(rop.INT_ADD, op.getarglist()[:], op.result)
-                # 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))
-
+        self.emit_operation(op) # emit the op
+        r = self.getvalue(op.result)
+        r.intbound.intersect(resbound)
 
     def optimize_INT_SUB_OVF(self, op):
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))
         resbound = v1.intbound.sub_bound(v2.intbound)
-        if resbound.has_lower and resbound.has_upper and \
-               self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
-            # Transform into INT_SUB and remove guard
+        if resbound.bounded():
             op = op.copy_and_change(rop.INT_SUB)
-            self.optimize_INT_SUB(op) # emit the op
-        else:
-            self.emit_operation(op)
-            r = self.getvalue(op.result)
-            r.intbound.intersect(resbound)
-            self.emit_operation(self.nextop)
-            if self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
-                # Synthesize the non overflowing op for optimize_default to reuse
-                self.pure(rop.INT_SUB, op.getarglist()[:], op.result)
-                # 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))
-
+        self.emit_operation(op) # emit the op
+        r = self.getvalue(op.result)
+        r.intbound.intersect(resbound)
 
     def optimize_INT_MUL_OVF(self, op):
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))
         resbound = v1.intbound.mul_bound(v2.intbound)
-        if resbound.has_lower and resbound.has_upper and \
-               self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
-            # Transform into INT_MUL and remove guard
+        if resbound.bounded():
             op = op.copy_and_change(rop.INT_MUL)
-            self.optimize_INT_MUL(op) # emit the op
-        else:
-            self.emit_operation(op)
-            r = self.getvalue(op.result)
-            r.intbound.intersect(resbound)
-            self.emit_operation(self.nextop)
-            if self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
-                # Synthesize the non overflowing op for optimize_default to reuse
-                self.pure(rop.INT_MUL, op.getarglist()[:], op.result)
-
+        self.emit_operation(op)
+        r = self.getvalue(op.result)
+        r.intbound.intersect(resbound)
 
     def optimize_INT_LT(self, op):
         v1 = self.getvalue(op.getarg(0))
diff --git a/pypy/jit/metainterp/optimizeopt/intutils.py b/pypy/jit/metainterp/optimizeopt/intutils.py
--- a/pypy/jit/metainterp/optimizeopt/intutils.py
+++ b/pypy/jit/metainterp/optimizeopt/intutils.py
@@ -1,4 +1,5 @@
 from pypy.rlib.rarithmetic import ovfcheck, ovfcheck_lshift, LONG_BIT
+from pypy.rlib.objectmodel import we_are_translated
 from pypy.jit.metainterp.resoperation import rop, ResOperation
 from pypy.jit.metainterp.history import BoxInt, ConstInt
 import sys
@@ -13,6 +14,10 @@
         self.has_lower = True
         self.upper = upper
         self.lower = lower
+        # check for unexpected overflows:
+        if not we_are_translated():
+            assert type(upper) is not long
+            assert type(lower) is not long
 
     # Returns True if the bound was updated
     def make_le(self, other):
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -1,12 +1,12 @@
 from pypy.jit.metainterp import jitprof, resume, compile
 from pypy.jit.metainterp.executor import execute_nonspec
-from pypy.jit.metainterp.history import BoxInt, BoxFloat, Const, ConstInt, REF
+from pypy.jit.metainterp.history import BoxInt, BoxFloat, Const, ConstInt, REF, INT
 from pypy.jit.metainterp.optimizeopt.intutils import IntBound, IntUnbounded, \
                                                      ImmutableIntUnbounded, \
                                                      IntLowerBound, MININT, MAXINT
 from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
     args_dict)
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop, ResOperation, AbstractResOp
 from pypy.jit.metainterp.typesystem import llhelper, oohelper
 from pypy.tool.pairtype import extendabletype
 from pypy.rlib.debug import debug_start, debug_stop, debug_print
@@ -95,6 +95,10 @@
         return guards
 
     def import_from(self, other, optimizer):
+        if self.level == LEVEL_CONSTANT:
+            assert other.level == LEVEL_CONSTANT
+            assert other.box.same_constant(self.box)
+            return
         assert self.level <= LEVEL_NONNULL
         if other.level == LEVEL_CONSTANT:
             self.make_constant(other.get_key_box())
@@ -141,6 +145,13 @@
             return not box.nonnull()
         return False
 
+    def same_value(self, other):
+        if not other:
+            return False
+        if self.is_constant() and other.is_constant():
+            return self.box.same_constant(other.box)
+        return self is other
+
     def make_constant(self, constbox):
         """Replace 'self.box' with a Const box."""
         assert isinstance(constbox, Const)
@@ -209,13 +220,19 @@
     def setfield(self, ofs, value):
         raise NotImplementedError
 
+    def getlength(self):
+        raise NotImplementedError
+
     def getitem(self, index):
         raise NotImplementedError
 
-    def getlength(self):
+    def setitem(self, index, value):
         raise NotImplementedError
 
-    def setitem(self, index, value):
+    def getinteriorfield(self, index, ofs, default):
+        raise NotImplementedError
+
+    def setinteriorfield(self, index, ofs, value):
         raise NotImplementedError
 
 
@@ -230,9 +247,10 @@
 CONST_1      = ConstInt(1)
 CVAL_ZERO    = ConstantValue(CONST_0)
 CVAL_ZERO_FLOAT = ConstantValue(Const._new(0.0))
-CVAL_UNINITIALIZED_ZERO = ConstantValue(CONST_0)
 llhelper.CVAL_NULLREF = ConstantValue(llhelper.CONST_NULL)
 oohelper.CVAL_NULLREF = ConstantValue(oohelper.CONST_NULL)
+REMOVED = AbstractResOp(None)
+
 
 class Optimization(object):
     next_optimization = None
@@ -244,6 +262,7 @@
         raise NotImplementedError
 
     def emit_operation(self, op):
+        self.last_emitted_operation = op
         self.next_optimization.propagate_forward(op)
 
     # FIXME: Move some of these here?
@@ -283,11 +302,11 @@
             return self.optimizer.optpure.has_pure_result(opnum, args, descr)
         return False
 
-    def get_pure_result(self, key):    
+    def get_pure_result(self, key):
         if self.optimizer.optpure:
             return self.optimizer.optpure.get_pure_result(key)
         return None
-    
+
     def setup(self):
         pass
 
@@ -311,20 +330,20 @@
     def forget_numberings(self, box):
         self.optimizer.forget_numberings(box)
 
+
 class Optimizer(Optimization):
 
-    def __init__(self, metainterp_sd, loop, optimizations=None, bridge=False):
+    def __init__(self, metainterp_sd, loop, optimizations=None):
         self.metainterp_sd = metainterp_sd
         self.cpu = metainterp_sd.cpu
         self.loop = loop
-        self.bridge = bridge
         self.values = {}
         self.interned_refs = self.cpu.ts.new_ref_dict()
+        self.interned_ints = {}
         self.resumedata_memo = resume.ResumeDataLoopMemo(metainterp_sd)
         self.bool_boxes = {}
         self.producer = {}
         self.pendingfields = []
-        self.exception_might_have_happened = False
         self.quasi_immutable_deps = None
         self.opaque_pointers = {}
         self.replaces_guard = {}
@@ -346,6 +365,7 @@
             optimizations[-1].next_optimization = self
             for o in optimizations:
                 o.optimizer = self
+                o.last_emitted_operation = None
                 o.setup()
         else:
             optimizations = []
@@ -392,6 +412,9 @@
             if not value:
                 return box
             return self.interned_refs.setdefault(value, box)
+        #elif constbox.type == INT:
+        #    value = constbox.getint()
+        #    return self.interned_ints.setdefault(value, box)
         else:
             return box
 
@@ -477,7 +500,6 @@
             return CVAL_ZERO
 
     def propagate_all_forward(self):
-        self.exception_might_have_happened = self.bridge
         self.clear_newoperations()
         for op in self.loop.operations:
             self.first_optimization.propagate_forward(op)
@@ -524,7 +546,7 @@
 
     def replace_op(self, old_op, new_op):
         # XXX: Do we want to cache indexes to prevent search?
-        i = len(self._newoperations) 
+        i = len(self._newoperations)
         while i > 0:
             i -= 1
             if self._newoperations[i] is old_op:
diff --git a/pypy/jit/metainterp/optimizeopt/pure.py b/pypy/jit/metainterp/optimizeopt/pure.py
--- a/pypy/jit/metainterp/optimizeopt/pure.py
+++ b/pypy/jit/metainterp/optimizeopt/pure.py
@@ -1,4 +1,4 @@
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
+from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, REMOVED
 from pypy.jit.metainterp.resoperation import rop, ResOperation
 from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
     args_dict)
@@ -61,7 +61,10 @@
         oldop = self.pure_operations.get(args, None)
         if oldop is not None and oldop.getdescr() is op.getdescr():
             assert oldop.getopnum() == op.getopnum()
+            # this removes a CALL_PURE that has the same (non-constant)
+            # arguments as a previous CALL_PURE.
             self.make_equal_to(op.result, self.getvalue(oldop.result))
+            self.last_emitted_operation = REMOVED
             return
         else:
             self.pure_operations[args] = op
@@ -72,6 +75,13 @@
         self.emit_operation(ResOperation(rop.CALL, args, op.result,
                                          op.getdescr()))
 
+    def optimize_GUARD_NO_EXCEPTION(self, op):
+        if self.last_emitted_operation is REMOVED:
+            # it was a CALL_PURE that was killed; so we also kill the
+            # following GUARD_NO_EXCEPTION
+            return
+        self.emit_operation(op)
+
     def flush(self):
         assert self.posponedop is None
 
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
@@ -294,12 +294,6 @@
             raise InvalidLoop
         self.optimize_GUARD_CLASS(op)
 
-    def optimize_GUARD_NO_EXCEPTION(self, op):
-        if not self.optimizer.exception_might_have_happened:
-            return
-        self.emit_operation(op)
-        self.optimizer.exception_might_have_happened = False
-
     def optimize_CALL_LOOPINVARIANT(self, op):
         arg = op.getarg(0)
         # 'arg' must be a Const, because residual_call in codewriter
@@ -310,6 +304,7 @@
         resvalue = self.loop_invariant_results.get(key, None)
         if resvalue is not None:
             self.make_equal_to(op.result, resvalue)
+            self.last_emitted_operation = REMOVED
             return
         # change the op to be a normal call, from the backend's point of view
         # there is no reason to have a separate operation for this
@@ -337,7 +332,7 @@
     def optimize_INT_IS_ZERO(self, op):
         self._optimize_nullness(op, op.getarg(0), False)
 
-    def _optimize_oois_ooisnot(self, op, expect_isnot):
+    def _optimize_oois_ooisnot(self, op, expect_isnot, instance):
         value0 = self.getvalue(op.getarg(0))
         value1 = self.getvalue(op.getarg(1))
         if value0.is_virtual():
@@ -355,21 +350,28 @@
         elif value0 is value1:
             self.make_constant_int(op.result, not expect_isnot)
         else:
-            cls0 = value0.get_constant_class(self.optimizer.cpu)
-            if cls0 is not None:
-                cls1 = value1.get_constant_class(self.optimizer.cpu)
-                if cls1 is not None and not cls0.same_constant(cls1):
-                    # cannot be the same object, as we know that their
-                    # class is different
-                    self.make_constant_int(op.result, expect_isnot)
-                    return
+            if instance:
+                cls0 = value0.get_constant_class(self.optimizer.cpu)
+                if cls0 is not None:
+                    cls1 = value1.get_constant_class(self.optimizer.cpu)
+                    if cls1 is not None and not cls0.same_constant(cls1):
+                        # cannot be the same object, as we know that their
+                        # class is different
+                        self.make_constant_int(op.result, expect_isnot)
+                        return
             self.emit_operation(op)
 
+    def optimize_PTR_EQ(self, op):
+        self._optimize_oois_ooisnot(op, False, False)
+
     def optimize_PTR_NE(self, op):
-        self._optimize_oois_ooisnot(op, True)
+        self._optimize_oois_ooisnot(op, True, False)
 
-    def optimize_PTR_EQ(self, op):
-        self._optimize_oois_ooisnot(op, False)
+    def optimize_INSTANCE_PTR_EQ(self, op):
+        self._optimize_oois_ooisnot(op, False, True)
+
+    def optimize_INSTANCE_PTR_NE(self, op):
+        self._optimize_oois_ooisnot(op, True, True)
 
 ##    def optimize_INSTANCEOF(self, op):
 ##        value = self.getvalue(op.args[0])
@@ -437,10 +439,19 @@
             except KeyError:
                 pass
             else:
+                # this removes a CALL_PURE with all constant arguments.
                 self.make_constant(op.result, result)
+                self.last_emitted_operation = REMOVED
                 return
         self.emit_operation(op)
 
+    def optimize_GUARD_NO_EXCEPTION(self, op):
+        if self.last_emitted_operation is REMOVED:
+            # it was a CALL_PURE or a CALL_LOOPINVARIANT that was killed;
+            # so we also kill the following GUARD_NO_EXCEPTION
+            return
+        self.emit_operation(op)
+
     def optimize_INT_FLOORDIV(self, op):
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))
@@ -448,6 +459,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
@@ -455,10 +469,9 @@
                                         args = [op.getarg(0), ConstInt(highest_bit(val))])
         self.emit_operation(op)
 
-    def optimize_CAST_OPAQUE_PTR(self, op):
+    def optimize_MARK_OPAQUE_PTR(self, op):
         value = self.getvalue(op.getarg(0))
         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))
diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py b/pypy/jit/metainterp/optimizeopt/simplify.py
--- a/pypy/jit/metainterp/optimizeopt/simplify.py
+++ b/pypy/jit/metainterp/optimizeopt/simplify.py
@@ -25,7 +25,8 @@
         #     but it's a bit hard to implement robustly if heap.py is also run
         pass
 
-    optimize_CAST_OPAQUE_PTR = optimize_VIRTUAL_REF
+    def optimize_MARK_OPAQUE_PTR(self, op):
+        pass
 
 
 dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_',
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
@@ -9,6 +9,7 @@
 from pypy.jit.metainterp.history import AbstractDescr, ConstInt, BoxInt
 from pypy.jit.metainterp import executor, compile, resume, history
 from pypy.jit.metainterp.resoperation import rop, opname, ResOperation
+from pypy.rlib.rarithmetic import LONG_BIT
 
 
 def test_store_final_boxes_in_guard():
@@ -508,13 +509,13 @@
         ops = """
         [p0]
         guard_class(p0, ConstClass(node_vtable)) []
-        i0 = ptr_ne(p0, NULL)
+        i0 = instance_ptr_ne(p0, NULL)
         guard_true(i0) []
-        i1 = ptr_eq(p0, NULL)
+        i1 = instance_ptr_eq(p0, NULL)
         guard_false(i1) []
-        i2 = ptr_ne(NULL, p0)
+        i2 = instance_ptr_ne(NULL, p0)
         guard_true(i0) []
-        i3 = ptr_eq(NULL, p0)
+        i3 = instance_ptr_eq(NULL, p0)
         guard_false(i1) []
         jump(p0)
         """
@@ -680,25 +681,60 @@
 
     # ----------
 
-    def test_fold_guard_no_exception(self):
-        ops = """
-        [i]
-        guard_no_exception() []
-        i1 = int_add(i, 3)
-        guard_no_exception() []
+    def test_keep_guard_no_exception(self):
+        ops = """
+        [i1]
         i2 = call(i1, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
-        guard_no_exception() []
-        i3 = call(i2, descr=nonwritedescr)
-        jump(i1)       # the exception is considered lost when we loop back
-        """
-        expected = """
-        [i]
-        i1 = int_add(i, 3)
-        i2 = call(i1, descr=nonwritedescr)
+        jump(i2)
+        """
+        self.optimize_loop(ops, ops)
+
+    def test_keep_guard_no_exception_with_call_pure_that_is_not_folded(self):
+        ops = """
+        [i1]
+        i2 = call_pure(123456, i1, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
-        i3 = call(i2, descr=nonwritedescr)
-        jump(i1)
+        jump(i2)
+        """
+        expected = """
+        [i1]
+        i2 = call(123456, i1, descr=nonwritedescr)
+        guard_no_exception() [i1, i2]
+        jump(i2)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_remove_guard_no_exception_with_call_pure_on_constant_args(self):
+        arg_consts = [ConstInt(i) for i in (123456, 81)]
+        call_pure_results = {tuple(arg_consts): ConstInt(5)}
+        ops = """
+        [i1]
+        i3 = same_as(81)
+        i2 = call_pure(123456, i3, descr=nonwritedescr)
+        guard_no_exception() [i1, i2]
+        jump(i2)
+        """
+        expected = """
+        [i1]
+        jump(5)
+        """
+        self.optimize_loop(ops, expected, call_pure_results)
+
+    def test_remove_guard_no_exception_with_duplicated_call_pure(self):
+        ops = """
+        [i1]
+        i2 = call_pure(123456, i1, descr=nonwritedescr)
+        guard_no_exception() [i1, i2]
+        i3 = call_pure(123456, i1, descr=nonwritedescr)
+        guard_no_exception() [i1, i2, i3]
+        jump(i3)
+        """
+        expected = """
+        [i1]
+        i2 = call(123456, i1, descr=nonwritedescr)
+        guard_no_exception() [i1, i2]
+        jump(i2)
         """
         self.optimize_loop(ops, expected)
 
@@ -935,7 +971,6 @@
         """
         self.optimize_loop(ops, expected)
 
-
     def test_virtual_constant_isnonnull(self):
         ops = """
         [i0]
@@ -951,6 +986,55 @@
         """
         self.optimize_loop(ops, expected)
 
+    def test_virtual_array_of_struct(self):
+        ops = """
+        [f0, f1, f2, f3]
+        p0 = new_array(2, descr=complexarraydescr)
+        setinteriorfield_gc(p0, 0, f0, descr=complexrealdescr)
+        setinteriorfield_gc(p0, 0, f1, descr=compleximagdescr)
+        setinteriorfield_gc(p0, 1, f2, descr=complexrealdescr)
+        setinteriorfield_gc(p0, 1, f3, descr=compleximagdescr)
+        f4 = getinteriorfield_gc(p0, 0, descr=complexrealdescr)
+        f5 = getinteriorfield_gc(p0, 1, descr=complexrealdescr)
+        f6 = float_mul(f4, f5)
+        f7 = getinteriorfield_gc(p0, 0, descr=compleximagdescr)
+        f8 = getinteriorfield_gc(p0, 1, descr=compleximagdescr)
+        f9 = float_mul(f7, f8)
+        f10 = float_add(f6, f9)
+        finish(f10)
+        """
+        expected = """
+        [f0, f1, f2, f3]
+        f4 = float_mul(f0, f2)
+        f5 = float_mul(f1, f3)
+        f6 = float_add(f4, f5)
+        finish(f6)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_virtual_array_of_struct_forced(self):
+        ops = """
+        [f0, f1]
+        p0 = new_array(1, descr=complexarraydescr)
+        setinteriorfield_gc(p0, 0, f0, descr=complexrealdescr)
+        setinteriorfield_gc(p0, 0, f1, descr=compleximagdescr)
+        f2 = getinteriorfield_gc(p0, 0, descr=complexrealdescr)
+        f3 = getinteriorfield_gc(p0, 0, descr=compleximagdescr)
+        f4 = float_mul(f2, f3)
+        i0 = escape(f4, p0)
+        finish(i0)
+        """
+        expected = """
+        [f0, f1]
+        f2 = float_mul(f0, f1)
+        p0 = new_array(1, descr=complexarraydescr)
+        setinteriorfield_gc(p0, 0, f0, descr=complexrealdescr)
+        setinteriorfield_gc(p0, 0, f1, descr=compleximagdescr)
+        i0 = escape(f2, p0)
+        finish(i0)
+        """
+        self.optimize_loop(ops, expected)
+
     def test_nonvirtual_1(self):
         ops = """
         [i]
@@ -2026,7 +2110,7 @@
         ops = """
         [p1]
         guard_class(p1, ConstClass(node_vtable2)) []
-        i = ptr_ne(ConstPtr(myptr), p1)
+        i = instance_ptr_ne(ConstPtr(myptr), p1)
         guard_true(i) []
         jump(p1)
         """
@@ -2181,6 +2265,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]
@@ -4063,6 +4158,38 @@
         """
         self.optimize_strunicode_loop(ops, expected)
 
+    def test_str_concat_constant_lengths(self):
+        ops = """
+        [i0]
+        p0 = newstr(1)
+        strsetitem(p0, 0, i0)
+        p1 = newstr(0)
+        p2 = call(0, p0, p1, descr=strconcatdescr)
+        i1 = call(0, p2, p0, descr=strequaldescr)
+        finish(i1)
+        """
+        expected = """
+        [i0]
+        finish(1)
+        """
+        self.optimize_strunicode_loop(ops, expected)
+
+    def test_str_concat_constant_lengths_2(self):
+        ops = """
+        [i0]
+        p0 = newstr(0)
+        p1 = newstr(1)
+        strsetitem(p1, 0, i0)
+        p2 = call(0, p0, p1, descr=strconcatdescr)
+        i1 = call(0, p2, p1, descr=strequaldescr)
+        finish(i1)
+        """
+        expected = """
+        [i0]
+        finish(1)
+        """
+        self.optimize_strunicode_loop(ops, expected)
+
     def test_str_slice_1(self):
         ops = """
         [p1, i1, i2]
@@ -4165,15 +4292,38 @@
         """
         self.optimize_strunicode_loop(ops, expected)
 
+    def test_str_slice_plain_virtual(self):
+        ops = """
+        []
+        p0 = newstr(11)
+        copystrcontent(s"hello world", p0, 0, 0, 11)
+        p1 = call(0, p0, 0, 5, descr=strslicedescr)
+        finish(p1)
+        """
+        expected = """
+        []
+        p0 = newstr(11)
+        copystrcontent(s"hello world", p0, 0, 0, 11)
+        # Eventually this should just return s"hello", but ATM this test is
+        # just verifying that it doesn't return "\0\0\0\0\0", so being
+        # slightly underoptimized is ok.
+        p1 = newstr(5)
+        copystrcontent(p0, p1, 0, 0, 5)
+        finish(p1)
+        """
+        self.optimize_strunicode_loop(ops, expected)
+
     # ----------
     def optimize_strunicode_loop_extradescrs(self, ops, optops):
         class FakeCallInfoCollection:
             def callinfo_for_oopspec(self, oopspecindex):
                 calldescrtype = type(LLtypeMixin.strequaldescr)
+                effectinfotype = type(LLtypeMixin.strequaldescr.get_extra_info())
                 for value in LLtypeMixin.__dict__.values():
                     if isinstance(value, calldescrtype):
                         extra = value.get_extra_info()
-                        if extra and extra.oopspecindex == oopspecindex:
+                        if (extra and isinstance(extra, effectinfotype) and
+                            extra.oopspecindex == oopspecindex):
                             # returns 0 for 'func' in this test
                             return value, 0
                 raise AssertionError("not found: oopspecindex=%d" %
@@ -4653,11 +4803,11 @@
         i5 = int_ge(i0, 0)
         guard_true(i5) []
         i1 = int_mod(i0, 42)
-        i2 = int_rshift(i1, 63)
+        i2 = int_rshift(i1, %d)
         i3 = int_and(42, i2)
         i4 = int_add(i1, i3)
         finish(i4)
-        """
+        """ % (LONG_BIT-1)
         expected = """
         [i0]
         i5 = int_ge(i0, 0)
@@ -4665,21 +4815,41 @@
         i1 = int_mod(i0, 42)
         finish(i1)
         """
-        py.test.skip("in-progress")
         self.optimize_loop(ops, expected)
 
-        # Also, 'n % power-of-two' can be turned into int_and(),
-        # but that's a bit harder to detect here because it turns into
-        # several operations, and of course it is wrong to just turn
+        # 'n % power-of-two' can be turned into int_and(); at least that's
+        # easy to do now if n is known to be non-negative.
+        ops = """
+        [i0]
+        i5 = int_ge(i0, 0)
+        guard_true(i5) []
+        i1 = int_mod(i0, 8)
+        i2 = int_rshift(i1, %d)
+        i3 = int_and(42, i2)
+        i4 = int_add(i1, i3)
+        finish(i4)
+        """ % (LONG_BIT-1)
+        expected = """
+        [i0]
+        i5 = int_ge(i0, 0)
+        guard_true(i5) []
+        i1 = int_and(i0, 7)
+        finish(i1)
+        """
+        self.optimize_loop(ops, expected)
+
+        # Of course any 'maybe-negative % power-of-two' can be turned into
+        # int_and(), but that's a bit harder to detect here because it turns
+        # into several operations, and of course it is wrong to just turn
         # int_mod(i0, 16) into int_and(i0, 15).
         ops = """
         [i0]
         i1 = int_mod(i0, 16)
-        i2 = int_rshift(i1, 63)
+        i2 = int_rshift(i1, %d)
         i3 = int_and(16, i2)
         i4 = int_add(i1, i3)
         finish(i4)
-        """
+        """ % (LONG_BIT-1)
         expected = """
         [i0]
         i4 = int_and(i0, 15)
@@ -4688,6 +4858,16 @@
         py.test.skip("harder")
         self.optimize_loop(ops, expected)
 
+    def test_intmod_bounds_bug1(self):
+        ops = """
+        [i0]
+        i1 = int_mod(i0, %d)
+        i2 = int_eq(i1, 0)
+        guard_false(i2) []
+        finish()
+        """ % (-(1<<(LONG_BIT-1)),)
+        self.optimize_loop(ops, ops)
+
     def test_bounded_lazy_setfield(self):
         ops = """
         [p0, i0]
@@ -4770,6 +4950,27 @@
 
     def test_plain_virtual_string_copy_content(self):
         ops = """
+        [i1]
+        p0 = newstr(6)
+        copystrcontent(s"hello!", p0, 0, 0, 6)
+        p1 = call(0, p0, s"abc123", descr=strconcatdescr)
+        i0 = strgetitem(p1, i1)
+        finish(i0)
+        """
+        expected = """
+        [i1]
+        p0 = newstr(6)
+        copystrcontent(s"hello!", p0, 0, 0, 6)
+        p1 = newstr(12)
+        copystrcontent(p0, p1, 0, 0, 6)
+        copystrcontent(s"abc123", p1, 0, 6, 6)
+        i0 = strgetitem(p1, i1)
+        finish(i0)
+        """
+        self.optimize_strunicode_loop(ops, expected)
+
+    def test_plain_virtual_string_copy_content_2(self):
+        ops = """
         []
         p0 = newstr(6)
         copystrcontent(s"hello!", p0, 0, 0, 6)
@@ -4781,14 +4982,23 @@
         []
         p0 = newstr(6)
         copystrcontent(s"hello!", p0, 0, 0, 6)
-        p1 = newstr(12)
-        copystrcontent(p0, p1, 0, 0, 6)
-        copystrcontent(s"abc123", p1, 0, 6, 6)
-        i0 = strgetitem(p1, 0)
+        i0 = strgetitem(p0, 0)
         finish(i0)
         """
         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
@@ -931,17 +931,14 @@
         [i]
         guard_no_exception() []
         i1 = int_add(i, 3)
-        guard_no_exception() []
         i2 = call(i1, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
-        guard_no_exception() []
         i3 = call(i2, descr=nonwritedescr)
         jump(i1)       # the exception is considered lost when we loop back
         """
-        # note that 'guard_no_exception' at the very start is kept around
-        # for bridges, but not for loops
         preamble = """
         [i]
+        guard_no_exception() []    # occurs at the start of bridges, so keep it
         i1 = int_add(i, 3)
         i2 = call(i1, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
@@ -950,6 +947,7 @@
         """
         expected = """
         [i]
+        guard_no_exception() []    # occurs at the start of bridges, so keep it
         i1 = int_add(i, 3)
         i2 = call(i1, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
@@ -958,6 +956,23 @@
         """
         self.optimize_loop(ops, expected, preamble)
 
+    def test_bug_guard_no_exception(self):
+        ops = """
+        []
+        i0 = call(123, descr=nonwritedescr)
+        p0 = call(0, "xy", descr=s2u_descr)      # string -> unicode
+        guard_no_exception() []
+        escape(p0)
+        jump()
+        """
+        expected = """
+        []
+        i0 = call(123, descr=nonwritedescr)
+        escape(u"xy")
+        jump()
+        """
+        self.optimize_loop(ops, expected)
+
     # ----------
 
     def test_call_loopinvariant(self):
@@ -2168,13 +2183,13 @@
         ops = """
         [p0, i0, p1, i1, i2]
         setfield_gc(p0, i1, descr=valuedescr)
-        copystrcontent(p0, i0, p1, i1, i2)
+        copystrcontent(p0, p1, i0, i1, i2)
         escape()
         jump(p0, i0, p1, i1, i2)
         """
         expected = """
         [p0, i0, p1, i1, i2]
-        copystrcontent(p0, i0, p1, i1, i2)
+        copystrcontent(p0, p1, i0, i1, i2)
         setfield_gc(p0, i1, descr=valuedescr)
         escape()
         jump(p0, i0, p1, i1, i2)
@@ -2683,7 +2698,7 @@
         ops = """
         [p1]
         guard_class(p1, ConstClass(node_vtable2)) []
-        i = ptr_ne(ConstPtr(myptr), p1)
+        i = instance_ptr_ne(ConstPtr(myptr), p1)
         guard_true(i) []
         jump(p1)
         """
@@ -3331,7 +3346,7 @@
         jump(p1, i1, i2, i6)
         '''
         self.optimize_loop(ops, expected, preamble)
-        
+
 
     # ----------
 
@@ -4783,6 +4798,52 @@
         """
         self.optimize_loop(ops, expected)
 
+
+    def test_division_nonneg(self):
+        py.test.skip("harder")
+        # this is how an app-level division turns into right now
+        ops = """
+        [i4]
+        i1 = int_ge(i4, 0)
+        guard_true(i1) []
+        i16 = int_floordiv(i4, 3)
+        i18 = int_mul(i16, 3)
+        i19 = int_sub(i4, i18)
+        i21 = int_rshift(i19, %d)
+        i22 = int_add(i16, i21)
+        finish(i22)
+        """ % (LONG_BIT-1)
+        expected = """
+        [i4]
+        i1 = int_ge(i4, 0)
+        guard_true(i1) []
+        i16 = int_floordiv(i4, 3)
+        finish(i16)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_division_by_2(self):
+        py.test.skip("harder")
+        ops = """
+        [i4]
+        i1 = int_ge(i4, 0)
+        guard_true(i1) []
+        i16 = int_floordiv(i4, 2)
+        i18 = int_mul(i16, 2)
+        i19 = int_sub(i4, i18)
+        i21 = int_rshift(i19, %d)
+        i22 = int_add(i16, i21)
+        finish(i22)
+        """ % (LONG_BIT-1)
+        expected = """
+        [i4]
+        i1 = int_ge(i4, 0)
+        guard_true(i1) []
+        i16 = int_rshift(i4, 1)
+        finish(i16)
+        """
+        self.optimize_loop(ops, expected)
+
     def test_subsub_ovf(self):
         ops = """
         [i0]
@@ -5800,10 +5861,12 @@
         class FakeCallInfoCollection:
             def callinfo_for_oopspec(self, oopspecindex):
                 calldescrtype = type(LLtypeMixin.strequaldescr)
+                effectinfotype = type(LLtypeMixin.strequaldescr.get_extra_info())
                 for value in LLtypeMixin.__dict__.values():
                     if isinstance(value, calldescrtype):
                         extra = value.get_extra_info()
-                        if extra and extra.oopspecindex == oopspecindex:
+                        if (extra and isinstance(extra, effectinfotype) and
+                            extra.oopspecindex == oopspecindex):
                             # returns 0 for 'func' in this test
                             return value, 0
                 raise AssertionError("not found: oopspecindex=%d" %
@@ -6233,12 +6296,15 @@
     def test_str2unicode_constant(self):
         ops = """
         []
+        escape(1213)
         p0 = call(0, "xy", descr=s2u_descr)      # string -> unicode
+        guard_no_exception() []
         escape(p0)
         jump()
         """
         expected = """
         []
+        escape(1213)
         escape(u"xy")
         jump()
         """
@@ -6248,6 +6314,7 @@
         ops = """
         [p0]
         p1 = call(0, p0, descr=s2u_descr)      # string -> unicode
+        guard_no_exception() []
         escape(p1)
         jump(p1)
         """
@@ -7280,7 +7347,7 @@
         ops = """
         [p1, p2]
         setarrayitem_gc(p1, 2, 10, descr=arraydescr)
-        setarrayitem_gc(p2, 3, 13, descr=arraydescr)        
+        setarrayitem_gc(p2, 3, 13, descr=arraydescr)
         call(0, p1, p2, 0, 0, 10, descr=arraycopydescr)
         jump(p1, p2)
         """
@@ -7307,6 +7374,150 @@
         """
         self.optimize_loop(ops, expected)
 
+    def test_repeated_constant_setfield_mixed_with_guard(self):
+        ops = """
+        [p22, p18]
+        setfield_gc(p22, 2, descr=valuedescr)
+        guard_nonnull_class(p18, ConstClass(node_vtable)) []
+        setfield_gc(p22, 2, descr=valuedescr)
+        jump(p22, p18)
+        """
+        preamble = """
+        [p22, p18]
+        setfield_gc(p22, 2, descr=valuedescr)
+        guard_nonnull_class(p18, ConstClass(node_vtable)) []
+        jump(p22, p18)
+        """
+        short = """
+        [p22, p18]
+        i1 = getfield_gc(p22, descr=valuedescr)
+        guard_value(i1, 2) []
+        jump(p22, p18)
+        """
+        expected = """
+        [p22, p18]
+        jump(p22, p18)
+        """
+        self.optimize_loop(ops, expected, preamble, expected_short=short)
+
+    def test_repeated_setfield_mixed_with_guard(self):
+        ops = """
+        [p22, p18, i1]
+        i2 = getfield_gc(p22, descr=valuedescr)
+        call(i2, descr=nonwritedescr)
+        setfield_gc(p22, i1, descr=valuedescr)
+        guard_nonnull_class(p18, ConstClass(node_vtable)) []
+        setfield_gc(p22, i1, descr=valuedescr)
+        jump(p22, p18, i1)
+        """
+        preamble = """
+        [p22, p18, i1]
+        i2 = getfield_gc(p22, descr=valuedescr)
+        call(i2, descr=nonwritedescr)
+        setfield_gc(p22, i1, descr=valuedescr)
+        guard_nonnull_class(p18, ConstClass(node_vtable)) []
+        jump(p22, p18, i1, i1)
+        """
+        short = """
+        [p22, p18, i1]
+        i2 = getfield_gc(p22, descr=valuedescr)
+        jump(p22, p18, i1, i2)
+        """
+        expected = """
+        [p22, p18, i1, i2]
+        call(i2, descr=nonwritedescr)
+        setfield_gc(p22, i1, descr=valuedescr)
+        jump(p22, p18, i1, i1)
+        """
+        self.optimize_loop(ops, expected, preamble, expected_short=short)
+
+    def test_cache_setfield_across_loop_boundaries(self):
+        ops = """
+        [p1]
+        p2 = getfield_gc(p1, descr=valuedescr)
+        guard_nonnull_class(p2, ConstClass(node_vtable)) []
+        call(p2, descr=nonwritedescr)
+        p3 = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(p1, p3, descr=valuedescr)
+        jump(p1)
+        """
+        expected = """
+        [p1, p2]
+        call(p2, descr=nonwritedescr)
+        p3 = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(p1, p3, descr=valuedescr)
+        jump(p1, p3)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_cache_setarrayitem_across_loop_boundaries(self):
+        ops = """
+        [p1]
+        p2 = getarrayitem_gc(p1, 3, descr=arraydescr)
+        guard_nonnull_class(p2, ConstClass(node_vtable)) []
+        call(p2, descr=nonwritedescr)
+        p3 = new_with_vtable(ConstClass(node_vtable))
+        setarrayitem_gc(p1, 3, p3, descr=arraydescr)
+        jump(p1)
+        """
+        expected = """
+        [p1, p2]
+        call(p2, descr=nonwritedescr)
+        p3 = new_with_vtable(ConstClass(node_vtable))
+        setarrayitem_gc(p1, 3, p3, descr=arraydescr)
+        jump(p1, p3)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_setarrayitem_p0_p0(self):
+        ops = """
+        [i0, i1]
+        p0 = escape()
+        setarrayitem_gc(p0, 2, p0, descr=arraydescr)
+        jump(i0, i1)
+        """
+        expected = """
+        [i0, i1]
+        p0 = escape()
+        setarrayitem_gc(p0, 2, p0, descr=arraydescr)
+        jump(i0, i1)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_setfield_p0_p0(self):
+        ops = """
+        [i0, i1]
+        p0 = escape()
+        setfield_gc(p0, p0, descr=arraydescr)
+        jump(i0, i1)
+        """
+        expected = """
+        [i0, i1]
+        p0 = escape()
+        setfield_gc(p0, p0, descr=arraydescr)
+        jump(i0, i1)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_setfield_p0_p1_p0(self):
+        ops = """
+        [i0, i1]
+        p0 = escape()
+        p1 = escape()
+        setfield_gc(p0, p1, descr=adescr)
+        setfield_gc(p1, p0, descr=bdescr)
+        jump(i0, i1)
+        """
+        expected = """
+        [i0, i1]
+        p0 = escape()
+        p1 = escape()
+        setfield_gc(p0, p1, descr=adescr)
+        setfield_gc(p1, p0, descr=bdescr)
+        jump(i0, i1)
+        """
+        self.optimize_loop(ops, expected)
+
 class TestLLtype(OptimizeOptTest, LLtypeMixin):
     pass
 
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py b/pypy/jit/metainterp/optimizeopt/test/test_util.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_util.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py
@@ -185,6 +185,18 @@
              EffectInfo([], [arraydescr], [], [arraydescr],
                         oopspecindex=EffectInfo.OS_ARRAYCOPY))
 
+
+    # array of structs (complex data)
+    complexarray = lltype.GcArray(
+        lltype.Struct("complex",
+            ("real", lltype.Float),
+            ("imag", lltype.Float),
+        )
+    )
+    complexarraydescr = cpu.arraydescrof(complexarray)
+    complexrealdescr = cpu.interiorfielddescrof(complexarray, "real")
+    compleximagdescr = cpu.interiorfielddescrof(complexarray, "imag")
+
     for _name, _os in [
         ('strconcatdescr',               'OS_STR_CONCAT'),
         ('strslicedescr',                'OS_STR_SLICE'),
@@ -240,7 +252,7 @@
 ##    def get_class_of_box(self, box):
 ##        root = box.getref(ootype.ROOT)
 ##        return ootype.classof(root)
-    
+
 ##    cpu = runner.OOtypeCPU(None)
 ##    NODE = ootype.Instance('NODE', ootype.ROOT, {})
 ##    NODE._add_fields({'value': ootype.Signed,
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]
@@ -271,20 +271,91 @@
     def _make_virtual(self, modifier):
         return modifier.make_varray(self.arraydescr)
 
+class VArrayStructValue(AbstractVirtualValue):
+    def __init__(self, arraydescr, size, keybox, source_op=None):
+        AbstractVirtualValue.__init__(self, keybox, source_op)
+        self.arraydescr = arraydescr
+        self._items = [{} for _ in xrange(size)]
+
+    def getlength(self):
+        return len(self._items)
+
+    def getinteriorfield(self, index, ofs, default):
+        return self._items[index].get(ofs, default)
+
+    def setinteriorfield(self, index, ofs, itemvalue):
+        assert isinstance(itemvalue, optimizer.OptValue)
+        self._items[index][ofs] = itemvalue
+
+    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)
+        self.box = box = self.source_op.result
+        for index in range(len(self._items)):
+            iteritems = self._items[index].iteritems()
+            # random order is fine, except for tests
+            if not we_are_translated():
+                iteritems = list(iteritems)
+                iteritems.sort(key = lambda (x, y): x.sort_key())
+            for descr, value in iteritems:
+                subbox = value.force_box(optforce)
+                op = ResOperation(rop.SETINTERIORFIELD_GC,
+                    [box, ConstInt(index), subbox], None, descr=descr
+                )
+                optforce.emit_operation(op)
+
+    def _get_list_of_descrs(self):
+        descrs = []
+        for item in self._items:
+            item_descrs = item.keys()
+            sort_descrs(item_descrs)
+            descrs.append(item_descrs)
+        return descrs
+
+    def get_args_for_fail(self, modifier):
+        if self.box is None and not modifier.already_seen_virtual(self.keybox):
+            itemdescrs = self._get_list_of_descrs()
+            itemboxes = []
+            for i in range(len(self._items)):
+                for descr in itemdescrs[i]:
+                    itemboxes.append(self._items[i][descr].get_key_box())
+            modifier.register_virtual_fields(self.keybox, itemboxes)
+            for i in range(len(self._items)):
+                for descr in itemdescrs[i]:
+                    self._items[i][descr].get_args_for_fail(modifier)
+
+    def force_at_end_of_preamble(self, already_forced, optforce):
+        if self in already_forced:
+            return self
+        already_forced[self] = self
+        for index in range(len(self._items)):
+            for descr in self._items[index].keys():
+                self._items[index][descr] = self._items[index][descr].force_at_end_of_preamble(already_forced, optforce)
+        return self
+
+    def _make_virtual(self, modifier):
+        return modifier.make_varraystruct(self.arraydescr, self._get_list_of_descrs())
+
+
 class OptVirtualize(optimizer.Optimization):
     "Virtualize objects until they escape."
 
     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)
         return vvalue
 
     def make_varray(self, arraydescr, size, box, source_op=None):
-        constvalue = self.new_const_item(arraydescr)
-        vvalue = VArrayValue(arraydescr, constvalue, size, box, source_op)
+        if arraydescr.is_array_of_structs():
+            vvalue = VArrayStructValue(arraydescr, size, box, source_op)
+        else:
+            constvalue = self.new_const_item(arraydescr)
+            vvalue = VArrayValue(arraydescr, constvalue, size, box, source_op)
         self.make_equal_to(box, vvalue)
         return vvalue
 
@@ -431,6 +502,34 @@
         value.ensure_nonnull()
         self.emit_operation(op)
 
+    def optimize_GETINTERIORFIELD_GC(self, op):
+        value = self.getvalue(op.getarg(0))
+        if value.is_virtual():
+            indexbox = self.get_constant_box(op.getarg(1))
+            if indexbox is not None:
+                descr = op.getdescr()
+                fieldvalue = value.getinteriorfield(
+                    indexbox.getint(), descr, None
+                )
+                if fieldvalue is None:
+                    fieldvalue = self.new_const(descr)
+                self.make_equal_to(op.result, fieldvalue)
+                return
+        value.ensure_nonnull()
+        self.emit_operation(op)
+
+    def optimize_SETINTERIORFIELD_GC(self, op):
+        value = self.getvalue(op.getarg(0))
+        if value.is_virtual():
+            indexbox = self.get_constant_box(op.getarg(1))
+            if indexbox is not None:
+                value.setinteriorfield(
+                    indexbox.getint(), op.getdescr(), self.getvalue(op.getarg(2))
+                )
+                return
+        value.ensure_nonnull()
+        self.emit_operation(op)
+
 
 dispatch_opt = make_dispatcher_method(OptVirtualize, 'optimize_',
         default=OptVirtualize.emit_operation)
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -16,7 +16,7 @@
 
 class AbstractVirtualStateInfo(resume.AbstractVirtualInfo):
     position = -1
-    
+
     def generalization_of(self, other, renum, bad):
         raise NotImplementedError
 
@@ -54,7 +54,7 @@
                 s.debug_print(indent + "    ", seen, bad)
         else:
             debug_print(indent + "    ...")
-                
+
 
     def debug_header(self, indent):
         raise NotImplementedError
@@ -77,13 +77,15 @@
             bad[self] = True
             bad[other] = True
             return False
+
+        assert isinstance(other, AbstractVirtualStructStateInfo)
         assert len(self.fielddescrs) == len(self.fieldstate)
         assert len(other.fielddescrs) == len(other.fieldstate)
         if len(self.fielddescrs) != len(other.fielddescrs):
             bad[self] = True
             bad[other] = True
             return False
-        
+
         for i in range(len(self.fielddescrs)):
             if other.fielddescrs[i] is not self.fielddescrs[i]:
                 bad[self] = True
@@ -112,8 +114,8 @@
     def _enum(self, virtual_state):
         for s in self.fieldstate:
             s.enum(virtual_state)
-        
-        
+
+
 class VirtualStateInfo(AbstractVirtualStructStateInfo):
     def __init__(self, known_class, fielddescrs):
         AbstractVirtualStructStateInfo.__init__(self, fielddescrs)
@@ -128,13 +130,13 @@
 
     def debug_header(self, indent):
         debug_print(indent + 'VirtualStateInfo(%d):' % self.position)
-        
+
 class VStructStateInfo(AbstractVirtualStructStateInfo):
     def __init__(self, typedescr, fielddescrs):
         AbstractVirtualStructStateInfo.__init__(self, fielddescrs)
         self.typedescr = typedescr
 
-    def _generalization_of(self, other):        
+    def _generalization_of(self, other):
         if not isinstance(other, VStructStateInfo):
             return False
         if self.typedescr is not other.typedescr:
@@ -143,7 +145,7 @@
 
     def debug_header(self, indent):
         debug_print(indent + 'VStructStateInfo(%d):' % self.position)
-        
+
 class VArrayStateInfo(AbstractVirtualStateInfo):
     def __init__(self, arraydescr):
         self.arraydescr = arraydescr
@@ -157,11 +159,7 @@
             bad[other] = True
             return False
         renum[self.position] = other.position
-        if not isinstance(other, VArrayStateInfo):
-            bad[self] = True
-            bad[other] = True
-            return False
-        if self.arraydescr is not other.arraydescr:
+        if not self._generalization_of(other):
             bad[self] = True
             bad[other] = True
             return False
@@ -177,6 +175,10 @@
                 return False
         return True
 
+    def _generalization_of(self, other):
+        return (isinstance(other, VArrayStateInfo) and
+            self.arraydescr is other.arraydescr)
+
     def enum_forced_boxes(self, boxes, value, optimizer):
         assert isinstance(value, virtualize.VArrayValue)
         assert value.is_virtual()
@@ -192,8 +194,75 @@
 
     def debug_header(self, indent):
         debug_print(indent + 'VArrayStateInfo(%d):' % self.position)
-            
-        
+
+class VArrayStructStateInfo(AbstractVirtualStateInfo):
+    def __init__(self, arraydescr, fielddescrs):
+        self.arraydescr = arraydescr
+        self.fielddescrs = fielddescrs
+
+    def generalization_of(self, other, renum, bad):
+        assert self.position != -1
+        if self.position in renum:
+            if renum[self.position] == other.position:
+                return True
+            bad[self] = True
+            bad[other] = True
+            return False
+        renum[self.position] = other.position
+        if not self._generalization_of(other):
+            bad[self] = True
+            bad[other] = True
+            return False
+
+        assert isinstance(other, VArrayStructStateInfo)
+        if len(self.fielddescrs) != len(other.fielddescrs):
+            bad[self] = True
+            bad[other] = True
+            return False
+
+        p = 0
+        for i in range(len(self.fielddescrs)):
+            if len(self.fielddescrs[i]) != len(other.fielddescrs[i]):
+                bad[self] = True
+                bad[other] = True
+                return False
+            for j in range(len(self.fielddescrs[i])):
+                if self.fielddescrs[i][j] is not other.fielddescrs[i][j]:
+                    bad[self] = True
+                    bad[other] = True
+                    return False
+                if not self.fieldstate[p].generalization_of(other.fieldstate[p],
+                                                            renum, bad):
+                    bad[self] = True
+                    bad[other] = True
+                    return False
+                p += 1
+        return True
+
+    def _generalization_of(self, other):
+        return (isinstance(other, VArrayStructStateInfo) and
+            self.arraydescr is other.arraydescr)
+
+    def _enum(self, virtual_state):
+        for s in self.fieldstate:
+            s.enum(virtual_state)
+
+    def enum_forced_boxes(self, boxes, value, optimizer):
+        assert isinstance(value, virtualize.VArrayStructValue)
+        assert value.is_virtual()
+        p = 0
+        for i in range(len(self.fielddescrs)):
+            for j in range(len(self.fielddescrs[i])):
+                v = value._items[i][self.fielddescrs[i][j]]
+                s = self.fieldstate[p]
+                if s.position > self.position:
+                    s.enum_forced_boxes(boxes, v, optimizer)
+                p += 1
+
+    def debug_header(self, indent):
+        debug_print(indent + 'VArrayStructStateInfo(%d):' % self.position)
+
+
 class NotVirtualStateInfo(AbstractVirtualStateInfo):
     def __init__(self, value):
         self.known_class = value.known_class
@@ -277,7 +346,7 @@
             op = ResOperation(rop.GUARD_CLASS, [box, self.known_class], None)
             extra_guards.append(op)
             return
-        
+
         if self.level == LEVEL_NONNULL and \
                other.level == LEVEL_UNKNOWN and \
                isinstance(box, BoxPtr) and \
@@ -285,7 +354,7 @@
             op = ResOperation(rop.GUARD_NONNULL, [box], None)
             extra_guards.append(op)
             return
-        
+
         if self.level == LEVEL_UNKNOWN and \
                other.level == LEVEL_UNKNOWN and \
                isinstance(box, BoxInt) and \
@@ -309,7 +378,7 @@
                     op = ResOperation(rop.GUARD_TRUE, [res], None)
                     extra_guards.append(op)
             return
-        
+
         # Remaining cases are probably not interesting
         raise InvalidLoop
         if self.level == LEVEL_CONSTANT:
@@ -319,7 +388,7 @@
     def enum_forced_boxes(self, boxes, value, optimizer):
         if self.level == LEVEL_CONSTANT:
             return
-        assert 0 <= self.position_in_notvirtuals 
+        assert 0 <= self.position_in_notvirtuals
         boxes[self.position_in_notvirtuals] = value.force_box(optimizer)
 
     def _enum(self, virtual_state):
@@ -348,7 +417,7 @@
         lb = ''
         if self.lenbound:
             lb = ', ' + self.lenbound.bound.__repr__()
-        
+
         debug_print(indent + mark + 'NotVirtualInfo(%d' % self.position +
                     ', ' + l + ', ' + self.intbound.__repr__() + lb + ')')
 
@@ -370,7 +439,7 @@
                 return False
         return True
 
-    def generate_guards(self, other, args, cpu, extra_guards):        
+    def generate_guards(self, other, args, cpu, extra_guards):
         assert len(self.state) == len(other.state) == len(args)
         renum = {}
         for i in range(len(self.state)):
@@ -393,7 +462,7 @@
                     inputargs.append(box)
 
         assert None not in inputargs
-            
+
         return inputargs
 
     def debug_print(self, hdr='', bad=None):
@@ -412,7 +481,7 @@
 
     def register_virtual_fields(self, keybox, fieldboxes):
         self.fieldboxes[keybox] = fieldboxes
-        
+
     def already_seen_virtual(self, keybox):
         return keybox in self.fieldboxes
 
@@ -463,6 +532,9 @@
     def make_varray(self, arraydescr):
         return VArrayStateInfo(arraydescr)
 
+    def make_varraystruct(self, arraydescr, fielddescrs):
+        return VArrayStructStateInfo(arraydescr, fielddescrs)
+
 class BoxNotProducable(Exception):
     pass
 
@@ -479,6 +551,7 @@
         optimizer.produce_potential_short_preamble_ops(self)
 
         self.short_boxes = {}
+        self.short_boxes_in_production = {}
 
         for box in self.potential_ops.keys():
             try:
@@ -501,12 +574,12 @@
             else: # Low priority
                 lo -= 1
         return alts
-            
+
     def renamed(self, box):
         if box in self.rename:
             return self.rename[box]
         return box
-    
+
     def add_to_short(self, box, op):
         if op:
             op = op.clone()
@@ -528,12 +601,16 @@
             self.optimizer.make_equal_to(newbox, value)
         else:
             self.short_boxes[box] = op
-        
+
     def produce_short_preamble_box(self, box):
         if box in self.short_boxes:
-            return 
+            return
         if isinstance(box, Const):
-            return 
+            return
+        if box in self.short_boxes_in_production:
+            raise BoxNotProducable
+        self.short_boxes_in_production[box] = True
+        
         if box in self.potential_ops:
             ops = self.prioritized_alternatives(box)
             produced_one = False
@@ -570,7 +647,7 @@
             else:
                 debug_print(logops.repr_of_arg(box) + ': None')
         debug_stop('jit-short-boxes')
-        
+
     def operations(self):
         if not we_are_translated(): # For tests
             ops = self.short_boxes.values()
@@ -588,7 +665,7 @@
         if not isinstance(oldbox, Const) and newbox not in self.short_boxes:
             self.short_boxes[newbox] = self.short_boxes[oldbox]
         self.aliases[newbox] = oldbox
-        
+
     def original(self, box):
         while box in self.aliases:
             box = self.aliases[box]
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
@@ -1,8 +1,9 @@
 from pypy.jit.codewriter.effectinfo import EffectInfo
 from pypy.jit.metainterp.history import (BoxInt, Const, ConstInt, ConstPtr,
-    get_const_ptr_for_string, get_const_ptr_for_unicode)
+    get_const_ptr_for_string, get_const_ptr_for_unicode, BoxPtr, REF, INT)
 from pypy.jit.metainterp.optimizeopt import optimizer, virtualize
-from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1, llhelper
+from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1
+from pypy.jit.metainterp.optimizeopt.optimizer import llhelper, REMOVED
 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
 from pypy.jit.metainterp.resoperation import rop, ResOperation
 from pypy.rlib.objectmodel import specialize, we_are_translated
@@ -106,7 +107,12 @@
         if not we_are_translated():
             op.name = 'FORCE'
         optforce.emit_operation(op)
-        self.string_copy_parts(optforce, box, CONST_0, self.mode)
+        self.initialize_forced_string(optforce, box, CONST_0, self.mode)
+
+    def initialize_forced_string(self, string_optimizer, targetbox,
+                                 offsetbox, mode):
+        return self.string_copy_parts(string_optimizer, targetbox,
+                                      offsetbox, mode)
 
 
 class VStringPlainValue(VAbstractStringValue):
@@ -114,11 +120,20 @@
     _lengthbox = None     # cache only
 
     def setup(self, size):
-        self._chars = [optimizer.CVAL_UNINITIALIZED_ZERO] * size
+        # in this list, None means: "it's probably uninitialized so far,
+        # but maybe it was actually filled."  So to handle this case,
+        # strgetitem cannot be virtual-ized and must be done as a residual
+        # operation.  By contrast, any non-None value means: we know it
+        # is initialized to this value; strsetitem() there makes no sense.
+        # Also, as long as self.is_virtual(), then we know that no-one else
+        # could have written to the string, so we know that in this case
+        # "None" corresponds to "really uninitialized".
+        self._chars = [None] * size
 
     def setup_slice(self, longerlist, start, stop):
         assert 0 <= start <= stop <= len(longerlist)
         self._chars = longerlist[start:stop]
+        # slice the 'longerlist', which may also contain Nones
 
     def getstrlen(self, _, mode):
         if self._lengthbox is None:
@@ -126,53 +141,66 @@
         return self._lengthbox
 
     def getitem(self, index):
-        return self._chars[index]
+        return self._chars[index]     # may return None!
 
     def setitem(self, index, charvalue):
         assert isinstance(charvalue, optimizer.OptValue)
+        assert self._chars[index] is None, (
+            "setitem() on an already-initialized location")
         self._chars[index] = charvalue
 
+    def is_completely_initialized(self):
+        for c in self._chars:
+            if c is None:
+                return False
+        return True
+
     @specialize.arg(1)
     def get_constant_string_spec(self, mode):
         for c in self._chars:
-            if c is optimizer.CVAL_UNINITIALIZED_ZERO or not c.is_constant():
+            if c is None or not c.is_constant():
                 return None
         return mode.emptystr.join([mode.chr(c.box.getint())
                                    for c in self._chars])
 
     def string_copy_parts(self, string_optimizer, targetbox, offsetbox, mode):
-        if not self.is_virtual() and targetbox is not self.box:
-            lengthbox = self.getstrlen(string_optimizer, mode)
-            srcbox = self.force_box(string_optimizer)
-            return copy_str_content(string_optimizer, srcbox, targetbox,
-                                CONST_0, offsetbox, lengthbox, mode)
+        if not self.is_virtual() and not self.is_completely_initialized():
+            return VAbstractStringValue.string_copy_parts(
+                self, string_optimizer, targetbox, offsetbox, mode)
+        else:
+            return self.initialize_forced_string(string_optimizer, targetbox,
+                                                 offsetbox, mode)
+
+    def initialize_forced_string(self, string_optimizer, targetbox,
+                                 offsetbox, mode):
         for i in range(len(self._chars)):
-            charbox = self._chars[i].force_box(string_optimizer)
-            if not (isinstance(charbox, Const) and charbox.same_constant(CONST_0)):
-                string_optimizer.emit_operation(ResOperation(mode.STRSETITEM, [targetbox,
-                                                                               offsetbox,
-                                                                               charbox],
-                                                  None))
+            assert isinstance(targetbox, BoxPtr)   # ConstPtr never makes sense
+            charvalue = self.getitem(i)
+            if charvalue is not None:
+                charbox = charvalue.force_box(string_optimizer)
+                if not (isinstance(charbox, Const) and
+                        charbox.same_constant(CONST_0)):
+                    op = ResOperation(mode.STRSETITEM, [targetbox,
+                                                        offsetbox,
+                                                        charbox],
+                                      None)
+                    string_optimizer.emit_operation(op)
             offsetbox = _int_add(string_optimizer, offsetbox, CONST_1)
         return offsetbox
 
     def get_args_for_fail(self, modifier):
         if self.box is None and not modifier.already_seen_virtual(self.keybox):
-            charboxes = [value.get_key_box() for value in self._chars]
+            charboxes = []
+            for value in self._chars:
+                if value is not None:
+                    box = value.get_key_box()
+                else:
+                    box = None
+                charboxes.append(box)
             modifier.register_virtual_fields(self.keybox, charboxes)
             for value in self._chars:
-                value.get_args_for_fail(modifier)
-
-    def FIXME_enum_forced_boxes(self, boxes, already_seen):
-        key = self.get_key_box()
-        if key in already_seen:
-            return
-        already_seen[key] = None
-        if self.box is None:
-            for box in self._chars:
-                box.enum_forced_boxes(boxes, already_seen)
-        else:
-            boxes.append(self.box)
+                if value is not None:
+                    value.get_args_for_fail(modifier)
 
     def _make_virtual(self, modifier):
         return modifier.make_vstrplain(self.mode is mode_unicode)
@@ -180,6 +208,7 @@
 
 class VStringConcatValue(VAbstractStringValue):
     """The concatenation of two other strings."""
+    _attrs_ = ('left', 'right', 'lengthbox')
 
     lengthbox = None     # or the computed length
 
@@ -226,18 +255,6 @@
             self.left.get_args_for_fail(modifier)
             self.right.get_args_for_fail(modifier)
 
-    def FIXME_enum_forced_boxes(self, boxes, already_seen):
-        key = self.get_key_box()
-        if key in already_seen:
-            return
-        already_seen[key] = None
-        if self.box is None:
-            self.left.enum_forced_boxes(boxes, already_seen)
-            self.right.enum_forced_boxes(boxes, already_seen)
-            self.lengthbox = None
-        else:
-            boxes.append(self.box)
-
     def _make_virtual(self, modifier):
         return modifier.make_vstrconcat(self.mode is mode_unicode)
 
@@ -284,18 +301,6 @@
             self.vstart.get_args_for_fail(modifier)
             self.vlength.get_args_for_fail(modifier)
 
-    def FIXME_enum_forced_boxes(self, boxes, already_seen):
-        key = self.get_key_box()
-        if key in already_seen:
-            return
-        already_seen[key] = None
-        if self.box is None:
-            self.vstr.enum_forced_boxes(boxes, already_seen)
-            self.vstart.enum_forced_boxes(boxes, already_seen)
-            self.vlength.enum_forced_boxes(boxes, already_seen)
-        else:
-            boxes.append(self.box)
-
     def _make_virtual(self, modifier):
         return modifier.make_vstrslice(self.mode is mode_unicode)
 
@@ -312,6 +317,7 @@
         for i in range(lengthbox.value):
             charbox = _strgetitem(string_optimizer, srcbox, srcoffsetbox, mode)
             srcoffsetbox = _int_add(string_optimizer, srcoffsetbox, CONST_1)
+            assert isinstance(targetbox, BoxPtr)   # ConstPtr never makes sense
             string_optimizer.emit_operation(ResOperation(mode.STRSETITEM, [targetbox,
                                                                            offsetbox,
                                                                            charbox],
@@ -322,6 +328,7 @@
             nextoffsetbox = _int_add(string_optimizer, offsetbox, lengthbox)
         else:
             nextoffsetbox = None
+        assert isinstance(targetbox, BoxPtr)   # ConstPtr never makes sense
         op = ResOperation(mode.COPYSTRCONTENT, [srcbox, targetbox,
                                                 srcoffsetbox, offsetbox,
                                                 lengthbox], None)
@@ -408,6 +415,7 @@
 
     def optimize_STRSETITEM(self, op):
         value = self.getvalue(op.getarg(0))
+        assert not value.is_constant() # strsetitem(ConstPtr) never makes sense
         if value.is_virtual() and isinstance(value, VStringPlainValue):
             indexbox = self.get_constant_box(op.getarg(1))
             if indexbox is not None:
@@ -441,11 +449,20 @@
         #
         if isinstance(value, VStringPlainValue):  # even if no longer virtual
             if vindex.is_constant():
-                res = value.getitem(vindex.box.getint())
-                # If it is uninitialized we can't return it, it was set by a
-                # COPYSTRCONTENT, not a STRSETITEM
-                if res is not optimizer.CVAL_UNINITIALIZED_ZERO:
-                    return res
+                result = value.getitem(vindex.box.getint())
+                if result is not None:
+                    return result
+        #
+        if isinstance(value, VStringConcatValue) and vindex.is_constant():
+            len1box = value.left.getstrlen(self, mode)
+            if isinstance(len1box, ConstInt):
+                index = vindex.box.getint()
+                len1 = len1box.getint()
+                if index < len1:
+                    return self.strgetitem(value.left, vindex, mode)
+                else:
+                    vindex = optimizer.ConstantValue(ConstInt(index - len1))
+                    return self.strgetitem(value.right, vindex, mode)
         #
         resbox = _strgetitem(self, value.force_box(self), vindex.force_box(self), mode)
         return self.getvalue(resbox)
@@ -467,6 +484,11 @@
 
     def _optimize_COPYSTRCONTENT(self, op, mode):
         # args: src dst srcstart dststart length
+        assert op.getarg(0).type == REF
+        assert op.getarg(1).type == REF
+        assert op.getarg(2).type == INT
+        assert op.getarg(3).type == INT
+        assert op.getarg(4).type == INT
         src = self.getvalue(op.getarg(0))
         dst = self.getvalue(op.getarg(1))
         srcstart = self.getvalue(op.getarg(2))
@@ -508,6 +530,11 @@
 
     optimize_CALL_PURE = optimize_CALL
 
+    def optimize_GUARD_NO_EXCEPTION(self, op):
+        if self.last_emitted_operation is REMOVED:
+            return
+        self.emit_operation(op)
+
     def opt_call_str_STR2UNICODE(self, op):
         # Constant-fold unicode("constant string").
         # More generally, supporting non-constant but virtual cases is
@@ -522,6 +549,7 @@
         except UnicodeDecodeError:
             return False
         self.make_constant(op.result, get_const_ptr_for_unicode(u))
+        self.last_emitted_operation = REMOVED
         return True
 
     def opt_call_stroruni_STR_CONCAT(self, op, mode):
@@ -538,13 +566,12 @@
         vstart = self.getvalue(op.getarg(2))
         vstop = self.getvalue(op.getarg(3))
         #
-        if (isinstance(vstr, VStringPlainValue) and vstart.is_constant()
-            and vstop.is_constant()):
-            # slicing with constant bounds of a VStringPlainValue
-            value = self.make_vstring_plain(op.result, op, mode)
-            value.setup_slice(vstr._chars, vstart.box.getint(),
-                                           vstop.box.getint())
-            return True
+        #if (isinstance(vstr, VStringPlainValue) and vstart.is_constant()
+        #    and vstop.is_constant()):
+        #    value = self.make_vstring_plain(op.result, op, mode)
+        #    value.setup_slice(vstr._chars, vstart.box.getint(),
+        #                      vstop.box.getint())
+        #    return True
         #
         vstr.ensure_nonnull()
         lengthbox = _int_sub(self, vstop.force_box(self),
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
@@ -165,7 +165,7 @@
         if not we_are_translated():
             for b in registers[count:]:
                 assert not oldbox.same_box(b)
-                
+
 
     def make_result_of_lastop(self, resultbox):
         got_type = resultbox.type
@@ -199,7 +199,7 @@
                     'float_add', 'float_sub', 'float_mul', 'float_truediv',
                     'float_lt', 'float_le', 'float_eq',
                     'float_ne', 'float_gt', 'float_ge',
-                    'ptr_eq', 'ptr_ne',
+                    'ptr_eq', 'ptr_ne', 'instance_ptr_eq', 'instance_ptr_ne',
                     ]:
         exec py.code.Source('''
             @arguments("box", "box")
@@ -240,8 +240,8 @@
         return self.execute(rop.PTR_EQ, box, history.CONST_NULL)
 
     @arguments("box")
-    def opimpl_cast_opaque_ptr(self, box):
-        return self.execute(rop.CAST_OPAQUE_PTR, box)
+    def opimpl_mark_opaque_ptr(self, box):
+        return self.execute(rop.MARK_OPAQUE_PTR, box)
 
     @arguments("box")
     def _opimpl_any_return(self, box):
@@ -604,7 +604,7 @@
     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):
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
@@ -90,7 +90,10 @@
         return op
 
     def __repr__(self):
-        return self.repr()
+        try:
+            return self.repr()
+        except NotImplementedError:
+            return object.__repr__(self)
 
     def repr(self, graytext=False):
         # RPython-friendly version
@@ -404,8 +407,8 @@
     'FLOAT_TRUEDIV/2',
     'FLOAT_NEG/1',
     'FLOAT_ABS/1',
-    'CAST_FLOAT_TO_INT/1',
-    'CAST_INT_TO_FLOAT/1',
+    'CAST_FLOAT_TO_INT/1',          # don't use for unsigned ints; we would
+    'CAST_INT_TO_FLOAT/1',          # need some messy code in the backend
     'CAST_FLOAT_TO_SINGLEFLOAT/1',
     'CAST_SINGLEFLOAT_TO_FLOAT/1',
     #
@@ -437,7 +440,8 @@
     #
     'PTR_EQ/2b',
     'PTR_NE/2b',
-    'CAST_OPAQUE_PTR/1b',
+    'INSTANCE_PTR_EQ/2b',
+    'INSTANCE_PTR_NE/2b',
     #
     'ARRAYLEN_GC/1d',
     'STRLEN/1',
@@ -469,6 +473,7 @@
     'FORCE_TOKEN/0',
     'VIRTUAL_REF/2',         # removed before it's passed to the backend
     'READ_TIMESTAMP/0',
+    'MARK_OPAQUE_PTR/1b',
     '_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations -----
 
     'SETARRAYITEM_GC/3d',
diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py
--- a/pypy/jit/metainterp/resume.py
+++ b/pypy/jit/metainterp/resume.py
@@ -126,6 +126,7 @@
 UNASSIGNED = tag(-1<<13, TAGBOX)
 UNASSIGNEDVIRTUAL = tag(-1<<13, TAGVIRTUAL)
 NULLREF = tag(-1, TAGCONST)
+UNINITIALIZED = tag(-2, TAGCONST)   # used for uninitialized string characters
 
 
 class ResumeDataLoopMemo(object):
@@ -139,7 +140,7 @@
         self.numberings = {}
         self.cached_boxes = {}
         self.cached_virtuals = {}
-    
+
         self.nvirtuals = 0
         self.nvholes = 0
         self.nvreused = 0
@@ -273,6 +274,9 @@
     def make_varray(self, arraydescr):
         return VArrayInfo(arraydescr)
 
+    def make_varraystruct(self, arraydescr, fielddescrs):
+        return VArrayStructInfo(arraydescr, fielddescrs)
+
     def make_vstrplain(self, is_unicode=False):
         if is_unicode:
             return VUniPlainInfo()
@@ -402,7 +406,7 @@
                 virtuals[num] = vinfo
 
         if self._invalidation_needed(len(liveboxes), nholes):
-            memo.clear_box_virtual_numbers()           
+            memo.clear_box_virtual_numbers()
 
     def _invalidation_needed(self, nliveboxes, nholes):
         memo = self.memo
@@ -436,6 +440,8 @@
         self.storage.rd_pendingfields = rd_pendingfields
 
     def _gettagged(self, box):
+        if box is None:
+            return UNINITIALIZED
         if isinstance(box, Const):
             return self.memo.getconst(box)
         else:
@@ -455,7 +461,7 @@
 
     def debug_prints(self):
         raise NotImplementedError
-        
+
 class AbstractVirtualStructInfo(AbstractVirtualInfo):
     def __init__(self, fielddescrs):
         self.fielddescrs = fielddescrs
@@ -537,6 +543,29 @@
         for i in self.fieldnums:
             debug_print("\t\t", str(untag(i)))
 
+
+class VArrayStructInfo(AbstractVirtualInfo):
+    def __init__(self, arraydescr, fielddescrs):
+        self.arraydescr = arraydescr
+        self.fielddescrs = fielddescrs
+
+    def debug_prints(self):
+        debug_print("\tvarraystructinfo", self.arraydescr)
+        for i in self.fieldnums:
+            debug_print("\t\t", str(untag(i)))
+
+    @specialize.argtype(1)
+    def allocate(self, decoder, index):
+        array = decoder.allocate_array(self.arraydescr, len(self.fielddescrs))
+        decoder.virtuals_cache[index] = array
+        p = 0
+        for i in range(len(self.fielddescrs)):
+            for j in range(len(self.fielddescrs[i])):
+                decoder.setinteriorfield(i, self.fielddescrs[i][j], array, self.fieldnums[p])
+                p += 1
+        return array
+
+
 class VStrPlainInfo(AbstractVirtualInfo):
     """Stands for the string made out of the characters of all fieldnums."""
 
@@ -546,7 +575,9 @@
         string = decoder.allocate_string(length)
         decoder.virtuals_cache[index] = string
         for i in range(length):
-            decoder.string_setitem(string, i, self.fieldnums[i])
+            charnum = self.fieldnums[i]
+            if not tagged_eq(charnum, UNINITIALIZED):
+                decoder.string_setitem(string, i, charnum)
         return string
 
     def debug_prints(self):
@@ -599,7 +630,9 @@
         string = decoder.allocate_unicode(length)
         decoder.virtuals_cache[index] = string
         for i in range(length):
-            decoder.unicode_setitem(string, i, self.fieldnums[i])
+            charnum = self.fieldnums[i]
+            if not tagged_eq(charnum, UNINITIALIZED):
+                decoder.unicode_setitem(string, i, charnum)
         return string
 
     def debug_prints(self):
@@ -884,6 +917,17 @@
         self.metainterp.execute_and_record(rop.SETFIELD_GC, descr,
                                            structbox, fieldbox)
 
+    def setinteriorfield(self, index, descr, array, fieldnum):
+        if descr.is_pointer_field():
+            kind = REF
+        elif descr.is_float_field():
+            kind = FLOAT
+        else:
+            kind = INT
+        fieldbox = self.decode_box(fieldnum, kind)
+        self.metainterp.execute_and_record(rop.SETINTERIORFIELD_GC, descr,
+                                           array, ConstInt(index), fieldbox)
+
     def setarrayitem_int(self, arraydescr, arraybox, index, fieldnum):
         self._setarrayitem(arraydescr, arraybox, index, fieldnum, INT)
 
@@ -1164,6 +1208,17 @@
             newvalue = self.decode_int(fieldnum)
             self.cpu.bh_setfield_gc_i(struct, descr, newvalue)
 
+    def setinteriorfield(self, index, descr, array, fieldnum):
+        if descr.is_pointer_field():
+            newvalue = self.decode_ref(fieldnum)
+            self.cpu.bh_setinteriorfield_gc_r(array, index, descr, newvalue)
+        elif descr.is_float_field():
+            newvalue = self.decode_float(fieldnum)
+            self.cpu.bh_setinteriorfield_gc_f(array, index, descr, newvalue)
+        else:
+            newvalue = self.decode_int(fieldnum)
+            self.cpu.bh_setinteriorfield_gc_i(array, index, descr, newvalue)
+
     def setarrayitem_int(self, arraydescr, array, index, fieldnum):
         newvalue = self.decode_int(fieldnum)
         self.cpu.bh_setarrayitem_gc_i(arraydescr, array, index, newvalue)
diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py
--- a/pypy/jit/metainterp/test/support.py
+++ b/pypy/jit/metainterp/test/support.py
@@ -12,7 +12,7 @@
 from pypy.rlib.rfloat import isnan
 
 def _get_jitcodes(testself, CPUClass, func, values, type_system,
-                  supports_longlong=False, **kwds):
+                  supports_longlong=False, translationoptions={}, **kwds):
     from pypy.jit.codewriter import support
 
     class FakeJitCell(object):
@@ -42,7 +42,8 @@
         enable_opts = ALL_OPTS_DICT
 
     func._jit_unroll_safe_ = True
-    rtyper = support.annotate(func, values, type_system=type_system)
+    rtyper = support.annotate(func, values, type_system=type_system,
+                              translationoptions=translationoptions)
     graphs = rtyper.annotator.translator.graphs
     testself.all_graphs = graphs
     result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0]
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
@@ -10,6 +10,7 @@
 from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
 from pypy.jit.metainterp.warmspot import get_stats
 from pypy.jit.metainterp.warmstate import set_future_value
+from pypy.rlib import rerased
 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,
@@ -3435,7 +3436,159 @@
             return sa
         res = self.meta_interp(f, [16])
         assert res == f(16)
-        
+
+    def test_ptr_eq(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_instance_ptr_eq(self):
+        myjitdriver = JitDriver(greens = [], reds = ["n", "i", "a1", "a2"])
+        class A(object):
+            pass
+        def f(n):
+            a1 = A()
+            a2 = A()
+            i = 0
+            while n > 0:
+                myjitdriver.jit_merge_point(n=n, i=i, a1=a1, a2=a2)
+                if n % 2:
+                    a = a2
+                else:
+                    a = a1
+                i += a is a1
+                n -= 1
+            return i
+        res = self.meta_interp(f, [10])
+        assert res == f(10)
+        def f(n):
+            a1 = A()
+            a2 = A()
+            i = 0
+            while n > 0:
+                myjitdriver.jit_merge_point(n=n, i=i, a1=a1, a2=a2)
+                if n % 2:
+                    a = a2
+                else:
+                    a = a1
+                if a is a2:
+                    i += 1
+                n -= 1
+            return i
+        res = self.meta_interp(f, [10])
+        assert res == f(10)
+
+    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 = {"q": 1}
+                if n % 2:
+                    d["k"] = n
+                else:
+                    d["z"] = n
+                n -= len(d) - d["q"]
+            return n
+        res = self.meta_interp(f, [10])
+        assert res == 0
+
+    def test_virtual_dict_constant_keys(self):
+        myjitdriver = JitDriver(greens = [], reds = ["n"])
+        def g(d):
+            return d["key"] - 1
+
+        def f(n):
+            while n > 0:
+                myjitdriver.jit_merge_point(n=n)
+                x = {"key": n}
+                n = g(x)
+                del x["key"]
+            return n
+
+        res = self.meta_interp(f, [10])
+        assert res == 0
+        self.check_loops({"int_sub": 1, "int_gt": 1, "guard_true": 1, "jump": 1})
+
+    def test_virtual_opaque_ptr(self):
+        myjitdriver = JitDriver(greens = [], reds = ["n"])
+        erase, unerase = rerased.new_erasing_pair("x")
+        @look_inside_iff(lambda x: isvirtual(x))
+        def g(x):
+            return x[0]
+        def f(n):
+            while n > 0:
+                myjitdriver.jit_merge_point(n=n)
+                x = []
+                y = erase(x)
+                z = unerase(y)
+                z.append(1)
+                n -= g(z)
+            return n
+        res = self.meta_interp(f, [10])
+        assert res == 0
+        self.check_loops({"int_sub": 1, "int_gt": 1, "guard_true": 1, "jump": 1})
+
+    def test_virtual_opaque_dict(self):
+        myjitdriver = JitDriver(greens = [], reds = ["n"])
+        erase, unerase = rerased.new_erasing_pair("x")
+        @look_inside_iff(lambda x: isvirtual(x))
+        def g(x):
+            return x[0]["key"] - 1
+        def f(n):
+            while n > 0:
+                myjitdriver.jit_merge_point(n=n)
+                x = [{}]
+                x[0]["key"] = n
+                x[0]["other key"] = n
+                y = erase(x)
+                z = unerase(y)
+                n = g(x)
+            return n
+        res = self.meta_interp(f, [10])
+        assert res == 0
+        self.check_loops({"int_sub": 1, "int_gt": 1, "guard_true": 1, "jump": 1})
+
+    def test_convert_from_SmallFunctionSetPBCRepr_to_FunctionsPBCRepr(self):
+        f1 = lambda n: n+1
+        f2 = lambda n: n+2
+        f3 = lambda n: n+3
+        f4 = lambda n: n+4
+        f5 = lambda n: n+5
+        f6 = lambda n: n+6
+        f7 = lambda n: n+7
+        f8 = lambda n: n+8
+        def h(n, x):
+            return x(n)
+        h._dont_inline = True
+        def g(n, x):
+            return h(n, x)
+        g._dont_inline = True
+        def f(n):
+            n = g(n, f1)
+            n = g(n, f2)
+            n = h(n, f3)
+            n = h(n, f4)
+            n = h(n, f5)
+            n = h(n, f6)
+            n = h(n, f7)
+            n = h(n, f8)
+            return n
+        assert f(5) == 41
+        translationoptions = {'withsmallfuncsets': 3}
+        self.interp_operations(f, [5], translationoptions=translationoptions)
 
 
 class TestLLtype(BaseLLtypeTests, LLJitMixin):
@@ -3490,11 +3643,12 @@
                     o = o.dec()
                 pc += 1
             return pc
-        res = self.meta_interp(main, [False, 100, True], taggedpointers=True)
+        topt = {'taggedpointers': True}
+        res = self.meta_interp(main, [False, 100, True],
+                               translationoptions=topt)
 
     def test_rerased(self):
-        from pypy.rlib.rerased import erase_int, unerase_int, new_erasing_pair
-        eraseX, uneraseX = new_erasing_pair("X")
+        eraseX, uneraseX = rerased.new_erasing_pair("X")
         #
         class X:
             def __init__(self, a, b):
@@ -3507,19 +3661,20 @@
                 e = eraseX(X(i, j))
             else:
                 try:
-                    e = erase_int(i)
+                    e = rerased.erase_int(i)
                 except OverflowError:
                     return -42
             if j & 1:
                 x = uneraseX(e)
                 return x.a - x.b
             else:
-                return unerase_int(e)
+                return rerased.unerase_int(e)
         #
-        x = self.interp_operations(f, [-128, 0], taggedpointers=True)
+        topt = {'taggedpointers': True}
+        x = self.interp_operations(f, [-128, 0], translationoptions=topt)
         assert x == -128
         bigint = sys.maxint//2 + 1
-        x = self.interp_operations(f, [bigint, 0], taggedpointers=True)
+        x = self.interp_operations(f, [bigint, 0], translationoptions=topt)
         assert x == -42
-        x = self.interp_operations(f, [1000, 1], taggedpointers=True)
+        x = self.interp_operations(f, [1000, 1], translationoptions=topt)
         assert x == 999
diff --git a/pypy/jit/metainterp/test/test_float.py b/pypy/jit/metainterp/test/test_float.py
--- a/pypy/jit/metainterp/test/test_float.py
+++ b/pypy/jit/metainterp/test/test_float.py
@@ -1,5 +1,6 @@
-import math
+import math, sys
 from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
+from pypy.rlib.rarithmetic import intmask, r_uint
 
 
 class FloatTests:
@@ -45,6 +46,34 @@
         res = self.interp_operations(f, [-2.0])
         assert res == -8.5
 
+    def test_cast_float_to_int(self):
+        def g(f):
+            return int(f)
+        res = self.interp_operations(g, [-12345.9])
+        assert res == -12345
+
+    def test_cast_float_to_uint(self):
+        def g(f):
+            return intmask(r_uint(f))
+        res = self.interp_operations(g, [sys.maxint*2.0])
+        assert res == intmask(long(sys.maxint*2.0))
+        res = self.interp_operations(g, [-12345.9])
+        assert res == -12345
+
+    def test_cast_int_to_float(self):
+        def g(i):
+            return float(i)
+        res = self.interp_operations(g, [-12345])
+        assert type(res) is float and res == -12345.0
+
+    def test_cast_uint_to_float(self):
+        def g(i):
+            return float(r_uint(i))
+        res = self.interp_operations(g, [intmask(sys.maxint*2)])
+        assert type(res) is float and res == float(sys.maxint*2)
+        res = self.interp_operations(g, [-12345])
+        assert type(res) is float and res == float(long(r_uint(-12345)))
+
 
 class TestOOtype(FloatTests, OOJitMixin):
     pass
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
@@ -371,3 +371,17 @@
         assert h.is_unescaped(box1)
         h.invalidate_caches(rop.SETARRAYITEM_GC, None, [box2, index1, box1])
         assert not h.is_unescaped(box1)
+
+        h = HeapCache()
+        h.new_array(box1, lengthbox1)
+        h.new(box2)
+        assert h.is_unescaped(box1)
+        assert h.is_unescaped(box2)
+        h.invalidate_caches(rop.SETARRAYITEM_GC, None, [box1, lengthbox2, box2])
+        assert h.is_unescaped(box1)
+        assert h.is_unescaped(box2)
+        h.invalidate_caches(
+            rop.CALL, FakeCallDescr(FakeEffektinfo.EF_RANDOM_EFFECTS), [box1]
+        )
+        assert not h.is_unescaped(box1)
+        assert not h.is_unescaped(box2)
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
@@ -1135,16 +1135,11 @@
     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
+        del Const.__eq__
 
 def test_virtual_adder_make_varray():
     b2s, b4s = [BoxPtr(), BoxInt(4)]
diff --git a/pypy/jit/metainterp/test/test_tracingopts.py b/pypy/jit/metainterp/test/test_tracingopts.py
--- a/pypy/jit/metainterp/test/test_tracingopts.py
+++ b/pypy/jit/metainterp/test/test_tracingopts.py
@@ -3,6 +3,7 @@
 from pypy.jit.metainterp.test.support import LLJitMixin
 from pypy.rlib import jit
 from pypy.rlib.rarithmetic import ovfcheck
+from pypy.rlib.rstring import StringBuilder
 
 import py
 
@@ -590,4 +591,14 @@
         assert res == 4
         self.check_operations_history(int_add_ovf=0)
         res = self.interp_operations(fn, [sys.maxint])
-        assert res == 12
\ No newline at end of file
+        assert res == 12
+
+    def test_copy_str_content(self):
+        def fn(n):
+            a = StringBuilder()
+            x = [1]
+            a.append("hello world")
+            return x[0]
+        res = self.interp_operations(fn, [0])
+        assert res == 1
+        self.check_operations_history(getarrayitem_gc=0, getarrayitem_gc_pure=0 )
\ No newline at end of file
diff --git a/pypy/jit/metainterp/test/test_virtualstate.py b/pypy/jit/metainterp/test/test_virtualstate.py
--- a/pypy/jit/metainterp/test/test_virtualstate.py
+++ b/pypy/jit/metainterp/test/test_virtualstate.py
@@ -847,7 +847,8 @@
         i5 = arraylen_gc(p2, descr=arraydescr)
         i6 = int_ge(i5, 1)
         guard_true(i6) []
-        jump(p0, p1, p2)
+        p3 = getarrayitem_gc(p2, 0, descr=arraydescr)
+        jump(p0, p1, p3, p2)
         """
         self.optimize_bridge(loop, bridge, expected, p0=self.myptr)
 
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
@@ -48,13 +48,13 @@
     translator.warmrunnerdesc = warmrunnerdesc    # for later debugging
 
 def ll_meta_interp(function, args, backendopt=False, type_system='lltype',
-                   listcomp=False, **kwds):
+                   listcomp=False, translationoptions={}, **kwds):
     if listcomp:
         extraconfigopts = {'translation.list_comprehension_operations': True}
     else:
         extraconfigopts = {}
-    if kwds.pop("taggedpointers", False):
-        extraconfigopts["translation.taggedpointers"] = True
+    for key, value in translationoptions.items():
+        extraconfigopts['translation.' + key] = value
     interp, graph = get_interpreter(function, args,
                                     backendopt=False,  # will be done below
                                     type_system=type_system,
@@ -62,7 +62,7 @@
     clear_tcache()
     return jittify_and_run(interp, graph, args, backendopt=backendopt, **kwds)
 
-def jittify_and_run(interp, graph, args, repeat=1,
+def jittify_and_run(interp, graph, args, repeat=1, graph_and_interp_only=False,
                     backendopt=False, trace_limit=sys.maxint,
                     inline=False, loop_longevity=0, retrace_limit=5,
                     function_threshold=4,
@@ -93,6 +93,8 @@
         jd.warmstate.set_param_max_retrace_guards(max_retrace_guards)
         jd.warmstate.set_param_enable_opts(enable_opts)
     warmrunnerdesc.finish()
+    if graph_and_interp_only:
+        return interp, graph
     res = interp.eval_graph(graph, args)
     if not kwds.get('translate_support_code', False):
         warmrunnerdesc.metainterp_sd.profiler.finish()
@@ -157,6 +159,9 @@
 def get_stats():
     return pyjitpl._warmrunnerdesc.stats
 
+def reset_stats():
+    pyjitpl._warmrunnerdesc.stats.clear()
+
 def get_translator():
     return pyjitpl._warmrunnerdesc.translator
 
diff --git a/pypy/module/_file/interp_file.py b/pypy/module/_file/interp_file.py
--- a/pypy/module/_file/interp_file.py
+++ b/pypy/module/_file/interp_file.py
@@ -206,24 +206,28 @@
     @unwrap_spec(size=int)
     def direct_readlines(self, size=0):
         stream = self.getstream()
-        # NB. this implementation is very inefficient for unbuffered
-        # streams, but ok if stream.readline() is efficient.
+        # this is implemented as: .read().split('\n')
+        # except that it keeps the \n in the resulting strings
         if size <= 0:
-            result = []
-            while True:
-                line = stream.readline()
-                if not line:
-                    break
-                result.append(line)
-                size -= len(line)
+            data = stream.readall()
         else:
-            result = []
-            while size > 0:
-                line = stream.readline()
-                if not line:
-                    break
-                result.append(line)
-                size -= len(line)
+            data = stream.read(size)
+        result = []
+        splitfrom = 0
+        for i in range(len(data)):
+            if data[i] == '\n':
+                result.append(data[splitfrom : i + 1])
+                splitfrom = i + 1
+        #
+        if splitfrom < len(data):
+            # there is a partial line at the end.  If size > 0, it is likely
+            # to be because the 'read(size)' returned data up to the middle
+            # of a line.  In that case, use 'readline()' to read until the
+            # end of the current line.
+            data = data[splitfrom:]
+            if size > 0:
+                data += stream.readline()
+            result.append(data)
         return result
 
     @unwrap_spec(offset=r_longlong, whence=int)
diff --git a/pypy/module/_hashlib/interp_hashlib.py b/pypy/module/_hashlib/interp_hashlib.py
--- a/pypy/module/_hashlib/interp_hashlib.py
+++ b/pypy/module/_hashlib/interp_hashlib.py
@@ -4,14 +4,21 @@
 from pypy.interpreter.error import OperationError
 from pypy.tool.sourcetools import func_renamer
 from pypy.interpreter.baseobjspace import Wrappable
-from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+from pypy.rlib import rgc, ropenssl
 from pypy.rlib.objectmodel import keepalive_until_here
-from pypy.rlib import ropenssl
 from pypy.rlib.rstring import StringBuilder
 from pypy.module.thread.os_lock import Lock
 
 algorithms = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512')
 
+# HASH_MALLOC_SIZE is the size of EVP_MD, EVP_MD_CTX plus their points
+# Used for adding memory pressure. Last number is an (under?)estimate of
+# EVP_PKEY_CTX's size.
+# XXX: Make a better estimate here
+HASH_MALLOC_SIZE = ropenssl.EVP_MD_SIZE + ropenssl.EVP_MD_CTX_SIZE \
+        + rffi.sizeof(ropenssl.EVP_MD) * 2 + 208
+
 def hash_name_mapper_callback(obj_name, userdata):
     state = global_state[0] 
     assert state is not None
@@ -55,22 +62,27 @@
 
 class W_Hash(Wrappable):
     ctx = lltype.nullptr(ropenssl.EVP_MD_CTX.TO)
+    _block_size = -1
 
     def __init__(self, space, name):
         self.name = name
+        self.digest_size = self.compute_digest_size()
 
         # Allocate a lock for each HASH object.
         # An optimization would be to not release the GIL on small requests,
         # and use a custom lock only when needed.
         self.lock = Lock(space)
 
+        ctx = lltype.malloc(ropenssl.EVP_MD_CTX.TO, flavor='raw')
+        rgc.add_memory_pressure(HASH_MALLOC_SIZE + self.digest_size)
+        self.ctx = ctx
+
+    def initdigest(self, space, name):
         digest = ropenssl.EVP_get_digestbyname(name)
         if not digest:
             raise OperationError(space.w_ValueError,
                                  space.wrap("unknown hash function"))
-        ctx = lltype.malloc(ropenssl.EVP_MD_CTX.TO, flavor='raw')
-        ropenssl.EVP_DigestInit(ctx, digest)
-        self.ctx = ctx
+        ropenssl.EVP_DigestInit(self.ctx, digest)
 
     def __del__(self):
         # self.lock.free()
@@ -106,33 +118,29 @@
         "Return the digest value as a string of hexadecimal digits."
         digest = self._digest(space)
         hexdigits = '0123456789abcdef'
-        result = StringBuilder(self._digest_size() * 2)
+        result = StringBuilder(self.digest_size * 2)
         for c in digest:
             result.append(hexdigits[(ord(c) >> 4) & 0xf])
             result.append(hexdigits[ ord(c)       & 0xf])
         return space.wrap(result.build())
 
     def get_digest_size(self, space):
-        return space.wrap(self._digest_size())
+        return space.wrap(self.digest_size)
 
     def get_block_size(self, space):
-        return space.wrap(self._block_size())
+        return space.wrap(self.compute_block_size())
 
     def _digest(self, space):
-        copy = self.copy(space)
-        ctx = copy.ctx
-        digest_size = self._digest_size()
-        digest = lltype.malloc(rffi.CCHARP.TO, digest_size, flavor='raw')
+        with lltype.scoped_alloc(ropenssl.EVP_MD_CTX.TO) as ctx:
+            with self.lock:
+                ropenssl.EVP_MD_CTX_copy(ctx, self.ctx)
+            digest_size = self.digest_size
+            with lltype.scoped_alloc(rffi.CCHARP.TO, digest_size) as digest:
+                ropenssl.EVP_DigestFinal(ctx, digest, None)
+                ropenssl.EVP_MD_CTX_cleanup(ctx)
+                return rffi.charpsize2str(digest, digest_size)
 
-        try:
-            ropenssl.EVP_DigestFinal(ctx, digest, None)
-            return rffi.charpsize2str(digest, digest_size)
-        finally:
-            keepalive_until_here(copy)
-            lltype.free(digest, flavor='raw')
-
-
-    def _digest_size(self):
+    def compute_digest_size(self):
         # XXX This isn't the nicest way, but the EVP_MD_size OpenSSL
         # XXX function is defined as a C macro on OS X and would be
         # XXX significantly harder to implement in another way.
@@ -146,12 +154,14 @@
             'sha512': 64, 'SHA512': 64,
             }.get(self.name, 0)
 
-    def _block_size(self):
+    def compute_block_size(self):
+        if self._block_size != -1:
+            return self._block_size
         # XXX This isn't the nicest way, but the EVP_MD_CTX_block_size
         # XXX OpenSSL function is defined as a C macro on some systems
         # XXX and would be significantly harder to implement in
         # XXX another way.
-        return {
+        self._block_size = {
             'md5':     64, 'MD5':     64,
             'sha1':    64, 'SHA1':    64,
             'sha224':  64, 'SHA224':  64,
@@ -159,6 +169,7 @@
             'sha384': 128, 'SHA384': 128,
             'sha512': 128, 'SHA512': 128,
             }.get(self.name, 0)
+        return self._block_size
 
 W_Hash.typedef = TypeDef(
     'HASH',
@@ -176,6 +187,7 @@
 @unwrap_spec(name=str, string='bufferstr')
 def new(space, name, string=''):
     w_hash = W_Hash(space, name)
+    w_hash.initdigest(space, name)
     w_hash.update(space, string)
     return space.wrap(w_hash)
 
diff --git a/pypy/module/_minimal_curses/__init__.py b/pypy/module/_minimal_curses/__init__.py
--- a/pypy/module/_minimal_curses/__init__.py
+++ b/pypy/module/_minimal_curses/__init__.py
@@ -4,7 +4,8 @@
     try:
         import _minimal_curses as _curses   # when running on top of pypy-c
     except ImportError:
-        raise ImportError("no _curses or _minimal_curses module")  # no _curses at all
+        import py
+        py.test.skip("no _curses or _minimal_curses module") #no _curses at all
 
 from pypy.interpreter.mixedmodule import MixedModule
 from pypy.module._minimal_curses import fficurses
diff --git a/pypy/module/_multiprocessing/interp_semaphore.py b/pypy/module/_multiprocessing/interp_semaphore.py
--- a/pypy/module/_multiprocessing/interp_semaphore.py
+++ b/pypy/module/_multiprocessing/interp_semaphore.py
@@ -4,6 +4,7 @@
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.error import wrap_oserror, OperationError
 from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib import rgc
 from pypy.rlib.rarithmetic import r_uint
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.rpython.tool import rffi_platform as platform
@@ -23,6 +24,8 @@
     _CreateSemaphore = rwin32.winexternal(
         'CreateSemaphoreA', [rffi.VOIDP, rffi.LONG, rffi.LONG, rwin32.LPCSTR],
         rwin32.HANDLE)
+    _CloseHandle = rwin32.winexternal('CloseHandle', [rwin32.HANDLE],
+        rwin32.BOOL, threadsafe=False)
     _ReleaseSemaphore = rwin32.winexternal(
         'ReleaseSemaphore', [rwin32.HANDLE, rffi.LONG, rffi.LONGP],
         rwin32.BOOL)
@@ -51,6 +54,7 @@
         SEM_FAILED = platform.ConstantInteger('SEM_FAILED')
         SEM_VALUE_MAX = platform.ConstantInteger('SEM_VALUE_MAX')
         SEM_TIMED_WAIT = platform.Has('sem_timedwait')
+        SEM_T_SIZE = platform.SizeOf('sem_t')
 
     config = platform.configure(CConfig)
     TIMEVAL        = config['TIMEVAL']
@@ -61,18 +65,21 @@
     SEM_FAILED     = config['SEM_FAILED'] # rffi.cast(SEM_T, config['SEM_FAILED'])
     SEM_VALUE_MAX  = config['SEM_VALUE_MAX']
     SEM_TIMED_WAIT = config['SEM_TIMED_WAIT']
+    SEM_T_SIZE = config['SEM_T_SIZE']
     if sys.platform == 'darwin':
         HAVE_BROKEN_SEM_GETVALUE = True
     else:
         HAVE_BROKEN_SEM_GETVALUE = False
 
-    def external(name, args, result):
+    def external(name, args, result, **kwargs):
         return rffi.llexternal(name, args, result,
-                               compilation_info=eci)
+                               compilation_info=eci, **kwargs)
 
     _sem_open = external('sem_open',
                          [rffi.CCHARP, rffi.INT, rffi.INT, rffi.UINT],
                          SEM_T)
+    # tread sem_close as not threadsafe for now to be able to use the __del__
+    _sem_close = external('sem_close', [SEM_T], rffi.INT, threadsafe=False)
     _sem_unlink = external('sem_unlink', [rffi.CCHARP], rffi.INT)
     _sem_wait = external('sem_wait', [SEM_T], rffi.INT)
     _sem_trywait = external('sem_trywait', [SEM_T], rffi.INT)
@@ -90,6 +97,11 @@
             raise OSError(rposix.get_errno(), "sem_open failed")
         return res
 
+    def sem_close(handle):
+        res = _sem_close(handle)
+        if res < 0:
+            raise OSError(rposix.get_errno(), "sem_close failed")
+
     def sem_unlink(name):
         res = _sem_unlink(name)
         if res < 0:
@@ -205,6 +217,11 @@
             raise WindowsError(err, "CreateSemaphore")
         return handle
 
+    def delete_semaphore(handle):
+        if not _CloseHandle(handle):
+            err = rwin32.GetLastError()
+            raise WindowsError(err, "CloseHandle")
+
     def semlock_acquire(self, space, block, w_timeout):
         if not block:
             full_msecs = 0
@@ -291,8 +308,13 @@
             sem_unlink(name)
         except OSError:
             pass
+        else:
+            rgc.add_memory_pressure(SEM_T_SIZE)
         return sem
 
+    def delete_semaphore(handle):
+        sem_close(handle)
+
     def semlock_acquire(self, space, block, w_timeout):
         if not block:
             deadline = lltype.nullptr(TIMESPECP.TO)
@@ -483,6 +505,9 @@
     def exit(self, space, __args__):
         self.release(space)
 
+    def __del__(self):
+        delete_semaphore(self.handle)
+
 @unwrap_spec(kind=int, value=int, maxvalue=int)
 def descr_new(space, w_subtype, kind, value, maxvalue):
     if kind != RECURSIVE_MUTEX and kind != SEMAPHORE:
diff --git a/pypy/module/_socket/interp_socket.py b/pypy/module/_socket/interp_socket.py
--- a/pypy/module/_socket/interp_socket.py
+++ b/pypy/module/_socket/interp_socket.py
@@ -16,9 +16,6 @@
         self.space.getexecutioncontext().checksignals()
 
 class W_RSocket(Wrappable, RSocket):
-    def __del__(self):
-        self.close()
-
     def _accept_w(self, space):
         """_accept() -> (socket object, address info)
 
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -211,7 +211,9 @@
             return result
 
         def __del__(self):
-            self.clear_all_weakrefs()
+            # note that we don't call clear_all_weakrefs here because
+            # an array with freed buffer is ok to see - it's just empty with 0
+            # length
             self.setlen(0)
 
         def setlen(self, size):
diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -788,6 +788,22 @@
         r = weakref.ref(a)
         assert r() is a
 
+    def test_subclass_del(self):
+        import array, gc, weakref
+        l = []
+        
+        class A(array.array):
+            pass
+
+        a = A('d')
+        a.append(3.0)
+        r = weakref.ref(a, lambda a: l.append(a()))
+        del a
+        gc.collect(); gc.collect()   # XXX needs two of them right now...
+        assert l
+        assert l[0] is None or len(l[0]) == 0
+
+
 class DontTestCPythonsOwnArray(BaseArrayTests):
 
     def setup_class(cls):
@@ -808,11 +824,7 @@
         cls.w_tempfile = cls.space.wrap(
             str(py.test.ensuretemp('array').join('tmpfile')))
         cls.w_maxint = cls.space.wrap(sys.maxint)
-
-
-
-
-
+    
     def test_buffer_info(self):
         a = self.array('b', b'Hi!')
         bi = a.buffer_info()
diff --git a/pypy/module/bz2/test/test_large.py b/pypy/module/bz2/test/test_large.py
--- a/pypy/module/bz2/test/test_large.py
+++ b/pypy/module/bz2/test/test_large.py
@@ -8,7 +8,7 @@
             py.test.skip("skipping this very slow test; try 'pypy-c -A'")
         cls.space = gettestobjspace(usemodules=('bz2',))
         largetest_bz2 = py.path.local(__file__).dirpath().join("largetest.bz2")
-        cls.w_compressed_data = cls.space.wrap(largetest_bz2.read())
+        cls.w_compressed_data = cls.space.wrap(largetest_bz2.read('rb'))
 
     def test_decompress(self):
         from bz2 import decompress
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -391,6 +391,7 @@
         'Slice': 'space.gettypeobject(W_SliceObject.typedef)',
         'StaticMethod': 'space.gettypeobject(StaticMethod.typedef)',
         'CFunction': 'space.gettypeobject(cpyext.methodobject.W_PyCFunctionObject.typedef)',
+        'WrapperDescr': 'space.gettypeobject(cpyext.methodobject.W_PyCMethodObject.typedef)'
         }.items():
         GLOBALS['Py%s_Type#' % (cpyname, )] = ('PyTypeObject*', pypyexpr)
 
diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -237,6 +237,7 @@
 def PyStaticMethod_New(space, w_func):
     return space.wrap(StaticMethod(w_func))
 
+ at cpython_api([PyObject, lltype.Ptr(PyMethodDef)], PyObject)
 def PyDescr_NewMethod(space, w_type, method):
     return space.wrap(W_PyCMethodObject(space, method, w_type))
 
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -586,10 +586,6 @@
 def PyDescr_NewMember(space, type, meth):
     raise NotImplementedError
 
- at cpython_api([PyTypeObjectPtr, PyMethodDef], PyObject)
-def PyDescr_NewMethod(space, type, meth):
-    raise NotImplementedError
-
 @cpython_api([PyTypeObjectPtr, wrapperbase, rffi.VOIDP], PyObject)
 def PyDescr_NewWrapper(space, type, wrapper, wrapped):
     raise NotImplementedError
@@ -610,14 +606,6 @@
 def PyWrapper_New(space, w_d, w_self):
     raise NotImplementedError
 
- at cpython_api([PyObject], PyObject)
-def PyDictProxy_New(space, dict):
-    """Return a proxy object for a mapping which enforces read-only behavior.
-    This is normally used to create a proxy to prevent modification of the
-    dictionary for non-dynamic class types.
-    """
-    raise NotImplementedError
-
 @cpython_api([PyObject, PyObject, rffi.INT_real], rffi.INT_real, error=-1)
 def PyDict_Merge(space, a, b, override):
     """Iterate over mapping object b adding key-value pairs to dictionary a.
@@ -2293,15 +2281,6 @@
     changes in your code for properly supporting 64-bit systems."""
     raise NotImplementedError
 
- at cpython_api([rffi.CWCHARP, Py_ssize_t, rffi.CCHARP], PyObject)
-def PyUnicode_EncodeUTF8(space, s, size, errors):
-    """Encode the Py_UNICODE buffer of the given size using UTF-8 and return a
-    Python string object.  Return NULL if an exception was raised by the codec.
-
-    This function used an int type for size. This might require
-    changes in your code for properly supporting 64-bit systems."""
-    raise NotImplementedError
-
 @cpython_api([rffi.CCHARP, Py_ssize_t, rffi.CCHARP, rffi.INTP], PyObject)
 def PyUnicode_DecodeUTF32(space, s, size, errors, byteorder):
     """Decode length bytes from a UTF-32 encoded buffer string and return the
@@ -2481,31 +2460,6 @@
     was raised by the codec."""
     raise NotImplementedError
 
- at cpython_api([rffi.CCHARP, Py_ssize_t, rffi.CCHARP], PyObject)
-def PyUnicode_DecodeLatin1(space, s, size, errors):
-    """Create a Unicode object by decoding size bytes of the Latin-1 encoded string
-    s.  Return NULL if an exception was raised by the codec.
-
-    This function used an int type for size. This might require
-    changes in your code for properly supporting 64-bit systems."""
-    raise NotImplementedError
-
- at cpython_api([rffi.CWCHARP, Py_ssize_t, rffi.CCHARP], PyObject)
-def PyUnicode_EncodeLatin1(space, s, size, errors):
-    """Encode the Py_UNICODE buffer of the given size using Latin-1 and return
-    a Python string object.  Return NULL if an exception was raised by the codec.
-
-    This function used an int type for size. This might require
-    changes in your code for properly supporting 64-bit systems."""
-    raise NotImplementedError
-
- at cpython_api([PyObject], PyObject)
-def PyUnicode_AsLatin1String(space, unicode):
-    """Encode a Unicode object using Latin-1 and return the result as Python string
-    object.  Error handling is "strict".  Return NULL if an exception was raised
-    by the codec."""
-    raise NotImplementedError
-
 @cpython_api([rffi.CCHARP, Py_ssize_t, PyObject, rffi.CCHARP], PyObject)
 def PyUnicode_DecodeCharmap(space, s, size, mapping, errors):
     """Create a Unicode object by decoding size bytes of the encoded string s using
@@ -2564,13 +2518,6 @@
     """
     raise NotImplementedError
 
- at cpython_api([PyObject], PyObject)
-def PyUnicode_AsMBCSString(space, unicode):
-    """Encode a Unicode object using MBCS and return the result as Python string
-    object.  Error handling is "strict".  Return NULL if an exception was raised
-    by the codec."""
-    raise NotImplementedError
-
 @cpython_api([PyObject, PyObject], PyObject)
 def PyUnicode_Concat(space, left, right):
     """Concat two strings giving a new Unicode string."""
@@ -2912,16 +2859,3 @@
     """Return true if ob is a proxy object.
     """
     raise NotImplementedError
-
- at cpython_api([PyObject, PyObject], PyObject)
-def PyWeakref_NewProxy(space, ob, callback):
-    """Return a weak reference proxy object for the object ob.  This will always
-    return a new reference, but is not guaranteed to create a new object; an
-    existing proxy object may be returned.  The second parameter, callback, can
-    be a callable object that receives notification when ob is garbage
-    collected; it should accept a single parameter, which will be the weak
-    reference object itself. callback may also be None or NULL.  If ob
-    is not a weakly-referencable object, or if callback is not callable,
-    None, or NULL, this will return NULL and raise TypeError.
-    """
-    raise NotImplementedError
diff --git a/pypy/module/cpyext/test/test_methodobject.py b/pypy/module/cpyext/test/test_methodobject.py
--- a/pypy/module/cpyext/test/test_methodobject.py
+++ b/pypy/module/cpyext/test/test_methodobject.py
@@ -79,7 +79,7 @@
         raises(TypeError, mod.isSameFunction, 1)
 
 class TestPyCMethodObject(BaseApiTest):
-    def test_repr(self, space):
+    def test_repr(self, space, api):
         """
         W_PyCMethodObject has a repr string which describes it as a method
         and gives its name and the name of its class.
@@ -94,7 +94,7 @@
         ml.c_ml_meth = rffi.cast(PyCFunction_typedef,
                                  c_func.get_llhelper(space))
 
-        method = PyDescr_NewMethod(space, space.w_str, ml)
+        method = api.PyDescr_NewMethod(space.w_str, ml)
         assert repr(method).startswith(
             "<built-in method 'func' of 'str' object ")
 
diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py
--- a/pypy/module/cpyext/test/test_unicodeobject.py
+++ b/pypy/module/cpyext/test/test_unicodeobject.py
@@ -188,6 +188,12 @@
         assert space.unwrap(w_u) == 'sp'
         rffi.free_charp(u)
 
+    def test_encode_utf8(self, space, api):
+        u = rffi.unicode2wcharp(u'sp&#65533;m')
+        w_s = api.PyUnicode_EncodeUTF8(u, 4, None)
+        assert space.unwrap(w_s) == u'sp&#65533;m'.encode('utf-8')
+        rffi.free_wcharp(u)
+
     def test_IS(self, space, api):
         for char in [0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x1c, 0x1d, 0x1e, 0x1f,
                      0x20, 0x85, 0xa0, 0x1680, 0x2000, 0x2001, 0x2002,
@@ -385,6 +391,24 @@
                     data, len(u), lltype.nullptr(rffi.CCHARP.TO))
         rffi.free_wcharp(data)
 
+    def test_latin1(self, space, api):
+        s = 'abcdefg'
+        data = rffi.str2charp(s)
+        w_u = api.PyUnicode_DecodeLatin1(data, len(s), lltype.nullptr(rffi.CCHARP.TO))
+        assert space.eq_w(w_u, space.wrap(u"abcdefg"))
+        rffi.free_charp(data)
+
+        uni = u'abcdefg'
+        data = rffi.unicode2wcharp(uni)
+        w_s = api.PyUnicode_EncodeLatin1(data, len(uni), lltype.nullptr(rffi.CCHARP.TO))
+        assert space.eq_w(space.wrap("abcdefg"), w_s)
+        rffi.free_wcharp(data)
+
+        ustr = "abcdef"
+        w_ustr = space.wrap(ustr.decode("ascii"))
+        result = api.PyUnicode_AsLatin1String(w_ustr)
+        assert space.eq_w(space.wrap(ustr), result)
+
     def test_format(self, space, api):
         w_format = space.wrap(u'hi %s')
         w_args = space.wrap((u'test',))
diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py
--- a/pypy/module/cpyext/test/test_weakref.py
+++ b/pypy/module/cpyext/test/test_weakref.py
@@ -15,6 +15,12 @@
         assert api.PyErr_Occurred() is space.w_TypeError
         api.PyErr_Clear()
 
+    def test_proxy(self, space, api):
+        w_obj = space.w_Warning # some weakrefable object
+        w_proxy = api.PyWeakref_NewProxy(w_obj, None)
+        assert space.unwrap(space.str(w_proxy)) == "<type 'exceptions.Warning'>"
+        assert space.unwrap(space.repr(w_proxy)).startswith('<weak')
+
     def test_weakref_lockobject(self, space, api):
         # some new weakrefable object
         w_obj = space.call_function(space.w_type, space.wrap("newtype"),
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -14,6 +14,7 @@
 from pypy.module.sys.interp_encoding import setdefaultencoding
 from pypy.objspace.std import unicodeobject, unicodetype
 from pypy.rlib import runicode
+from pypy.tool.sourcetools import func_renamer
 import sys
 
 ## See comment in stringobject.py.
@@ -431,26 +432,49 @@
     ref[0] = rffi.cast(PyObject, py_newuni)
     return 0
 
- at cpython_api([PyObject], PyObject)
-def PyUnicode_AsUTF8String(space, w_unicode):
-    """Encode a Unicode object using UTF-8 and return the result as Python string
-    object.  Error handling is "strict".  Return NULL if an exception was raised
-    by the codec."""
-    if not PyUnicode_Check(space, w_unicode):
-        PyErr_BadArgument(space)
-    return unicodetype.encode_object(space, w_unicode, "utf-8", "strict")
+def make_conversion_functions(suffix, encoding):
+    @cpython_api([PyObject], PyObject)
+    @func_renamer('PyUnicode_As%sString' % suffix)
+    def PyUnicode_AsXXXString(space, w_unicode):
+        """Encode a Unicode object and return the result as Python
+        string object.  Error handling is "strict".  Return NULL if an
+        exception was raised by the codec."""
+        if not PyUnicode_Check(space, w_unicode):
+            PyErr_BadArgument(space)
+        return unicodetype.encode_object(space, w_unicode, encoding, "strict")
 
- at cpython_api([CONST_STRING, Py_ssize_t, CONST_STRING], PyObject)
-def PyUnicode_DecodeUTF8(space, s, size, errors):
-    """Create a Unicode object by decoding size bytes of the UTF-8 encoded string
-    s. Return NULL if an exception was raised by the codec.
-    """
-    w_str = space.wrap(rffi.charpsize2str(s, size))
-    if errors:
-        w_errors = space.wrap(rffi.charp2str(errors))
-    else:
-        w_errors = space.w_None
-    return space.call_method(w_str, 'decode', space.wrap("utf-8"), w_errors)
+    @cpython_api([CONST_STRING, Py_ssize_t, CONST_STRING], PyObject)
+    @func_renamer('PyUnicode_Decode%s' % suffix)
+    def PyUnicode_DecodeXXX(space, s, size, errors):
+        """Create a Unicode object by decoding size bytes of the
+        encoded string s. Return NULL if an exception was raised by
+        the codec.
+        """
+        w_s = space.wrap(rffi.charpsize2str(s, size))
+        if errors:
+            w_errors = space.wrap(rffi.charp2str(errors))
+        else:
+            w_errors = space.w_None
+        return space.call_method(w_s, 'decode', space.wrap(encoding), w_errors)
+
+    @cpython_api([CONST_WSTRING, Py_ssize_t, CONST_STRING], PyObject)
+    @func_renamer('PyUnicode_Encode%s' % suffix)
+    def PyUnicode_EncodeXXX(space, s, size, errors):
+        """Encode the Py_UNICODE buffer of the given size and return a
+        Python string object.  Return NULL if an exception was raised
+        by the codec."""
+        w_u = space.wrap(rffi.wcharpsize2unicode(s, size))
+        if errors:
+            w_errors = space.wrap(rffi.charp2str(errors))
+        else:
+            w_errors = space.w_None
+        return space.call_method(w_u, 'encode', space.wrap(encoding), w_errors)
+
+make_conversion_functions('UTF8', 'utf-8')
+make_conversion_functions('ASCII', 'ascii')
+make_conversion_functions('Latin1', 'latin-1')
+if sys.platform == 'win32':
+    make_conversion_functions('MBCS', 'mbcs')
 
 @cpython_api([rffi.CCHARP, Py_ssize_t, rffi.CCHARP, rffi.INTP], PyObject)
 def PyUnicode_DecodeUTF16(space, s, size, llerrors, pbyteorder):
@@ -507,56 +531,6 @@
 
     return space.wrap(result)
 
- at cpython_api([PyObject], PyObject)
-def PyUnicode_AsASCIIString(space, w_unicode):
-    """Encode a Unicode object using ASCII and return the result as Python string
-    object.  Error handling is "strict".  Return NULL if an exception was raised
-    by the codec."""
-    return space.call_method(w_unicode, 'encode', space.wrap('ascii')) #space.w_None for errors?
-
- at cpython_api([rffi.CCHARP, Py_ssize_t, rffi.CCHARP], PyObject)
-def PyUnicode_DecodeASCII(space, s, size, errors):
-    """Create a Unicode object by decoding size bytes of the ASCII encoded string
-    s.  Return NULL if an exception was raised by the codec."""
-    w_s = space.wrap(rffi.charpsize2str(s, size))
-    return space.call_method(w_s, 'decode', space.wrap('ascii'))
-
- at cpython_api([rffi.CWCHARP, Py_ssize_t, rffi.CCHARP], PyObject)
-def PyUnicode_EncodeASCII(space, s, size, errors):
-    """Encode the Py_UNICODE buffer of the given size using ASCII and return a
-    Python string object.  Return NULL if an exception was raised by the codec.
-    """
-
-    w_s = space.wrap(rffi.wcharpsize2unicode(s, size))
-    return space.call_method(w_s, 'encode', space.wrap('ascii'))
-
-if sys.platform == 'win32':
-    @cpython_api([CONST_WSTRING, Py_ssize_t, CONST_STRING], PyObject)
-    def PyUnicode_EncodeMBCS(space, wchar_p, length, errors):
-        """Encode the Py_UNICODE buffer of the given size using MBCS and return a
-        Python string object.  Return NULL if an exception was raised by the codec.
-        """
-        w_unicode = space.wrap(rffi.wcharpsize2unicode(wchar_p, length))
-        if errors:
-            w_errors = space.wrap(rffi.charp2str(errors))
-        else:
-            w_errors = space.w_None
-        return space.call_method(w_unicode, "encode",
-                                 space.wrap("mbcs"), w_errors)
-
-    @cpython_api([CONST_STRING, Py_ssize_t, CONST_STRING], PyObject)
-    def PyUnicode_DecodeMBCS(space, s, size, errors):
-        """Create a Unicode object by decoding size bytes of the MBCS encoded string s.
-        Return NULL if an exception was raised by the codec.
-        """
-        w_str = space.wrap(rffi.charpsize2str(s, size))
-        w_encoding = space.wrap("mbcs")
-        if errors:
-            w_errors = space.wrap(rffi.charp2str(errors))
-        else:
-            w_errors = space.w_None
-        return space.call_method(w_str, 'decode', w_encoding, w_errors)
-
 @cpython_api([PyObject, PyObject], rffi.INT_real, error=-2)
 def PyUnicode_Compare(space, w_left, w_right):
     """Compare two strings and return -1, 0, 1 for less than, equal, and greater
diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py
--- a/pypy/module/cpyext/weakrefobject.py
+++ b/pypy/module/cpyext/weakrefobject.py
@@ -1,6 +1,6 @@
 from pypy.module.cpyext.api import cpython_api
 from pypy.module.cpyext.pyobject import PyObject, borrow_from
-from pypy.module._weakref.interp__weakref import W_Weakref
+from pypy.module._weakref.interp__weakref import W_Weakref, proxy
 
 @cpython_api([PyObject, PyObject], PyObject)
 def PyWeakref_NewRef(space, w_obj, w_callback):
@@ -16,6 +16,20 @@
     w_weakref = space.gettypeobject(W_Weakref.typedef)
     return space.call_function(w_weakref, w_obj, w_callback)
 
+ at cpython_api([PyObject, PyObject], PyObject)
+def PyWeakref_NewProxy(space, w_obj, w_callback):
+    """Return a weak reference proxy object for the object *ob*.  This will
+    alwas return a new reference, but is not guaranteed to create a new
+    object; an existing proxy object may be returned.  The second parameter,
+    *callback*, can be a callable object that receives notification when *ob*
+    is garbage collected; it should accept a single parameter, which will be
+    the weak reference object itself. *callback* may also be ``None`` or
+    *NULL*.  If *ob* is not a weakly-referencable object, or if *callback* is
+    not callable, ``None``, or *NULL*, this will return *NULL* and raise
+    :exc:`TypeError`.
+    """
+    return proxy(space, w_obj, w_callback)
+
 @cpython_api([PyObject], PyObject)
 def PyWeakref_GetObject(space, w_ref):
     """Return the referenced object from a weak reference.  If the referent is
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -13,6 +13,9 @@
         'empty': 'interp_numarray.zeros',
         'ones': 'interp_numarray.ones',
         'fromstring': 'interp_support.fromstring',
+
+        'True_': 'space.w_True',
+        'False_': 'space.w_False',
     }
 
     # ufuncs
diff --git a/pypy/module/micronumpy/compile.py b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -4,30 +4,52 @@
 """
 
 from pypy.interpreter.baseobjspace import InternalSpaceCache, W_Root
-from pypy.module.micronumpy.interp_dtype import W_Float64Dtype
-from pypy.module.micronumpy.interp_numarray import Scalar, SingleDimArray, BaseArray
+from pypy.module.micronumpy.interp_dtype import W_Float64Dtype, W_BoolDtype
+from pypy.module.micronumpy.interp_numarray import (Scalar, BaseArray,
+     descr_new_array, scalar_w, SingleDimArray)
+from pypy.module.micronumpy import interp_ufuncs
 from pypy.rlib.objectmodel import specialize
 
 
 class BogusBytecode(Exception):
     pass
 
-def create_array(dtype, size):
-    a = SingleDimArray(size, dtype=dtype)
-    for i in range(size):
-        dtype.setitem(a.storage, i, dtype.box(float(i % 10)))
-    return a
+class ArgumentMismatch(Exception):
+    pass
+
+class ArgumentNotAnArray(Exception):
+    pass
+
+class WrongFunctionName(Exception):
+    pass
+
+SINGLE_ARG_FUNCTIONS = ["sum", "prod", "max", "min", "all", "any", "unegative"]
 
 class FakeSpace(object):
     w_ValueError = None
     w_TypeError = None
+    w_None = None
+
+    w_bool = "bool"
+    w_int = "int"
+    w_float = "float"
+    w_list = "list"
+    w_long = "long"
+    w_tuple = 'tuple'
 
     def __init__(self):
         """NOT_RPYTHON"""
         self.fromcache = InternalSpaceCache(self).getorbuild
+        self.w_float64dtype = W_Float64Dtype(self)
 
     def issequence_w(self, w_obj):
-        return True
+        return isinstance(w_obj, ListObject) or isinstance(w_obj, SingleDimArray)
+
+    def isinstance_w(self, w_obj, w_tp):
+        return False
+
+    def decode_index4(self, w_idx, size):
+        return (self.int_w(w_idx), 0, 0, 1)
 
     @specialize.argtype(1)
     def wrap(self, obj):
@@ -39,72 +61,382 @@
             return IntObject(obj)
         raise Exception
 
+    def newlist(self, items):
+        return ListObject(items)
+
+    def listview(self, obj):
+        assert isinstance(obj, ListObject)
+        return obj.items
+
     def float(self, w_obj):
         assert isinstance(w_obj, FloatObject)
         return w_obj
 
     def float_w(self, w_obj):
+        assert isinstance(w_obj, FloatObject)        
         return w_obj.floatval
 
+    def int_w(self, w_obj):
+        if isinstance(w_obj, IntObject):
+            return w_obj.intval
+        elif isinstance(w_obj, FloatObject):
+            return int(w_obj.floatval)
+        raise NotImplementedError
+
+    def int(self, w_obj):
+        return w_obj
+
+    def is_true(self, w_obj):
+        assert isinstance(w_obj, BoolObject)
+        return w_obj.boolval
+
+    def is_w(self, w_obj, w_what):
+        return w_obj is w_what
+
+    def type(self, w_obj):
+        return w_obj.tp
+
+    def gettypefor(self, w_obj):
+        return None
+
+    def call_function(self, tp, w_dtype):
+        return w_dtype
+
+    @specialize.arg(1)
+    def interp_w(self, tp, what):
+        assert isinstance(what, tp)
+        return what
 
 class FloatObject(W_Root):
+    tp = FakeSpace.w_float
     def __init__(self, floatval):
         self.floatval = floatval
 
 class BoolObject(W_Root):
+    tp = FakeSpace.w_bool
     def __init__(self, boolval):
         self.boolval = boolval
 
 class IntObject(W_Root):
+    tp = FakeSpace.w_int
     def __init__(self, intval):
         self.intval = intval
 
+class ListObject(W_Root):
+    tp = FakeSpace.w_list
+    def __init__(self, items):
+        self.items = items
 
-space = FakeSpace()
+class InterpreterState(object):
+    def __init__(self, code):
+        self.code = code
+        self.variables = {}
+        self.results = []
 
-def numpy_compile(bytecode, array_size):
-    stack = []
-    i = 0
-    dtype = space.fromcache(W_Float64Dtype)
-    for b in bytecode:
-        if b == 'a':
-            stack.append(create_array(dtype, array_size))
-            i += 1
-        elif b == 'f':
-            stack.append(Scalar(dtype, dtype.box(1.2)))
-        elif b == '+':
-            right = stack.pop()
-            res = stack.pop().descr_add(space, right)
-            assert isinstance(res, BaseArray)
-            stack.append(res)
-        elif b == '-':
-            right = stack.pop()
-            res = stack.pop().descr_sub(space, right)
-            assert isinstance(res, BaseArray)
-            stack.append(res)
-        elif b == '*':
-            right = stack.pop()
-            res = stack.pop().descr_mul(space, right)
-            assert isinstance(res, BaseArray)
-            stack.append(res)
-        elif b == '/':
-            right = stack.pop()
-            res = stack.pop().descr_div(space, right)
-            assert isinstance(res, BaseArray)
-            stack.append(res)
-        elif b == '%':
-            right = stack.pop()
-            res = stack.pop().descr_mod(space, right)
-            assert isinstance(res, BaseArray)
-            stack.append(res)
-        elif b == '|':
-            res = stack.pop().descr_abs(space)
-            assert isinstance(res, BaseArray)
-            stack.append(res)
+    def run(self, space):
+        self.space = space
+        for stmt in self.code.statements:
+            stmt.execute(self)
+
+class Node(object):
+    def __eq__(self, other):
+        return (self.__class__ == other.__class__ and
+                self.__dict__ == other.__dict__)
+
+    def __ne__(self, other):
+        return not self == other
+
+    def wrap(self, space):
+        raise NotImplementedError
+
+    def execute(self, interp):
+        raise NotImplementedError
+
+class Assignment(Node):
+    def __init__(self, name, expr):
+        self.name = name
+        self.expr = expr
+
+    def execute(self, interp):
+        interp.variables[self.name] = self.expr.execute(interp)
+
+    def __repr__(self):
+        return "%% = %r" % (self.name, self.expr)
+
+class ArrayAssignment(Node):
+    def __init__(self, name, index, expr):
+        self.name = name
+        self.index = index
+        self.expr = expr
+
+    def execute(self, interp):
+        arr = interp.variables[self.name]
+        w_index = self.index.execute(interp).eval(0).wrap(interp.space)
+        w_val = self.expr.execute(interp).eval(0).wrap(interp.space)
+        arr.descr_setitem(interp.space, w_index, w_val)
+
+    def __repr__(self):
+        return "%s[%r] = %r" % (self.name, self.index, self.expr)
+
+class Variable(Node):
+    def __init__(self, name):
+        self.name = name
+
+    def execute(self, interp):
+        return interp.variables[self.name]
+
+    def __repr__(self):
+        return 'v(%s)' % self.name
+
+class Operator(Node):
+    def __init__(self, lhs, name, rhs):
+        self.name = name
+        self.lhs = lhs
+        self.rhs = rhs
+
+    def execute(self, interp):
+        w_lhs = self.lhs.execute(interp)
+        assert isinstance(w_lhs, BaseArray)
+        if isinstance(self.rhs, SliceConstant):
+            # XXX interface has changed on multidim branch
+            raise NotImplementedError
+        w_rhs = self.rhs.execute(interp)
+        if self.name == '+':
+            w_res = w_lhs.descr_add(interp.space, w_rhs)
+        elif self.name == '*':
+            w_res = w_lhs.descr_mul(interp.space, w_rhs)
+        elif self.name == '-':
+            w_res = w_lhs.descr_sub(interp.space, w_rhs)            
+        elif self.name == '->':
+            if isinstance(w_rhs, Scalar):
+                index = int(interp.space.float_w(
+                    w_rhs.value.wrap(interp.space)))
+                dtype = interp.space.fromcache(W_Float64Dtype)
+                return Scalar(dtype, w_lhs.get_concrete().eval(index))
+            else:
+                raise NotImplementedError
         else:
-            print "Unknown opcode: %s" % b
-            raise BogusBytecode()
-    if len(stack) != 1:
-        print "Bogus bytecode, uneven stack length"
-        raise BogusBytecode()
-    return stack[0]
+            raise NotImplementedError
+        if not isinstance(w_res, BaseArray):
+            dtype = interp.space.fromcache(W_Float64Dtype)
+            w_res = scalar_w(interp.space, dtype, w_res)
+        return w_res
+
+    def __repr__(self):
+        return '(%r %s %r)' % (self.lhs, self.name, self.rhs)
+
+class FloatConstant(Node):
+    def __init__(self, v):
+        self.v = float(v)
+
+    def __repr__(self):
+        return "Const(%s)" % self.v
+
+    def wrap(self, space):
+        return space.wrap(self.v)
+
+    def execute(self, interp):
+        dtype = interp.space.fromcache(W_Float64Dtype)
+        assert isinstance(dtype, W_Float64Dtype)
+        return Scalar(dtype, dtype.box(self.v))
+
+class RangeConstant(Node):
+    def __init__(self, v):
+        self.v = int(v)
+
+    def execute(self, interp):
+        w_list = interp.space.newlist(
+            [interp.space.wrap(float(i)) for i in range(self.v)])
+        dtype = interp.space.fromcache(W_Float64Dtype)
+        return descr_new_array(interp.space, None, w_list, w_dtype=dtype)
+
+    def __repr__(self):
+        return 'Range(%s)' % self.v
+
+class Code(Node):
+    def __init__(self, statements):
+        self.statements = statements
+
+    def __repr__(self):
+        return "\n".join([repr(i) for i in self.statements])
+
+class ArrayConstant(Node):
+    def __init__(self, items):
+        self.items = items
+
+    def wrap(self, space):
+        return space.newlist([item.wrap(space) for item in self.items])
+
+    def execute(self, interp):
+        w_list = self.wrap(interp.space)
+        dtype = interp.space.fromcache(W_Float64Dtype)
+        return descr_new_array(interp.space, None, w_list, w_dtype=dtype)
+
+    def __repr__(self):
+        return "[" + ", ".join([repr(item) for item in self.items]) + "]"
+
+class SliceConstant(Node):
+    def __init__(self):
+        pass
+
+    def __repr__(self):
+        return 'slice()'
+
+class Execute(Node):
+    def __init__(self, expr):
+        self.expr = expr
+
+    def __repr__(self):
+        return repr(self.expr)
+
+    def execute(self, interp):
+        interp.results.append(self.expr.execute(interp))
+
+class FunctionCall(Node):
+    def __init__(self, name, args):
+        self.name = name
+        self.args = args
+
+    def __repr__(self):
+        return "%s(%s)" % (self.name, ", ".join([repr(arg)
+                                                 for arg in self.args]))
+
+    def execute(self, interp):
+        if self.name in SINGLE_ARG_FUNCTIONS:
+            if len(self.args) != 1:
+                raise ArgumentMismatch
+            arr = self.args[0].execute(interp)
+            if not isinstance(arr, BaseArray):
+                raise ArgumentNotAnArray
+            if self.name == "sum":
+                w_res = arr.descr_sum(interp.space)
+            elif self.name == "prod":
+                w_res = arr.descr_prod(interp.space)
+            elif self.name == "max":
+                w_res = arr.descr_max(interp.space)
+            elif self.name == "min":
+                w_res = arr.descr_min(interp.space)
+            elif self.name == "any":
+                w_res = arr.descr_any(interp.space)
+            elif self.name == "all":
+                w_res = arr.descr_all(interp.space)
+            elif self.name == "unegative":
+                neg = interp_ufuncs.get(interp.space).negative
+                w_res = neg.call(interp.space, [arr])
+            else:
+                assert False # unreachable code
+            if isinstance(w_res, BaseArray):
+                return w_res
+            if isinstance(w_res, FloatObject):
+                dtype = interp.space.fromcache(W_Float64Dtype)
+            elif isinstance(w_res, BoolObject):
+                dtype = interp.space.fromcache(W_BoolDtype)
+            else:
+                dtype = None
+            return scalar_w(interp.space, dtype, w_res)
+        else:
+            raise WrongFunctionName
+
+class Parser(object):
+    def parse_identifier(self, id):
+        id = id.strip(" ")
+        #assert id.isalpha()
+        return Variable(id)
+
+    def parse_expression(self, expr):
+        tokens = [i for i in expr.split(" ") if i]
+        if len(tokens) == 1:
+            return self.parse_constant_or_identifier(tokens[0])
+        stack = []
+        tokens.reverse()
+        while tokens:
+            token = tokens.pop()
+            if token == ')':
+                raise NotImplementedError
+            elif self.is_identifier_or_const(token):
+                if stack:
+                    name = stack.pop().name
+                    lhs = stack.pop()
+                    rhs = self.parse_constant_or_identifier(token)
+                    stack.append(Operator(lhs, name, rhs))
+                else:
+                    stack.append(self.parse_constant_or_identifier(token))
+            else:
+                stack.append(Variable(token))
+        assert len(stack) == 1
+        return stack[-1]
+
+    def parse_constant(self, v):
+        lgt = len(v)-1
+        assert lgt >= 0
+        if ':' in v:
+            # a slice
+            assert v == ':'
+            return SliceConstant()
+        if v[0] == '[':
+            return ArrayConstant([self.parse_constant(elem)
+                                  for elem in v[1:lgt].split(",")])
+        if v[0] == '|':
+            return RangeConstant(v[1:lgt])
+        return FloatConstant(v)
+
+    def is_identifier_or_const(self, v):
+        c = v[0]
+        if ((c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z') or
+            (c >= '0' and c <= '9') or c in '-.[|:'):
+            if v == '-' or v == "->":
+                return False
+            return True
+        return False
+
+    def parse_function_call(self, v):
+        l = v.split('(')
+        assert len(l) == 2
+        name = l[0]
+        cut = len(l[1]) - 1
+        assert cut >= 0
+        args = [self.parse_constant_or_identifier(id)
+                for id in l[1][:cut].split(",")]
+        return FunctionCall(name, args)
+
+    def parse_constant_or_identifier(self, v):
+        c = v[0]
+        if (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z'):
+            if '(' in v:
+                return self.parse_function_call(v)
+            return self.parse_identifier(v)
+        return self.parse_constant(v)
+
+    def parse_array_subscript(self, v):
+        v = v.strip(" ")
+        l = v.split("[")
+        lgt = len(l[1]) - 1
+        assert lgt >= 0
+        rhs = self.parse_constant_or_identifier(l[1][:lgt])
+        return l[0], rhs
+        
+    def parse_statement(self, line):
+        if '=' in line:
+            lhs, rhs = line.split("=")
+            lhs = lhs.strip(" ")
+            if '[' in lhs:
+                name, index = self.parse_array_subscript(lhs)
+                return ArrayAssignment(name, index, self.parse_expression(rhs))
+            else: 
+                return Assignment(lhs, self.parse_expression(rhs))
+        else:
+            return Execute(self.parse_expression(line))
+
+    def parse(self, code):
+        statements = []
+        for line in code.split("\n"):
+            if '#' in line:
+                line = line.split('#', 1)[0]
+            line = line.strip(" ")
+            if line:
+                statements.append(self.parse_statement(line))
+        return Code(statements)
+
+def numpy_compile(code):
+    parser = Parser()
+    return InterpreterState(parser.parse(code))
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
@@ -108,6 +108,12 @@
         def setitem_w(self, space, storage, i, w_item):
             self.setitem(storage, i, self.unwrap(space, w_item))
 
+        def fill(self, storage, item, start, stop):
+            storage = self.unerase(storage)
+            item = self.unbox(item)
+            for i in xrange(start, stop):
+                storage[i] = item
+
         @specialize.argtype(1)
         def adapt_val(self, val):
             return self.box(rffi.cast(TP.TO.OF, val))
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -14,6 +14,27 @@
 any_driver = jit.JitDriver(greens=['signature'], reds=['i', 'size', 'self', 'dtype'])
 slice_driver = jit.JitDriver(greens=['signature'], reds=['i', 'j', 'step', 'stop', 'source', 'dest'])
 
+def descr_new_array(space, w_subtype, w_size_or_iterable, w_dtype=None):
+    l = space.listview(w_size_or_iterable)
+    if space.is_w(w_dtype, space.w_None):
+        w_dtype = None
+        for w_item in l:
+            w_dtype = interp_ufuncs.find_dtype_for_scalar(space, w_item, w_dtype)
+            if w_dtype is space.fromcache(interp_dtype.W_Float64Dtype):
+                break
+        if w_dtype is None:
+            w_dtype = space.w_None
+
+    dtype = space.interp_w(interp_dtype.W_Dtype,
+        space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
+    )
+    arr = SingleDimArray(len(l), dtype=dtype)
+    i = 0
+    for w_elem in l:
+        dtype.setitem_w(space, arr.storage, i, w_elem)
+        i += 1
+    return arr
+
 class BaseArray(Wrappable):
     _attrs_ = ["invalidates", "signature"]
 
@@ -32,27 +53,6 @@
     def add_invalidates(self, other):
         self.invalidates.append(other)
 
-    def descr__new__(space, w_subtype, w_size_or_iterable, w_dtype=None):
-        l = space.listview(w_size_or_iterable)
-        if space.is_w(w_dtype, space.w_None):
-            w_dtype = None
-            for w_item in l:
-                w_dtype = interp_ufuncs.find_dtype_for_scalar(space, w_item, w_dtype)
-                if w_dtype is space.fromcache(interp_dtype.W_Float64Dtype):
-                    break
-            if w_dtype is None:
-                w_dtype = space.w_None
-
-        dtype = space.interp_w(interp_dtype.W_Dtype,
-            space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
-        )
-        arr = SingleDimArray(len(l), dtype=dtype)
-        i = 0
-        for w_elem in l:
-            dtype.setitem_w(space, arr.storage, i, w_elem)
-            i += 1
-        return arr
-
     def _unaryop_impl(ufunc_name):
         def impl(self, space):
             return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [self])
@@ -201,6 +201,9 @@
     def descr_get_shape(self, space):
         return space.newtuple([self.descr_len(space)])
 
+    def descr_get_size(self, space):
+        return space.wrap(self.find_size())
+
     def descr_copy(self, space):
         return space.call_function(space.gettypefor(BaseArray), self, self.find_dtype())
 
@@ -565,13 +568,12 @@
 
     arr = SingleDimArray(size, dtype=dtype)
     one = dtype.adapt_val(1)
-    for i in xrange(size):
-        arr.dtype.setitem(arr.storage, i, one)
+    arr.dtype.fill(arr.storage, one, 0, size)
     return space.wrap(arr)
 
 BaseArray.typedef = TypeDef(
     'numarray',
-    __new__ = interp2app(BaseArray.descr__new__.im_func),
+    __new__ = interp2app(descr_new_array),
 
 
     __len__ = interp2app(BaseArray.descr_len),
@@ -608,6 +610,7 @@
 
     dtype = GetSetProperty(BaseArray.descr_get_dtype),
     shape = GetSetProperty(BaseArray.descr_get_shape),
+    size = GetSetProperty(BaseArray.descr_get_size),
 
     mean = interp2app(BaseArray.descr_mean),
     sum = interp2app(BaseArray.descr_sum),
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -32,11 +32,17 @@
         return self.identity.wrap(space)
 
     def descr_call(self, space, __args__):
-        try:
-            args_w = __args__.fixedunpack(self.argcount)
-        except ValueError, e:
-            raise OperationError(space.w_TypeError, space.wrap(str(e)))
-        return self.call(space, args_w)
+        if __args__.keywords or len(__args__.arguments_w) < self.argcount:
+            raise OperationError(space.w_ValueError,
+                space.wrap("invalid number of arguments")
+            )
+        elif len(__args__.arguments_w) > self.argcount:
+            # The extra arguments should actually be the output array, but we
+            # don't support that yet.
+            raise OperationError(space.w_TypeError,
+                space.wrap("invalid number of arguments")
+            )
+        return self.call(space, __args__.arguments_w)
 
     def descr_reduce(self, space, w_obj):
         from pypy.module.micronumpy.interp_numarray import convert_to_array, Scalar
@@ -236,22 +242,20 @@
     return dt
 
 def find_dtype_for_scalar(space, w_obj, current_guess=None):
-    w_type = space.type(w_obj)
-
     bool_dtype = space.fromcache(interp_dtype.W_BoolDtype)
     long_dtype = space.fromcache(interp_dtype.W_LongDtype)
     int64_dtype = space.fromcache(interp_dtype.W_Int64Dtype)
 
-    if space.is_w(w_type, space.w_bool):
+    if space.isinstance_w(w_obj, space.w_bool):
         if current_guess is None or current_guess is bool_dtype:
             return bool_dtype
         return current_guess
-    elif space.is_w(w_type, space.w_int):
+    elif space.isinstance_w(w_obj, space.w_int):
         if (current_guess is None or current_guess is bool_dtype or
             current_guess is long_dtype):
             return long_dtype
         return current_guess
-    elif space.is_w(w_type, space.w_long):
+    elif space.isinstance_w(w_obj, space.w_long):
         if (current_guess is None or current_guess is bool_dtype or
             current_guess is long_dtype or current_guess is int64_dtype):
             return int64_dtype
diff --git a/pypy/module/micronumpy/test/test_compile.py b/pypy/module/micronumpy/test/test_compile.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/test/test_compile.py
@@ -0,0 +1,170 @@
+
+import py
+from pypy.module.micronumpy.compile import *
+
+class TestCompiler(object):
+    def compile(self, code):
+        return numpy_compile(code)
+    
+    def test_vars(self):
+        code = """
+        a = 2
+        b = 3
+        """
+        interp = self.compile(code)
+        assert isinstance(interp.code.statements[0], Assignment)
+        assert interp.code.statements[0].name == 'a'
+        assert interp.code.statements[0].expr.v == 2
+        assert interp.code.statements[1].name == 'b'
+        assert interp.code.statements[1].expr.v == 3
+
+    def test_array_literal(self):
+        code = "a = [1,2,3]"
+        interp = self.compile(code)
+        assert isinstance(interp.code.statements[0].expr, ArrayConstant)
+        st = interp.code.statements[0]
+        assert st.expr.items == [FloatConstant(1), FloatConstant(2),
+                                 FloatConstant(3)]
+    
+    def test_array_literal2(self):
+        code = "a = [[1],[2],[3]]"
+        interp = self.compile(code)
+        assert isinstance(interp.code.statements[0].expr, ArrayConstant)
+        st = interp.code.statements[0]
+        assert st.expr.items == [ArrayConstant([FloatConstant(1)]),
+                                 ArrayConstant([FloatConstant(2)]),
+                                 ArrayConstant([FloatConstant(3)])]
+
+    def test_expr_1(self):
+        code = "b = a + 1"
+        interp = self.compile(code)
+        assert (interp.code.statements[0].expr ==
+                Operator(Variable("a"), "+", FloatConstant(1)))
+
+    def test_expr_2(self):
+        code = "b = a + b - 3"
+        interp = self.compile(code)
+        assert (interp.code.statements[0].expr ==
+                Operator(Operator(Variable("a"), "+", Variable("b")), "-",
+                         FloatConstant(3)))
+
+    def test_expr_3(self):
+        # an equivalent of range
+        code = "a = |20|"
+        interp = self.compile(code)
+        assert interp.code.statements[0].expr == RangeConstant(20)
+
+    def test_expr_only(self):
+        code = "3 + a"
+        interp = self.compile(code)
+        assert interp.code.statements[0] == Execute(
+            Operator(FloatConstant(3), "+", Variable("a")))
+
+    def test_array_access(self):
+        code = "a -> 3"
+        interp = self.compile(code)
+        assert interp.code.statements[0] == Execute(
+            Operator(Variable("a"), "->", FloatConstant(3)))
+
+    def test_function_call(self):
+        code = "sum(a)"
+        interp = self.compile(code)
+        assert interp.code.statements[0] == Execute(
+            FunctionCall("sum", [Variable("a")]))
+
+    def test_comment(self):
+        code = """
+        # some comment
+        a = b + 3  # another comment
+        """
+        interp = self.compile(code)
+        assert interp.code.statements[0] == Assignment(
+            'a', Operator(Variable('b'), "+", FloatConstant(3)))
+
+class TestRunner(object):
+    def run(self, code):
+        interp = numpy_compile(code)
+        space = FakeSpace()
+        interp.run(space)
+        return interp
+
+    def test_one(self):
+        code = """
+        a = 3
+        b = 4
+        a + b
+        """
+        interp = self.run(code)
+        assert sorted(interp.variables.keys()) == ['a', 'b']
+        assert interp.results[0]
+
+    def test_array_add(self):
+        code = """
+        a = [1,2,3,4]
+        b = [4,5,6,5]
+        a + b
+        """
+        interp = self.run(code)
+        assert interp.results[0]._getnums(False) == ["5.0", "7.0", "9.0", "9.0"]
+
+    def test_array_getitem(self):
+        code = """
+        a = [1,2,3,4]
+        b = [4,5,6,5]
+        a + b -> 3
+        """
+        interp = self.run(code)
+        assert interp.results[0].value.val == 3 + 6
+        
+    def test_range_getitem(self):
+        code = """
+        r = |20| + 3
+        r -> 3
+        """
+        interp = self.run(code)
+        assert interp.results[0].value.val == 6
+
+    def test_sum(self):
+        code = """
+        a = [1,2,3,4,5]
+        r = sum(a)
+        r
+        """
+        interp = self.run(code)
+        assert interp.results[0].value.val == 15
+
+    def test_array_write(self):
+        code = """
+        a = [1,2,3,4,5]
+        a[3] = 15
+        a -> 3
+        """
+        interp = self.run(code)
+        assert interp.results[0].value.val == 15
+
+    def test_min(self):
+        interp = self.run("""
+        a = |30|
+        a[15] = -12
+        b = a + a
+        min(b)
+        """)
+        assert interp.results[0].value.val == -24
+
+    def test_max(self):
+        interp = self.run("""
+        a = |30|
+        a[13] = 128
+        b = a + a
+        max(b)
+        """)
+        assert interp.results[0].value.val == 256
+
+    def test_slice(self):
+        py.test.skip("in progress")
+        interp = self.run("""
+        a = [1,2,3,4]
+        b = a -> :
+        b -> 3
+        """)
+        assert interp.results[0].value.val == 3
diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py
--- a/pypy/module/micronumpy/test/test_dtypes.py
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -36,37 +36,40 @@
         assert str(d) == "bool"
 
     def test_bool_array(self):
-        from numpy import array
+        import numpy
 
-        a = array([0, 1, 2, 2.5], dtype='?')
-        assert a[0] is False
+        a = numpy.array([0, 1, 2, 2.5], dtype='?')
+        assert a[0] is numpy.False_
         for i in xrange(1, 4):
-            assert a[i] is True
+            assert a[i] is numpy.True_
 
     def test_copy_array_with_dtype(self):
-        from numpy import array
-        a = array([0, 1, 2, 3], dtype=long)
+        import numpy
+
+        a = numpy.array([0, 1, 2, 3], dtype=long)
         # int on 64-bit, long in 32-bit
         assert isinstance(a[0], (int, long))
         b = a.copy()
         assert isinstance(b[0], (int, long))
 
-        a = array([0, 1, 2, 3], dtype=bool)
-        assert isinstance(a[0], bool)
+        a = numpy.array([0, 1, 2, 3], dtype=bool)
+        assert a[0] is numpy.False_
         b = a.copy()
-        assert isinstance(b[0], bool)
+        assert b[0] is numpy.False_
 
     def test_zeros_bool(self):
-        from numpy import zeros
-        a = zeros(10, dtype=bool)
+        import numpy
+
+        a = numpy.zeros(10, dtype=bool)
         for i in range(10):
-            assert a[i] is False
+            assert a[i] is numpy.False_
 
     def test_ones_bool(self):
-        from numpy import ones
-        a = ones(10, dtype=bool)
+        import numpy
+
+        a = numpy.ones(10, dtype=bool)
         for i in range(10):
-            assert a[i] is True
+            assert a[i] is numpy.True_
 
     def test_zeros_long(self):
         from numpy import zeros
@@ -77,7 +80,7 @@
 
     def test_ones_long(self):
         from numpy import ones
-        a = ones(10, dtype=bool)
+        a = ones(10, dtype=long)
         for i in range(10):
             assert isinstance(a[i], (int, long))
             assert a[1] == 1
@@ -96,8 +99,9 @@
 
     def test_bool_binop_types(self):
         from numpy import array, dtype
-        types = ('?','b','B','h','H','i','I','l','L','q','Q','f','d')
-        N = len(types)
+        types = [
+            '?', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', 'q', 'Q', 'f', 'd'
+        ]
         a = array([True], '?')
         for t in types:
             assert (a + array([0], t)).dtype is dtype(t)
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
@@ -17,6 +17,14 @@
         a[13] = 5.3
         assert a[13] == 5.3
 
+    def test_size(self):
+        from numpy import array
+        # XXX fixed on multidim branch
+        #assert array(3).size == 1
+        a = array([1, 2, 3])
+        assert a.size == 3
+        assert (a + a).size == 3
+
     def test_empty(self):
         """
         Test that empty() works.
@@ -214,7 +222,7 @@
     def test_add_other(self):
         from numpy import array
         a = array(range(5))
-        b = array(reversed(range(5)))
+        b = array(range(4, -1, -1))
         c = a + b
         for i in range(5):
             assert c[i] == 4
@@ -264,18 +272,19 @@
             assert b[i] == i - 5
 
     def test_mul(self):
-        from numpy import array, dtype
-        a = array(range(5))
+        import numpy
+
+        a = numpy.array(range(5))
         b = a * a
         for i in range(5):
             assert b[i] == i * i
 
-        a = array(range(5), dtype=bool)
+        a = numpy.array(range(5), dtype=bool)
         b = a * a
-        assert b.dtype is dtype(bool)
-        assert b[0] is False
+        assert b.dtype is numpy.dtype(bool)
+        assert b[0] is numpy.False_
         for i in range(1, 5):
-            assert b[i] is True
+            assert b[i] is numpy.True_
 
     def test_mul_constant(self):
         from numpy import array
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -24,10 +24,10 @@
     def test_wrong_arguments(self):
         from numpy import add, sin
 
-        raises(TypeError, add, 1)
+        raises(ValueError, add, 1)
         raises(TypeError, add, 1, 2, 3)
         raises(TypeError, sin, 1, 2)
-        raises(TypeError, sin)
+        raises(ValueError, sin)
 
     def test_single_item(self):
         from numpy import negative, sign, minimum
@@ -82,6 +82,8 @@
         b = negative(a)
         a[0] = 5.0
         assert b[0] == 5.0
+        a = array(range(30))
+        assert negative(a + a)[3] == -6
 
     def test_abs(self):
         from numpy import array, absolute
@@ -355,4 +357,4 @@
                 (3.5, 3),
                 (3, 3.5),
             ]:
-                assert ufunc(a, b) is func(a, b)
+                assert ufunc(a, b) == func(a, b)
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -1,253 +1,195 @@
 from pypy.jit.metainterp.test.support import LLJitMixin
 from pypy.module.micronumpy import interp_ufuncs, signature
-from pypy.module.micronumpy.compile import (numpy_compile, FakeSpace,
-    FloatObject, IntObject)
-from pypy.module.micronumpy.interp_dtype import W_Int32Dtype, W_Float64Dtype, W_Int64Dtype, W_UInt64Dtype
-from pypy.module.micronumpy.interp_numarray import (BaseArray, SingleDimArray,
-    SingleDimSlice, scalar_w)
+from pypy.module.micronumpy.compile import (FakeSpace,
+    FloatObject, IntObject, numpy_compile, BoolObject)
+from pypy.module.micronumpy.interp_numarray import (SingleDimArray,
+    SingleDimSlice)
 from pypy.rlib.nonconst import NonConstant
-from pypy.rpython.annlowlevel import llstr
-from pypy.rpython.test.test_llinterp import interpret
+from pypy.rpython.annlowlevel import llstr, hlstr
+from pypy.jit.metainterp.warmspot import reset_stats
+from pypy.jit.metainterp import pyjitpl
 
 import py
 
 
 class TestNumpyJIt(LLJitMixin):
-    def setup_class(cls):
-        cls.space = FakeSpace()
-        cls.float64_dtype = cls.space.fromcache(W_Float64Dtype)
-        cls.int64_dtype = cls.space.fromcache(W_Int64Dtype)
-        cls.uint64_dtype = cls.space.fromcache(W_UInt64Dtype)
-        cls.int32_dtype = cls.space.fromcache(W_Int32Dtype)
+    graph = None
+    interp = None
+        
+    def run(self, code):
+        space = FakeSpace()
+        
+        def f(code):
+            interp = numpy_compile(hlstr(code))
+            interp.run(space)
+            res = interp.results[-1]
+            w_res = res.eval(0).wrap(interp.space)
+            if isinstance(w_res, BoolObject):
+                return float(w_res.boolval)
+            elif isinstance(w_res, FloatObject):
+                return w_res.floatval
+            elif isinstance(w_res, IntObject):
+                return w_res.intval
+            else:
+                return -42.
+
+        if self.graph is None:
+            interp, graph = self.meta_interp(f, [llstr(code)],
+                                             listops=True,
+                                             backendopt=True,
+                                             graph_and_interp_only=True)
+            self.__class__.interp = interp
+            self.__class__.graph = graph
+
+        reset_stats()
+        pyjitpl._warmrunnerdesc.memory_manager.alive_loops.clear()
+        return self.interp.eval_graph(self.graph, [llstr(code)])
 
     def test_add(self):
-        def f(i):
-            ar = SingleDimArray(i, dtype=self.float64_dtype)
-            v = interp_ufuncs.get(self.space).add.call(self.space, [ar, ar])
-            return v.get_concrete().eval(3).val
-
-        result = self.meta_interp(f, [5], listops=True, backendopt=True)
+        result = self.run("""
+        a = |30|
+        b = a + a
+        b -> 3
+        """)
         self.check_loops({'getarrayitem_raw': 2, 'float_add': 1,
                           'setarrayitem_raw': 1, 'int_add': 1,
                           'int_lt': 1, 'guard_true': 1, 'jump': 1})
-        assert result == f(5)
+        assert result == 3 + 3
 
     def test_floatadd(self):
-        def f(i):
-            ar = SingleDimArray(i, dtype=self.float64_dtype)
-            v = interp_ufuncs.get(self.space).add.call(self.space, [
-                    ar,
-                    scalar_w(self.space, self.float64_dtype, self.space.wrap(4.5))
-                ],
-            )
-            assert isinstance(v, BaseArray)
-            return v.get_concrete().eval(3).val
-
-        result = self.meta_interp(f, [5], listops=True, backendopt=True)
+        result = self.run("""
+        a = |30| + 3
+        a -> 3
+        """)
+        assert result == 3 + 3
         self.check_loops({"getarrayitem_raw": 1, "float_add": 1,
                           "setarrayitem_raw": 1, "int_add": 1,
                           "int_lt": 1, "guard_true": 1, "jump": 1})
-        assert result == f(5)
 
     def test_sum(self):
-        space = self.space
-        float64_dtype = self.float64_dtype
-        int64_dtype = self.int64_dtype
-
-        def f(i):
-            if NonConstant(False):
-                dtype = int64_dtype
-            else:
-                dtype = float64_dtype
-            ar = SingleDimArray(i, dtype=dtype)
-            v = ar.descr_add(space, ar).descr_sum(space)
-            assert isinstance(v, FloatObject)
-            return v.floatval
-
-        result = self.meta_interp(f, [5], listops=True, backendopt=True)
+        result = self.run("""
+        a = |30|
+        b = a + a
+        sum(b)
+        """)
+        assert result == 2 * sum(range(30))
         self.check_loops({"getarrayitem_raw": 2, "float_add": 2,
                           "int_add": 1,
                           "int_lt": 1, "guard_true": 1, "jump": 1})
-        assert result == f(5)
 
     def test_prod(self):
-        space = self.space
-        float64_dtype = self.float64_dtype
-        int64_dtype = self.int64_dtype
-
-        def f(i):
-            if NonConstant(False):
-                dtype = int64_dtype
-            else:
-                dtype = float64_dtype
-            ar = SingleDimArray(i, dtype=dtype)
-            v = ar.descr_add(space, ar).descr_prod(space)
-            assert isinstance(v, FloatObject)
-            return v.floatval
-
-        result = self.meta_interp(f, [5], listops=True, backendopt=True)
+        result = self.run("""
+        a = |30|
+        b = a + a
+        prod(b)
+        """)
+        expected = 1
+        for i in range(30):
+            expected *= i * 2
+        assert result == expected
         self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
                           "float_mul": 1, "int_add": 1,
                           "int_lt": 1, "guard_true": 1, "jump": 1})
-        assert result == f(5)
 
     def test_max(self):
-        space = self.space
-        float64_dtype = self.float64_dtype
-        int64_dtype = self.int64_dtype
-
-        def f(i):
-            if NonConstant(False):
-                dtype = int64_dtype
-            else:
-                dtype = float64_dtype
-            ar = SingleDimArray(i, dtype=dtype)
-            j = 0
-            while j < i:
-                ar.get_concrete().setitem(j, float64_dtype.box(float(j)))
-                j += 1
-            v = ar.descr_add(space, ar).descr_max(space)
-            assert isinstance(v, FloatObject)
-            return v.floatval
-
-        result = self.meta_interp(f, [5], listops=True, backendopt=True)
+        py.test.skip("broken, investigate")
+        result = self.run("""
+        a = |30|
+        a[13] = 128
+        b = a + a
+        max(b)
+        """)
+        assert result == 256
         self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
-                          "float_gt": 1, "int_add": 1,
-                          "int_lt": 1, "guard_true": 1,
-                          "guard_false": 1, "jump": 1})
-        assert result == f(5)
+                          "float_mul": 1, "int_add": 1,
+                          "int_lt": 1, "guard_true": 1, "jump": 1})
 
     def test_min(self):
-        space = self.space
-        float64_dtype = self.float64_dtype
-        int64_dtype = self.int64_dtype
-
-        def f(i):
-            if NonConstant(False):
-                dtype = int64_dtype
-            else:
-                dtype = float64_dtype
-            ar = SingleDimArray(i, dtype=dtype)
-            j = 0
-            while j < i:
-                ar.get_concrete().setitem(j, float64_dtype.box(float(j)))
-                j += 1
-            v = ar.descr_add(space, ar).descr_min(space)
-            assert isinstance(v, FloatObject)
-            return v.floatval
-
-        result = self.meta_interp(f, [5], listops=True, backendopt=True)
+        py.test.skip("broken, investigate")
+        result = self.run("""
+        a = |30|
+        a[15] = -12
+        b = a + a
+        min(b)
+        """)
+        assert result == -24
         self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
-                           "float_lt": 1, "int_add": 1,
-                           "int_lt": 1, "guard_true": 2,
-                           "jump": 1})
-        assert result == f(5)
-
-    def test_argmin(self):
-        space = self.space
-        float64_dtype = self.float64_dtype
-
-        def f(i):
-            ar = SingleDimArray(i, dtype=NonConstant(float64_dtype))
-            j = 0
-            while j < i:
-                ar.get_concrete().setitem(j, float64_dtype.box(float(j)))
-                j += 1
-            return ar.descr_add(space, ar).descr_argmin(space).intval
-
-        result = self.meta_interp(f, [5], listops=True, backendopt=True)
-        self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
-                           "float_lt": 1, "int_add": 1,
-                           "int_lt": 1, "guard_true": 2,
-                           "jump": 1})
-        assert result == f(5)
-
-    def test_all(self):
-        space = self.space
-        float64_dtype = self.float64_dtype
-
-        def f(i):
-            ar = SingleDimArray(i, dtype=NonConstant(float64_dtype))
-            j = 0
-            while j < i:
-                ar.get_concrete().setitem(j, float64_dtype.box(1.0))
-                j += 1
-            return ar.descr_add(space, ar).descr_all(space).boolval
-
-        result = self.meta_interp(f, [5], listops=True, backendopt=True)
-        self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
-                          "int_add": 1, "float_ne": 1,
-                          "int_lt": 1, "guard_true": 2, "jump": 1})
-        assert result == f(5)
+                          "float_mul": 1, "int_add": 1,
+                          "int_lt": 1, "guard_true": 1, "jump": 1})
 
     def test_any(self):
-        space = self.space
-        float64_dtype = self.float64_dtype
-
-        def f(i):
-            ar = SingleDimArray(i, dtype=NonConstant(float64_dtype))
-            return ar.descr_add(space, ar).descr_any(space).boolval
-
-        result = self.meta_interp(f, [5], listops=True, backendopt=True)
+        result = self.run("""
+        a = [0,0,0,0,0,0,0,0,0,0,0]
+        a[8] = -12
+        b = a + a
+        any(b)
+        """)
+        assert result == 1
         self.check_loops({"getarrayitem_raw": 2, "float_add": 1,
-                          "int_add": 1, "float_ne": 1, "guard_false": 1,
-                          "int_lt": 1, "guard_true": 1, "jump": 1})
-        assert result == f(5)
+                          "float_ne": 1, "int_add": 1,
+                          "int_lt": 1, "guard_true": 1, "jump": 1,
+                          "guard_false": 1})
 
     def test_already_forced(self):
-        space = self.space
-
-        def f(i):
-            ar = SingleDimArray(i, dtype=self.float64_dtype)
-            v1 = interp_ufuncs.get(self.space).add.call(space, [ar, scalar_w(space, self.float64_dtype, space.wrap(4.5))])
-            assert isinstance(v1, BaseArray)
-            v2 = interp_ufuncs.get(self.space).multiply.call(space, [v1, scalar_w(space, self.float64_dtype, space.wrap(4.5))])
-            v1.force_if_needed()
-            assert isinstance(v2, BaseArray)
-            return v2.get_concrete().eval(3).val
-
-        result = self.meta_interp(f, [5], listops=True, backendopt=True)
+        result = self.run("""
+        a = |30|
+        b = a + 4.5
+        b -> 5 # forces
+        c = b * 8
+        c -> 5
+        """)
+        assert result == (5 + 4.5) * 8
         # This is the sum of the ops for both loops, however if you remove the
         # optimization then you end up with 2 float_adds, so we can still be
         # sure it was optimized correctly.
         self.check_loops({"getarrayitem_raw": 2, "float_mul": 1, "float_add": 1,
                            "setarrayitem_raw": 2, "int_add": 2,
                            "int_lt": 2, "guard_true": 2, "jump": 2})
-        assert result == f(5)
 
     def test_ufunc(self):
-        space = self.space
-        def f(i):
-            ar = SingleDimArray(i, dtype=self.float64_dtype)
-            v1 = interp_ufuncs.get(self.space).add.call(space, [ar, ar])
-            v2 = interp_ufuncs.get(self.space).negative.call(space, [v1])
-            return v2.get_concrete().eval(3).val
-
-        result = self.meta_interp(f, [5], listops=True, backendopt=True)
+        result = self.run("""
+        a = |30|
+        b = a + a
+        c = unegative(b)
+        c -> 3
+        """)
+        assert result == -6
         self.check_loops({"getarrayitem_raw": 2, "float_add": 1, "float_neg": 1,
                           "setarrayitem_raw": 1, "int_add": 1,
                           "int_lt": 1, "guard_true": 1, "jump": 1,
         })
-        assert result == f(5)
 
-    def test_appropriate_specialization(self):
-        space = self.space
-        def f(i):
-            ar = SingleDimArray(i, dtype=self.float64_dtype)
-
-            v1 = interp_ufuncs.get(self.space).add.call(space, [ar, ar])
-            v2 = interp_ufuncs.get(self.space).negative.call(space, [v1])
-            v2.get_concrete()
-
-            for i in xrange(5):
-                v1 = interp_ufuncs.get(self.space).multiply.call(space, [ar, ar])
-                v2 = interp_ufuncs.get(self.space).negative.call(space, [v1])
-                v2.get_concrete()
-
-        self.meta_interp(f, [5], listops=True, backendopt=True)
+    def test_specialization(self):
+        self.run("""
+        a = |30|
+        b = a + a
+        c = unegative(b)
+        c -> 3
+        d = a * a
+        unegative(d)
+        d -> 3
+        d = a * a
+        unegative(d)
+        d -> 3
+        d = a * a
+        unegative(d)
+        d -> 3
+        d = a * a
+        unegative(d)
+        d -> 3
+        """)
         # This is 3, not 2 because there is a bridge for the exit.
         self.check_loop_count(3)
 
+
+class TestNumpyOld(LLJitMixin):
+    def setup_class(cls):
+        from pypy.module.micronumpy.compile import FakeSpace
+        from pypy.module.micronumpy.interp_dtype import W_Float64Dtype
+        
+        cls.space = FakeSpace()
+        cls.float64_dtype = cls.space.fromcache(W_Float64Dtype)
+    
     def test_slice(self):
         def f(i):
             step = 3
@@ -332,17 +274,3 @@
         result = self.meta_interp(f, [5], listops=True, backendopt=True)
         assert result == f(5)
 
-class TestTranslation(object):
-    def test_compile(self):
-        x = numpy_compile('aa+f*f/a-', 10)
-        x = x.compute()
-        assert isinstance(x, SingleDimArray)
-        assert x.size == 10
-        assert x.eval(0).val == 0
-        assert x.eval(1).val == ((1 + 1) * 1.2) / 1.2 - 1
-
-    def test_translation(self):
-        # we import main to check if the target compiles
-        from pypy.translator.goal.targetnumpystandalone import main
-
-        interpret(main, [llstr('af+'), 100])
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
@@ -4,9 +4,9 @@
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.error import OperationError
 from pypy.objspace.descroperation import object_setattr
+from pypy.rlib import rgc
+from pypy.rlib.unroll import unrolling_iterable
 from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.rlib.unroll import unrolling_iterable
-
 from pypy.rpython.tool import rffi_platform
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.translator.platform import platform
@@ -118,6 +118,19 @@
         locals()[name] = rffi_platform.ConstantInteger(name)
     for name in xml_model_list:
         locals()[name] = rffi_platform.ConstantInteger(name)
+    for name in xml_model_list:
+        locals()[name] = rffi_platform.ConstantInteger(name)
+    for name in xml_model_list:
+        locals()[name] = rffi_platform.ConstantInteger(name)
+    for name in xml_model_list:
+        locals()[name] = rffi_platform.ConstantInteger(name)
+    for name in xml_model_list:
+        locals()[name] = rffi_platform.ConstantInteger(name)
+    for name in xml_model_list:
+        locals()[name] = rffi_platform.ConstantInteger(name)
+    for name in xml_model_list:
+        locals()[name] = rffi_platform.ConstantInteger(name)
+    XML_Parser_SIZE = rffi_platform.SizeOf("XML_Parser")
 
 for k, v in rffi_platform.configure(CConfigure).items():
     globals()[k] = v
@@ -793,7 +806,10 @@
             rffi.cast(rffi.CHAR, namespace_separator))
     else:
         xmlparser = XML_ParserCreate(encoding)
-
+    # Currently this is just the size of the pointer and some estimated bytes.
+    # The struct isn't actually defined in expat.h - it is in xmlparse.c
+    # XXX: find a good estimate of the XML_ParserStruct
+    rgc.add_memory_pressure(XML_Parser_SIZE + 300)
     if not xmlparser:
         raise OperationError(space.w_RuntimeError,
                              space.wrap('XML_ParserCreate failed'))
diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py
--- a/pypy/module/pypyjit/policy.py
+++ b/pypy/module/pypyjit/policy.py
@@ -16,7 +16,8 @@
         if modname in ['pypyjit', 'signal', 'micronumpy', 'math', 'exceptions',
                        'imp', 'sys', 'array', '_ffi', 'itertools', 'operator',
                        'posix', '_socket', '_sre', '_lsprof', '_weakref',
-                       '__pypy__', 'cStringIO', '_collections', 'struct']:
+                       '__pypy__', 'cStringIO', '_collections', 'struct',
+                       'mmap']:
             return True
         return False
 
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -465,3 +465,25 @@
             setfield_gc(p4, p22, descr=<GcPtrFieldDescr pypy.interpreter.nestedscope.Cell.inst_w_value .*>)
             jump(p0, p1, p2, p3, p4, p7, p22, p7, descr=<Loop0>)
         """)
+
+    def test_kwargs_virtual(self):
+        def main(n):
+            def g(**kwargs):
+                return kwargs["x"] + 1
+
+            i = 0
+            while i < n:
+                i = g(x=i)
+            return i
+
+        log = self.run(main, [500])
+        assert log.result == 500
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match("""
+            i2 = int_lt(i0, i1)
+            guard_true(i2, descr=...)
+            i3 = force_token()
+            i4 = int_add(i0, 1)
+            --TICK--
+            jump(..., descr=...)
+        """)
\ No newline at end of file
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
@@ -44,9 +44,9 @@
         # gc_id call is hoisted out of the loop, the id of a value obviously
         # can't change ;)
         assert loop.match_by_id("getitem", """
-            i28 = call(ConstClass(ll_dict_lookup__dicttablePtr_objectPtr_Signed), p18, p6, i25, descr=...)
+            i26 = call(ConstClass(ll_dict_lookup), p18, p6, i25, descr=...)
             ...
-            p33 = getinteriorfield_gc(p31, i26, <InteriorFieldDescr <GcPtrFieldDescr dictentry.value .*>>)
+            p33 = getinteriorfield_gc(p31, i26, descr=<InteriorFieldDescr <GcPtrFieldDescr dictentry.value .*>>)
             ...
         """)
 
@@ -69,4 +69,51 @@
             i9 = int_add(i5, 1)
             --TICK--
             jump(..., descr=...)
+        """)
+
+    def test_non_virtual_dict(self):
+        def main(n):
+            i = 0
+            while i < n:
+                d = {str(i): i}
+                i += d[str(i)] - i + 1
+            return i
+
+        log = self.run(main, [1000])
+        assert log.result == main(1000)
+        loop, = log.loops_by_filename(self.filepath)
+        assert loop.match("""
+            i8 = int_lt(i5, i7)
+            guard_true(i8, descr=...)
+            guard_not_invalidated(descr=...)
+            p10 = call(ConstClass(ll_int_str), i5, descr=<GcPtrCallDescr>)
+            guard_no_exception(descr=...)
+            i12 = call(ConstClass(ll_strhash), p10, descr=<SignedCallDescr>)
+            p13 = new(descr=...)
+            p15 = new_array(8, descr=<dictentryArrayDescr>)
+            setfield_gc(p13, p15, descr=<GcPtrFieldDescr dicttable.entries .*>)
+            i17 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<SignedCallDescr>)
+            setfield_gc(p13, 16, descr=<SignedFieldDescr dicttable.resize_counter .*>)
+            guard_no_exception(descr=...)
+            p20 = new_with_vtable(ConstClass(W_IntObject))
+            call(ConstClass(_ll_dict_setitem_lookup_done_trampoline), p13, p10, p20, i12, i17, descr=<VoidCallDescr>)
+            setfield_gc(p20, i5, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
+            guard_no_exception(descr=...)
+            i23 = call(ConstClass(ll_dict_lookup_trampoline), p13, p10, i12, descr=<SignedCallDescr>)
+            guard_no_exception(descr=...)
+            i26 = int_and(i23, .*)
+            i27 = int_is_true(i26)
+            guard_false(i27, descr=...)
+            p28 = getfield_gc(p13, descr=<GcPtrFieldDescr dicttable.entries .*>)
+            p29 = getinteriorfield_gc(p28, i23, descr=<InteriorFieldDescr <GcPtrFieldDescr dictentry.value .*>>)
+            guard_nonnull_class(p29, ConstClass(W_IntObject), descr=...)
+            i31 = getfield_gc_pure(p29, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
+            i32 = int_sub_ovf(i31, i5)
+            guard_no_overflow(descr=...)
+            i34 = int_add_ovf(i32, 1)
+            guard_no_overflow(descr=...)
+            i35 = int_add_ovf(i5, i34)
+            guard_no_overflow(descr=...)
+            --TICK--
+            jump(p0, p1, p2, p3, p4, i35, p13, i7, descr=<Loop0>)
         """)
\ No newline at end of file
diff --git a/pypy/module/rctime/interp_time.py b/pypy/module/rctime/interp_time.py
--- a/pypy/module/rctime/interp_time.py
+++ b/pypy/module/rctime/interp_time.py
@@ -245,6 +245,9 @@
 if sys.platform != 'win32':
     @unwrap_spec(secs=float)
     def sleep(space, secs):
+        if secs < 0:
+            raise OperationError(space.w_IOError,
+                                 space.wrap("Invalid argument: negative time in sleep"))
         pytime.sleep(secs)
 else:
     from pypy.rlib import rwin32
@@ -265,6 +268,9 @@
                                    OSError(EINTR, "sleep() interrupted"))
     @unwrap_spec(secs=float)
     def sleep(space, secs):
+        if secs < 0:
+            raise OperationError(space.w_IOError,
+                                 space.wrap("Invalid argument: negative time in sleep"))
         # as decreed by Guido, only the main thread can be
         # interrupted.
         main_thread = space.fromcache(State).main_thread
diff --git a/pypy/module/rctime/test/test_rctime.py b/pypy/module/rctime/test/test_rctime.py
--- a/pypy/module/rctime/test/test_rctime.py
+++ b/pypy/module/rctime/test/test_rctime.py
@@ -20,8 +20,9 @@
         import sys
         import os
         raises(TypeError, rctime.sleep, "foo")
-        rctime.sleep(1.2345)
-        
+        rctime.sleep(0.12345)
+        raises(IOError, rctime.sleep, -1.0)
+
     def test_clock(self):
         import time as rctime
         rctime.clock()
diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py
--- a/pypy/module/thread/ll_thread.py
+++ b/pypy/module/thread/ll_thread.py
@@ -2,10 +2,11 @@
 from pypy.rpython.lltypesystem import rffi, lltype, llmemory
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 import py
-from pypy.rlib import jit
+from pypy.rlib import jit, rgc
 from pypy.rlib.debug import ll_assert
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rpython.lltypesystem.lloperation import llop
+from pypy.rpython.tool import rffi_platform
 from pypy.tool import autopath
 
 class error(Exception):
@@ -49,7 +50,7 @@
 
 TLOCKP = rffi.COpaquePtr('struct RPyOpaque_ThreadLock',
                           compilation_info=eci)
-
+TLOCKP_SIZE = rffi_platform.sizeof('struct RPyOpaque_ThreadLock', eci)
 c_thread_lock_init = llexternal('RPyThreadLockInit', [TLOCKP], rffi.INT,
                                 threadsafe=False)   # may add in a global list
 c_thread_lock_dealloc_NOAUTO = llexternal('RPyOpaqueDealloc_ThreadLock',
@@ -173,6 +174,9 @@
     if rffi.cast(lltype.Signed, res) <= 0:
         lltype.free(ll_lock, flavor='raw', track_allocation=False)
         raise error("out of resources")
+    # Add some memory pressure for the size of the lock because it is an
+    # Opaque object
+    rgc.add_memory_pressure(TLOCKP_SIZE)
     return ll_lock
 
 def free_ll_lock(ll_lock):
diff --git a/pypy/objspace/std/boolobject.py b/pypy/objspace/std/boolobject.py
--- a/pypy/objspace/std/boolobject.py
+++ b/pypy/objspace/std/boolobject.py
@@ -27,11 +27,7 @@
 
     def uint_w(w_self, space):
         intval = int(w_self.boolval)
-        if intval < 0:
-            raise OperationError(space.w_ValueError,
-                                 space.wrap("cannot convert negative integer to unsigned"))
-        else:
-            return r_uint(intval)
+        return r_uint(intval)
 
     def bigint_w(w_self, space):
         return rbigint.fromint(int(w_self.boolval))
diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -226,17 +226,9 @@
     return space.wrapbytes(''.join(w_bytearray.data))
 
 def _convert_idx_params(space, w_self, w_start, w_stop):
-    start = slicetype.eval_slice_index(space, w_start)
-    stop = slicetype.eval_slice_index(space, w_stop)
     length = len(w_self.data)
-    if start < 0:
-        start += length
-        if start < 0:
-            start = 0
-    if stop < 0:
-        stop += length
-        if stop < 0:
-            stop = 0
+    start, stop = slicetype.unwrap_start_stop(
+            space, length, w_start, w_stop, False)
     return start, stop, length
 
 def str_count__Bytearray_Int_ANY_ANY(space, w_bytearray, w_char, w_start, w_stop):
diff --git a/pypy/objspace/std/floatobject.py b/pypy/objspace/std/floatobject.py
--- a/pypy/objspace/std/floatobject.py
+++ b/pypy/objspace/std/floatobject.py
@@ -546,6 +546,12 @@
     # Try to return int.
     return space.newtuple([space.int(w_num), space.int(w_den)])
 
+def float_is_integer__Float(space, w_float):
+    v = w_float.floatval
+    if not rfloat.isfinite(v):
+        return space.w_False
+    return space.wrap(math.floor(v) == v)
+
 from pypy.objspace.std import floattype
 register_all(vars(), floattype)
 
diff --git a/pypy/objspace/std/floattype.py b/pypy/objspace/std/floattype.py
--- a/pypy/objspace/std/floattype.py
+++ b/pypy/objspace/std/floattype.py
@@ -12,6 +12,7 @@
 
 
 float_as_integer_ratio = SMM("as_integer_ratio", 1)
+float_is_integer = SMM("is_integer", 1)
 float_hex = SMM("hex", 1)
 
 def descr_conjugate(space, w_float):
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -54,7 +54,12 @@
 
 def _init_from_iterable(space, items_w, w_iterable):
     # in its own function to make the JIT look into init__List
-    # XXX this would need a JIT driver somehow?
+    # xxx special hack for speed
+    from pypy.interpreter.generator import GeneratorIterator
+    if isinstance(w_iterable, GeneratorIterator):
+        w_iterable.unpack_into(items_w)
+        return
+    # /xxx
     w_iterator = space.iter(w_iterable)
     while True:
         try:
@@ -395,8 +400,8 @@
     # needs to be safe against eq_w() mutating the w_list behind our back
     items = w_list.wrappeditems
     size = len(items)
-    i = slicetype.adapt_bound(space, size, w_start)
-    stop = slicetype.adapt_bound(space, size, w_stop)
+    i, stop = slicetype.unwrap_start_stop(
+            space, size, w_start, w_stop, True)
     while i < stop and i < len(items):
         if space.eq_w(items[i], w_any):
             return space.wrap(i)
diff --git a/pypy/objspace/std/model.py b/pypy/objspace/std/model.py
--- a/pypy/objspace/std/model.py
+++ b/pypy/objspace/std/model.py
@@ -66,19 +66,11 @@
         from pypy.objspace.std import floatobject
         from pypy.objspace.std import complexobject
         from pypy.objspace.std import setobject
-        from pypy.objspace.std import smallintobject
-        from pypy.objspace.std import smalllongobject
         from pypy.objspace.std import tupleobject
-        from pypy.objspace.std import smalltupleobject
         from pypy.objspace.std import listobject
         from pypy.objspace.std import dictmultiobject
         from pypy.objspace.std import stringobject
         from pypy.objspace.std import bytearrayobject
-        from pypy.objspace.std import ropeobject
-        from pypy.objspace.std import ropeunicodeobject
-        from pypy.objspace.std import strsliceobject
-        from pypy.objspace.std import strjoinobject
-        from pypy.objspace.std import strbufobject
         from pypy.objspace.std import typeobject
         from pypy.objspace.std import sliceobject
         from pypy.objspace.std import longobject
@@ -137,7 +129,12 @@
         for option, value in config.objspace.std:
             if option.startswith("with") and option in option_to_typename:
                 for classname in option_to_typename[option]:
-                    implcls = eval(classname)
+                    modname = classname[:classname.index('.')]
+                    classname = classname[classname.index('.')+1:]
+                    d = {}
+                    exec "from pypy.objspace.std.%s import %s" % (
+                        modname, classname) in d
+                    implcls = d[classname]
                     if value:
                         self.typeorder[implcls] = []
                     else:
@@ -163,6 +160,7 @@
         # XXX build these lists a bit more automatically later
 
         if config.objspace.std.withsmallint:
+            from pypy.objspace.std import smallintobject
             self.typeorder[boolobject.W_BoolObject] += [
                 (smallintobject.W_SmallIntObject, boolobject.delegate_Bool2SmallInt),
                 ]
@@ -185,6 +183,7 @@
             (complexobject.W_ComplexObject, complexobject.delegate_Int2Complex),
             ]
         if config.objspace.std.withsmalllong:
+            from pypy.objspace.std import smalllongobject
             self.typeorder[boolobject.W_BoolObject] += [
                 (smalllongobject.W_SmallLongObject, smalllongobject.delegate_Bool2SmallLong),
                 ]
@@ -212,21 +211,25 @@
             (setobject.W_BaseSetObject, None)
             ]
         if config.objspace.std.withstrslice:
+            from pypy.objspace.std import strsliceobject
             self.typeorder[strsliceobject.W_StringSliceObject] += [
                 (stringobject.W_StringObject,
                                        strsliceobject.delegate_slice2str),
                 ]
         if config.objspace.std.withstrjoin:
+            from pypy.objspace.std import strjoinobject
             self.typeorder[strjoinobject.W_StringJoinObject] += [
                 (stringobject.W_StringObject,
                                        strjoinobject.delegate_join2str),
                 ]
         elif config.objspace.std.withstrbuf:
+            from pypy.objspace.std import strbufobject
             self.typeorder[strbufobject.W_StringBufferObject] += [
                 (stringobject.W_StringObject,
                                        strbufobject.delegate_buf2str),
                 ]
         if config.objspace.std.withsmalltuple:
+            from pypy.objspace.std import smalltupleobject
             self.typeorder[smalltupleobject.W_SmallTupleObject] += [
                 (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)]
 
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/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -88,11 +88,12 @@
         if self.config.objspace.std.withtproxy:
             transparent.setup(self)
 
+        interplevel_classes = {}
         for type, classes in self.model.typeorder.iteritems():
-            if len(classes) >= 3:
+            if len(classes) >= 3: # XXX what does this 3 mean??!
                 # W_Root, AnyXxx and actual object
-                self.gettypefor(type).interplevel_cls = classes[0][0]
-
+                interplevel_classes[self.gettypefor(type)] = classes[0][0]
+        self._interplevel_classes = interplevel_classes
 
     def get_builtin_types(self):
         return self.builtin_types
@@ -421,7 +422,7 @@
         else:
             if unroll:
                 return make_sure_not_resized(ObjSpace.unpackiterable_unroll(
-                    self, w_obj, expected_length)[:])
+                    self, w_obj, expected_length))
             else:
                 return make_sure_not_resized(ObjSpace.unpackiterable(
                     self, w_obj, expected_length)[:])
@@ -429,7 +430,8 @@
             raise self._wrap_expected_length(expected_length, len(t))
         return make_sure_not_resized(t)
 
-    def fixedview_unroll(self, w_obj, expected_length=-1):
+    def fixedview_unroll(self, w_obj, expected_length):
+        assert expected_length >= 0
         return self.fixedview(w_obj, expected_length, unroll=True)
 
     def listview(self, w_obj, expected_length=-1):
@@ -587,7 +589,7 @@
             raise OperationError(self.w_TypeError,
                                  self.wrap("need type object"))
         if is_annotation_constant(w_type):
-            cls = w_type.interplevel_cls
+            cls = self._get_interplevel_cls(w_type)
             if cls is not None:
                 assert w_inst is not None
                 if isinstance(w_inst, cls):
@@ -597,3 +599,9 @@
     @specialize.arg_or_var(2)
     def isinstance_w(space, w_inst, w_type):
         return space._type_isinstance(w_inst, w_type)
+
+    @specialize.memo()
+    def _get_interplevel_cls(self, w_type):
+        if not hasattr(self, "_interplevel_classes"):
+            return None # before running initialize
+        return self._interplevel_classes.get(w_type, None)
diff --git a/pypy/objspace/std/ropeobject.py b/pypy/objspace/std/ropeobject.py
--- a/pypy/objspace/std/ropeobject.py
+++ b/pypy/objspace/std/ropeobject.py
@@ -355,16 +355,8 @@
     self = w_self._node
     sub = w_sub._node
 
-    if space.is_w(w_start, space.w_None):
-        w_start = space.wrap(0)
-    if space.is_w(w_end, space.w_None):
-        w_end = space.len(w_self)
-    if upper_bound:
-        start = slicetype.adapt_bound(space, self.length(), w_start)
-        end = slicetype.adapt_bound(space, self.length(), w_end)
-    else:
-        start = slicetype.adapt_lower_bound(space, self.length(), w_start)
-        end = slicetype.adapt_lower_bound(space, self.length(), w_end)
+    start, end = slicetype.unwrap_start_stop(
+            space, self.length(), w_start, w_end, upper_bound)
 
     return (self, sub, start, end)
 _convert_idx_params._annspecialcase_ = 'specialize:arg(5)'
diff --git a/pypy/objspace/std/sliceobject.py b/pypy/objspace/std/sliceobject.py
--- a/pypy/objspace/std/sliceobject.py
+++ b/pypy/objspace/std/sliceobject.py
@@ -4,7 +4,7 @@
 from pypy.interpreter import gateway
 from pypy.objspace.std.model import registerimplementation, W_Object
 from pypy.objspace.std.register_all import register_all
-from pypy.objspace.std.slicetype import eval_slice_index
+from pypy.objspace.std.slicetype import _eval_slice_index
 
 class W_SliceObject(W_Object):
     from pypy.objspace.std.slicetype import slice_typedef as typedef
@@ -25,7 +25,7 @@
         if space.is_w(w_slice.w_step, space.w_None):
             step = 1
         else:
-            step = eval_slice_index(space, w_slice.w_step)
+            step = _eval_slice_index(space, w_slice.w_step)
             if step == 0:
                 raise OperationError(space.w_ValueError,
                                      space.wrap("slice step cannot be zero"))
@@ -35,7 +35,7 @@
             else:
                 start = 0
         else:
-            start = eval_slice_index(space, w_slice.w_start)
+            start = _eval_slice_index(space, w_slice.w_start)
             if start < 0:
                 start += length
                 if start < 0:
@@ -54,7 +54,7 @@
             else:
                 stop = length
         else:
-            stop = eval_slice_index(space, w_slice.w_stop)
+            stop = _eval_slice_index(space, w_slice.w_stop)
             if stop < 0:
                 stop += length
                 if stop < 0:
diff --git a/pypy/objspace/std/slicetype.py b/pypy/objspace/std/slicetype.py
--- a/pypy/objspace/std/slicetype.py
+++ b/pypy/objspace/std/slicetype.py
@@ -3,6 +3,7 @@
 from pypy.objspace.std.stdtypedef import StdTypeDef, SMM
 from pypy.objspace.std.register_all import register_all
 from pypy.interpreter.error import OperationError
+from pypy.rlib.objectmodel import specialize
 
 # indices multimehtod
 slice_indices = SMM('indices', 2,
@@ -14,7 +15,9 @@
                         ' normal slices.')
 
 # utility functions
-def eval_slice_index(space, w_int):
+def _eval_slice_index(space, w_int):
+    # note that it is the *callers* responsibility to check for w_None
+    # otherwise you can get funny error messages
     try:
         return space.getindex_w(w_int, None) # clamp if long integer too large
     except OperationError, err:
@@ -25,7 +28,7 @@
                                         "None or have an __index__ method"))
 
 def adapt_lower_bound(space, size, w_index):
-    index = eval_slice_index(space, w_index)
+    index = _eval_slice_index(space, w_index)
     if index < 0:
         index = index + size
         if index < 0:
@@ -34,16 +37,29 @@
     return index
 
 def adapt_bound(space, size, w_index):
-    index = eval_slice_index(space, w_index)
-    if index < 0:
-        index = index + size
-        if index < 0:
-            index = 0
+    index = adapt_lower_bound(space, size, w_index)
     if index > size:
         index = size
     assert index >= 0
     return index
 
+ at specialize.arg(4)
+def unwrap_start_stop(space, size, w_start, w_end, upper_bound=False):
+    if space.is_w(w_start, space.w_None):
+        start = 0
+    elif upper_bound:
+        start = adapt_bound(space, size, w_start)
+    else:
+        start = adapt_lower_bound(space, size, w_start)
+
+    if space.is_w(w_end, space.w_None):
+        end = size
+    elif upper_bound:
+        end = adapt_bound(space, size, w_end)
+    else:
+        end = adapt_lower_bound(space, size, w_end)
+    return start, end
+
 register_all(vars(), globals())
 
 # ____________________________________________________________
diff --git a/pypy/objspace/std/smallintobject.py b/pypy/objspace/std/smallintobject.py
--- a/pypy/objspace/std/smallintobject.py
+++ b/pypy/objspace/std/smallintobject.py
@@ -12,6 +12,7 @@
 from pypy.rlib.rbigint import rbigint
 from pypy.rlib.rarithmetic import r_uint
 from pypy.tool.sourcetools import func_with_new_name
+from pypy.objspace.std.inttype import wrapint
 
 class W_SmallIntObject(W_Object, UnboxedValue):
     __slots__ = 'intval'
@@ -48,14 +49,36 @@
 def delegate_SmallInt2Complex(space, w_small):
     return space.newcomplex(float(w_small.intval), 0.0)
 
+def add__SmallInt_SmallInt(space, w_a, w_b):
+    return wrapint(space, w_a.intval + w_b.intval) # cannot overflow
+
+def sub__SmallInt_SmallInt(space, w_a, w_b):
+    return wrapint(space, w_a.intval - w_b.intval) # cannot overflow
+
+def floordiv__SmallInt_SmallInt(space, w_a, w_b):
+    return wrapint(space, w_a.intval // w_b.intval) # cannot overflow
+
+div__SmallInt_SmallInt = floordiv__SmallInt_SmallInt
+
+def mod__SmallInt_SmallInt(space, w_a, w_b):
+    return wrapint(space, w_a.intval % w_b.intval) # cannot overflow
+
+def divmod__SmallInt_SmallInt(space, w_a, w_b):
+    w = wrapint(space, w_a.intval // w_b.intval) # cannot overflow
+    z = wrapint(space, w_a.intval % w_b.intval)
+    return space.newtuple([w, z])
+
 def copy_multimethods(ns):
     """Copy integer multimethods for small int."""
     for name, func in intobject.__dict__.iteritems():
         if "__Int" in name:
             new_name = name.replace("Int", "SmallInt")
-            # Copy the function, so the annotator specializes it for
-            # W_SmallIntObject.
-            ns[new_name] = func_with_new_name(func, new_name)
+            if new_name not in ns:
+                # Copy the function, so the annotator specializes it for
+                # W_SmallIntObject.
+                ns[new_name] = func = func_with_new_name(func, new_name, globals=ns)
+        else:
+            ns[name] = func
     ns["get_integer"] = ns["pos__SmallInt"] = ns["int__SmallInt"]
     ns["get_negint"] = ns["neg__SmallInt"]
 
diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py
--- a/pypy/objspace/std/smalltupleobject.py
+++ b/pypy/objspace/std/smalltupleobject.py
@@ -68,10 +68,10 @@
             raise IndexError
 
         def eq(self, space, w_other):
-            if self.length() != w_other.length():
+            if n != w_other.length():
                 return space.w_False
             for i in iter_n:
-                item1 = self.getitem(i)
+                item1 = getattr(self,'w_value%s' % i)
                 item2 = w_other.getitem(i)
                 if not space.eq_w(item1, item2):
                     return space.w_False
@@ -80,9 +80,9 @@
         def hash(self, space):
             mult = 1000003
             x = 0x345678
-            z = self.length()
+            z = n
             for i in iter_n:
-                w_item = self.getitem(i)
+                w_item = getattr(self, 'w_value%s' % i)
                 y = space.int_w(space.hash(w_item))
                 x = (x ^ y) * mult
                 z -= 1
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
@@ -4,7 +4,7 @@
 from pypy.interpreter.error import OperationError, operationerrfmt
 from pypy.interpreter import gateway
 from pypy.rlib.rarithmetic import ovfcheck
-from pypy.rlib.objectmodel import we_are_translated, compute_hash
+from pypy.rlib.objectmodel import we_are_translated, compute_hash, specialize
 from pypy.objspace.std.inttype import wrapint
 from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
 from pypy.objspace.std import slicetype, newformat
@@ -47,6 +47,7 @@
 W_StringObject.PREBUILT = [W_StringObject(chr(i)) for i in range(256)]
 del i
 
+ at specialize.arg(2)
 def _is_generic(space, w_self, fun):
     v = w_self._value
     if len(v) == 0:
@@ -56,14 +57,13 @@
         return space.newbool(fun(c))
     else:
         return _is_generic_loop(space, v, fun)
-_is_generic._annspecialcase_ = "specialize:arg(2)"
 
+ at specialize.arg(2)
 def _is_generic_loop(space, v, fun):
     for idx in range(len(v)):
         if not fun(v[idx]):
             return space.w_False
     return space.w_True
-_is_generic_loop._annspecialcase_ = "specialize:arg(2)"
 
 def _upper(ch):
     if ch.islower():
@@ -414,22 +414,14 @@
 
     return space.wrapbytes(u_self)
 
-def _convert_idx_params(space, w_self, w_sub, w_start, w_end, upper_bound=False):
+ at specialize.arg(4)
+def _convert_idx_params(space, w_self, w_start, w_end, upper_bound=False):
     self = w_self._value
-    sub = w_sub._value
+    lenself = len(self)
 
-    if space.is_w(w_start, space.w_None):
-        w_start = space.wrap(0)
-    if space.is_w(w_end, space.w_None):
-        w_end = space.len(w_self)
-    if upper_bound:
-        start = slicetype.adapt_bound(space, len(self), w_start)
-        end = slicetype.adapt_bound(space, len(self), w_end)
-    else:
-        start = slicetype.adapt_lower_bound(space, len(self), w_start)
-        end = slicetype.adapt_lower_bound(space, len(self), w_end)
-    return (self, sub, start, end)
-_convert_idx_params._annspecialcase_ = 'specialize:arg(5)'
+    start, end = slicetype.unwrap_start_stop(
+            space, lenself, w_start, w_end, upper_bound=upper_bound)
+    return (self, start, end)
 
 def contains__String_String(space, w_self, w_sub):
     self = w_self._value
@@ -442,13 +434,13 @@
     return space.newbool(self.find(chr(char)) >= 0)
 
 def str_find__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-    (self, sub, start, end) =  _convert_idx_params(space, w_self, w_sub, w_start, w_end)
-    res = self.find(sub, start, end)
+    (self, start, end) =  _convert_idx_params(space, w_self, w_start, w_end)
+    res = self.find(w_sub._value, start, end)
     return space.wrap(res)
 
 def str_rfind__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-    (self, sub, start, end) =  _convert_idx_params(space, w_self, w_sub, w_start, w_end)
-    res = self.rfind(sub, start, end)
+    (self, start, end) =  _convert_idx_params(space, w_self, w_start, w_end)
+    res = self.rfind(w_sub._value, start, end)
     return space.wrap(res)
 
 def str_partition__String_String(space, w_self, w_sub):
@@ -482,8 +474,8 @@
 
 
 def str_index__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-    (self, sub, start, end) =  _convert_idx_params(space, w_self, w_sub, w_start, w_end)
-    res = self.find(sub, start, end)
+    (self, start, end) =  _convert_idx_params(space, w_self, w_start, w_end)
+    res = self.find(w_sub._value, start, end)
     if res < 0:
         raise OperationError(space.w_ValueError,
                              space.wrap("substring not found in string.index"))
@@ -492,8 +484,8 @@
 
 
 def str_rindex__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-    (self, sub, start, end) =  _convert_idx_params(space, w_self, w_sub, w_start, w_end)
-    res = self.rfind(sub, start, end)
+    (self, start, end) =  _convert_idx_params(space, w_self, w_start, w_end)
+    res = self.rfind(w_sub._value, start, end)
     if res < 0:
         raise OperationError(space.w_ValueError,
                              space.wrap("substring not found in string.rindex"))
@@ -635,20 +627,17 @@
     return wrapstr(space, u_centered)
 
 def str_count__String_String_ANY_ANY(space, w_self, w_arg, w_start, w_end):
-    u_self, u_arg, u_start, u_end = _convert_idx_params(space, w_self, w_arg,
-                                                        w_start, w_end)
-    return wrapint(space, u_self.count(u_arg, u_start, u_end))
+    u_self, u_start, u_end = _convert_idx_params(space, w_self, w_start, w_end)
+    return wrapint(space, u_self.count(w_arg._value, u_start, u_end))
 
 def str_endswith__String_String_ANY_ANY(space, w_self, w_suffix, w_start, w_end):
-    (u_self, suffix, start, end) = _convert_idx_params(space, w_self,
-                                                       w_suffix, w_start,
-                                                       w_end, True)
-    return space.newbool(stringendswith(u_self, suffix, start, end))
+    (u_self, start, end) = _convert_idx_params(space, w_self, w_start,
+                                               w_end, True)
+    return space.newbool(stringendswith(u_self, w_suffix._value, start, end))
 
 def str_endswith__String_Tuple_ANY_ANY(space, w_self, w_suffixes, w_start, w_end):
-    (u_self, _, start, end) = _convert_idx_params(space, w_self,
-                                                  space.wrapbytes(''),
-                                                  w_start, w_end, True)
+    (u_self, start, end) = _convert_idx_params(space, w_self, w_start,
+                                               w_end, True)
     for w_suffix in space.fixedview(w_suffixes):
         if space.isinstance_w(w_suffix, space.w_unicode):
             w_u = space.call_function(space.w_unicode, w_self)
@@ -660,15 +649,13 @@
     return space.w_False
 
 def str_startswith__String_String_ANY_ANY(space, w_self, w_prefix, w_start, w_end):
-    (u_self, prefix, start, end) = _convert_idx_params(space, w_self,
-                                                       w_prefix, w_start,
-                                                       w_end, True)
-    return space.newbool(stringstartswith(u_self, prefix, start, end))
+    (u_self, start, end) = _convert_idx_params(space, w_self, w_start,
+                                               w_end, True)
+    return space.newbool(stringstartswith(u_self, w_prefix._value, start, end))
 
 def str_startswith__String_Tuple_ANY_ANY(space, w_self, w_prefixes, w_start, w_end):
-    (u_self, _, start, end) = _convert_idx_params(space, w_self,
-                                                  space.wrapbytes(''),
-                                                  w_start, w_end, True)
+    (u_self, start, end) = _convert_idx_params(space, w_self,
+                                               w_start, w_end, True)
     for w_prefix in space.fixedview(w_prefixes):
         if space.isinstance_w(w_prefix, space.w_unicode):
             w_u = space.call_function(space.w_unicode, w_self)
diff --git a/pypy/objspace/std/strsliceobject.py b/pypy/objspace/std/strsliceobject.py
--- a/pypy/objspace/std/strsliceobject.py
+++ b/pypy/objspace/std/strsliceobject.py
@@ -55,8 +55,8 @@
 def _convert_idx_params(space, w_self, w_sub, w_start, w_end):
     length = w_self.stop - w_self.start
     sub = w_sub._value
-    start = slicetype.adapt_bound(space, length, w_start)
-    end = slicetype.adapt_bound(space, length, w_end)
+    start, end = slicetype.unwrap_start_stop(
+            space, length, w_start, w_end, True)
 
     assert start >= 0
     assert end >= 0
diff --git a/pypy/objspace/std/test/test_floatobject.py b/pypy/objspace/std/test/test_floatobject.py
--- a/pypy/objspace/std/test/test_floatobject.py
+++ b/pypy/objspace/std/test/test_floatobject.py
@@ -63,6 +63,12 @@
     def setup_class(cls):
         cls.w_py26 = cls.space.wrap(sys.version_info >= (2, 6))
 
+    def test_isinteger(self):
+        assert (1.).is_integer()
+        assert not (1.1).is_integer()
+        assert not float("inf").is_integer()
+        assert not float("nan").is_integer()
+
     def test_conjugate(self):
         assert (1.).conjugate() == 1.
         assert (-1.).conjugate() == -1.
@@ -782,4 +788,4 @@
         # divide by 0
         raises(ZeroDivisionError, lambda: inf % 0)
         raises(ZeroDivisionError, lambda: inf // 0)
-        raises(ZeroDivisionError, divmod, inf, 0)
\ No newline at end of file
+        raises(ZeroDivisionError, divmod, inf, 0)
diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -2,11 +2,10 @@
 from pypy.objspace.std.listobject import W_ListObject
 from pypy.interpreter.error import OperationError
 
-from pypy.conftest import gettestobjspace
+from pypy.conftest import gettestobjspace, option
 
 
 class TestW_ListObject(object):
-
     def test_is_true(self):
         w = self.space.wrap
         w_list = W_ListObject([])
@@ -343,6 +342,13 @@
 
 
 class AppTestW_ListObject(object):
+    def setup_class(cls):
+        import sys
+        on_cpython = (option.runappdirect and
+                            not hasattr(sys, 'pypy_translation_info'))
+
+        cls.w_on_cpython = cls.space.wrap(on_cpython)
+
     def test_call_list(self):
         assert list('') == []
         assert list('abc') == ['a', 'b', 'c']
@@ -616,6 +622,14 @@
         assert c.index(0) == 0
         raises(ValueError, c.index, 3)
 
+    def test_index_cpython_bug(self):
+        if self.on_cpython:
+            skip("cpython has a bug here")
+        c = list('hello world')
+        assert c.index('l', None, None) == 2
+        assert c.index('l', 3, None) == 3
+        assert c.index('l', None, 4) == 2
+
     def test_ass_slice(self):
         l = range(6)
         l[1:3] = 'abc'
@@ -801,6 +815,20 @@
         l.__delslice__(0, 2)
         assert l == [3, 4]
 
+    def test_list_from_set(self):
+        l = ['a']
+        l.__init__(set('b'))
+        assert l == ['b']
+
+    def test_list_from_generator(self):
+        l = ['a']
+        g = (i*i for i in range(5))
+        l.__init__(g)
+        assert l == [0, 1, 4, 9, 16]
+        l.__init__(g)
+        assert l == []
+        assert list(g) == []
+
 
 class AppTestListFastSubscr:
 
diff --git a/pypy/objspace/std/test/test_obj.py b/pypy/objspace/std/test/test_obj.py
--- a/pypy/objspace/std/test/test_obj.py
+++ b/pypy/objspace/std/test/test_obj.py
@@ -102,3 +102,11 @@
             def __repr__(self):
                 return 123456
         assert A().__str__() == 123456
+
+def test_isinstance_shortcut():
+    from pypy.objspace.std import objspace
+    space = objspace.StdObjSpace()
+    w_a = space.wrap("a")
+    space.type = None
+    space.isinstance_w(w_a, space.w_str) # does not crash
+
diff --git a/pypy/objspace/std/test/test_sliceobject.py b/pypy/objspace/std/test/test_sliceobject.py
--- a/pypy/objspace/std/test/test_sliceobject.py
+++ b/pypy/objspace/std/test/test_sliceobject.py
@@ -42,6 +42,23 @@
                             getslice(length, mystart, mystop))
 
 
+    def test_indexes4(self):
+        space = self.space
+        w = space.wrap
+
+        def getslice(length, start, stop, step):
+            return [i for i in range(0, length, step) if start <= i < stop]
+
+        for step in [-5, -4, -3, -2, -1, 1, 2, 3, 4, 5, None]:
+            for length in range(5):
+                for start in range(-2*length-2, 2*length+3) + [None]:
+                    for stop in range(-2*length-2, 2*length+3) + [None]:
+                        sl = space.newslice(w(start), w(stop), w(step))
+                        mystart, mystop, mystep, slicelength = sl.indices4(space, length)
+                        assert len(range(length)[start:stop:step]) == slicelength
+                        assert slice(start, stop, step).indices(length) == (
+                                mystart, mystop, mystep)
+
 class AppTest_SliceObject:
     def test_new(self):
         def cmp_slice(sl1, sl2):
diff --git a/pypy/objspace/std/test/test_stdobjspace.py b/pypy/objspace/std/test/test_stdobjspace.py
--- a/pypy/objspace/std/test/test_stdobjspace.py
+++ b/pypy/objspace/std/test/test_stdobjspace.py
@@ -14,11 +14,11 @@
 
     def test_int_w_non_int(self):
         raises(OperationError,self.space.int_w,self.space.wrap(None))
-        raises(OperationError,self.space.int_w,self.space.wrap(""))        
+        raises(OperationError,self.space.int_w,self.space.wrap(""))
 
     def test_uint_w_non_int(self):
         raises(OperationError,self.space.uint_w,self.space.wrap(None))
-        raises(OperationError,self.space.uint_w,self.space.wrap(""))        
+        raises(OperationError,self.space.uint_w,self.space.wrap(""))
 
     def test_multimethods_defined_on(self):
         from pypy.objspace.std.stdtypedef import multimethods_defined_on
@@ -49,14 +49,14 @@
     def test_fastpath_isinstance(self):
         from pypy.objspace.std.stringobject import W_StringObject
         from pypy.objspace.std.intobject import W_IntObject
-        
+
         space = self.space
-        assert space.w_str.interplevel_cls is W_StringObject
-        assert space.w_int.interplevel_cls is W_IntObject
+        assert space._get_interplevel_cls(space.w_str) is W_StringObject
+        assert space._get_interplevel_cls(space.w_int) is W_IntObject
         class X(W_StringObject):
             def __init__(self):
                 pass
-            
+
             typedef = None
 
         assert space.isinstance_w(X(), space.w_str)
diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py
--- a/pypy/objspace/std/tupleobject.py
+++ b/pypy/objspace/std/tupleobject.py
@@ -103,15 +103,10 @@
             return space.w_False
     return space.w_True
 
-def _min(a, b):
-    if a < b:
-        return a
-    return b
-
 def lt__Tuple_Tuple(space, w_tuple1, w_tuple2):
     items1 = w_tuple1.wrappeditems
     items2 = w_tuple2.wrappeditems
-    ncmp = _min(len(items1), len(items2))
+    ncmp = min(len(items1), len(items2))
     # Search for the first index where items are different
     for p in range(ncmp):
         if not space.eq_w(items1[p], items2[p]):
@@ -122,7 +117,7 @@
 def gt__Tuple_Tuple(space, w_tuple1, w_tuple2):
     items1 = w_tuple1.wrappeditems
     items2 = w_tuple2.wrappeditems
-    ncmp = _min(len(items1), len(items2))
+    ncmp = min(len(items1), len(items2))
     # Search for the first index where items are different
     for p in range(ncmp):
         if not space.eq_w(items1[p], items2[p]):
@@ -167,17 +162,8 @@
     return space.wrap(count)
 
 def tuple_index__Tuple_ANY_ANY_ANY(space, w_tuple, w_obj, w_start, w_stop):
-    start = slicetype.eval_slice_index(space, w_start)
-    stop = slicetype.eval_slice_index(space, w_stop)
     length = len(w_tuple.wrappeditems)
-    if start < 0:
-        start += length
-        if start < 0:
-            start = 0
-    if stop < 0:
-        stop += length
-        if stop < 0:
-            stop = 0
+    start, stop = slicetype.unwrap_start_stop(space, length, w_start, w_stop)
     for i in range(start, min(stop, length)):
         w_item = w_tuple.wrappeditems[i]
         if space.eq_w(w_item, w_obj):
diff --git a/pypy/objspace/std/tupletype.py b/pypy/objspace/std/tupletype.py
--- a/pypy/objspace/std/tupletype.py
+++ b/pypy/objspace/std/tupletype.py
@@ -5,14 +5,14 @@
 
 def wraptuple(space, list_w):
     from pypy.objspace.std.tupleobject import W_TupleObject
-    from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2
-    from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3
-    from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4
-    from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5
-    from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6
-    from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7
-    from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8
     if space.config.objspace.std.withsmalltuple:
+        from pypy.objspace.std.smalltupleobject import W_SmallTupleObject2
+        from pypy.objspace.std.smalltupleobject import W_SmallTupleObject3
+        from pypy.objspace.std.smalltupleobject import W_SmallTupleObject4
+        from pypy.objspace.std.smalltupleobject import W_SmallTupleObject5
+        from pypy.objspace.std.smalltupleobject import W_SmallTupleObject6
+        from pypy.objspace.std.smalltupleobject import W_SmallTupleObject7
+        from pypy.objspace.std.smalltupleobject import W_SmallTupleObject8
         if len(list_w) == 2:
             return W_SmallTupleObject2(list_w)
         if len(list_w) == 3:
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
@@ -102,7 +102,6 @@
                           'instancetypedef',
                           'terminator',
                           '_version_tag?',
-                          'interplevel_cls',
                           ]
 
     # for config.objspace.std.getattributeshortcut
@@ -117,9 +116,6 @@
     # of the __new__ is an instance of the type
     w_bltin_new = None
 
-    interplevel_cls = None # not None for prebuilt instances of
-                           # interpreter-level types
-
     @dont_look_inside
     def __init__(w_self, space, name, bases_w, dict_w,
                  overridetypedef=None):
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
@@ -9,7 +9,7 @@
 from pypy.objspace.std import slicetype, newformat
 from pypy.objspace.std.tupleobject import W_TupleObject
 from pypy.rlib.rarithmetic import intmask, ovfcheck
-from pypy.rlib.objectmodel import compute_hash
+from pypy.rlib.objectmodel import compute_hash, specialize
 from pypy.rlib.rstring import UnicodeBuilder
 from pypy.rlib.runicode import unicode_encode_unicode_escape
 from pypy.module.unicodedata import unicodedb
@@ -370,42 +370,29 @@
         index = length
     return index
 
-def _convert_idx_params(space, w_self, w_sub, w_start, w_end, upper_bound=False):
-    assert isinstance(w_sub, W_UnicodeObject)
+ at specialize.arg(4)
+def _convert_idx_params(space, w_self, w_start, w_end, upper_bound=False):
     self = w_self._value
-    sub = w_sub._value
-
-    if space.is_w(w_start, space.w_None):
-        w_start = space.wrap(0)
-    if space.is_w(w_end, space.w_None):
-        w_end = space.len(w_self)
-
-    if upper_bound:
-        start = slicetype.adapt_bound(space, len(self), w_start)
-        end = slicetype.adapt_bound(space, len(self), w_end)
-    else:
-        start = slicetype.adapt_lower_bound(space, len(self), w_start)
-        end = slicetype.adapt_lower_bound(space, len(self), w_end)
-    return (self, sub, start, end)
-_convert_idx_params._annspecialcase_ = 'specialize:arg(5)'
+    start, end = slicetype.unwrap_start_stop(
+            space, len(self), w_start, w_end, upper_bound)
+    return (self, start, end)
 
 def unicode_endswith__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end):
-    self, substr, start, end = _convert_idx_params(space, w_self, w_substr,
+    self, start, end = _convert_idx_params(space, w_self,
                                                    w_start, w_end, True)
-    return space.newbool(stringendswith(self, substr, start, end))
+    return space.newbool(stringendswith(self, w_substr._value, start, end))
 
 def unicode_startswith__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end):
-    self, substr, start, end = _convert_idx_params(space, w_self, w_substr,
-                                                   w_start, w_end, True)
+    self, start, end = _convert_idx_params(space, w_self, w_start, w_end, True)
     # XXX this stuff can be waaay better for ootypebased backends if
     #     we re-use more of our rpython machinery (ie implement startswith
     #     with additional parameters as rpython)
-    return space.newbool(stringstartswith(self, substr, start, end))
+    return space.newbool(stringstartswith(self, w_substr._value, start, end))
 
 def unicode_startswith__Unicode_Tuple_ANY_ANY(space, w_unistr, w_prefixes,
                                               w_start, w_end):
-    unistr, _, start, end = _convert_idx_params(space, w_unistr, space.wrap(u''),
-                                                w_start, w_end, True)
+    unistr, start, end = _convert_idx_params(space, w_unistr,
+                                             w_start, w_end, True)
     for w_prefix in space.fixedview(w_prefixes):
         prefix = space.unicode_w(w_prefix)
         if stringstartswith(unistr, prefix, start, end):
@@ -414,7 +401,7 @@
 
 def unicode_endswith__Unicode_Tuple_ANY_ANY(space, w_unistr, w_suffixes,
                                             w_start, w_end):
-    unistr, _, start, end = _convert_idx_params(space, w_unistr, space.wrap(u''),
+    unistr, start, end = _convert_idx_params(space, w_unistr,
                                              w_start, w_end, True)
     for w_suffix in space.fixedview(w_suffixes):
         suffix = space.unicode_w(w_suffix)
@@ -520,37 +507,32 @@
     return space.newlist(lines)
 
 def unicode_find__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end):
-    self, substr, start, end = _convert_idx_params(space, w_self, w_substr,
-                                                   w_start, w_end)
-    return space.wrap(self.find(substr, start, end))
+    self, start, end = _convert_idx_params(space, w_self, w_start, w_end)
+    return space.wrap(self.find(w_substr._value, start, end))
 
 def unicode_rfind__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end):
-    self, substr, start, end = _convert_idx_params(space, w_self, w_substr,
-                                                   w_start, w_end)
-    return space.wrap(self.rfind(substr, start, end))
+    self, start, end = _convert_idx_params(space, w_self, w_start, w_end)
+    return space.wrap(self.rfind(w_substr._value, start, end))
 
 def unicode_index__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end):
-    self, substr, start, end = _convert_idx_params(space, w_self, w_substr,
-                                                   w_start, w_end)
-    index = self.find(substr, start, end)
+    self, start, end = _convert_idx_params(space, w_self, w_start, w_end)
+    index = self.find(w_substr._value, start, end)
     if index < 0:
         raise OperationError(space.w_ValueError,
                              space.wrap('substring not found'))
     return space.wrap(index)
 
 def unicode_rindex__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end):
-    self, substr, start, end = _convert_idx_params(space, w_self, w_substr,
-                                           w_start, w_end)
-    index = self.rfind(substr, start, end)
+    self, start, end = _convert_idx_params(space, w_self, w_start, w_end)
+    index = self.rfind(w_substr._value, start, end)
     if index < 0:
         raise OperationError(space.w_ValueError,
                              space.wrap('substring not found'))
     return space.wrap(index)
 
 def unicode_count__Unicode_Unicode_ANY_ANY(space, w_self, w_substr, w_start, w_end):
-    self, substr, start, end = _convert_idx_params(space, w_self, w_substr,
-                                                   w_start, w_end)
-    return space.wrap(self.count(substr, start, end))
+    self, start, end = _convert_idx_params(space, w_self, w_start, w_end)
+    return space.wrap(self.count(w_substr._value, start, end))
 
 def unicode_split__Unicode_None_ANY(space, w_self, w_none, w_maxsplit):
     maxsplit = space.int_w(w_maxsplit)
diff --git a/pypy/pytest.ini b/pypy/pytest.ini
--- a/pypy/pytest.ini
+++ b/pypy/pytest.ini
@@ -1,2 +1,2 @@
 [pytest]
-addopts = --assertmode=old
\ No newline at end of file
+addopts = --assertmode=old -rf
diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -939,7 +939,7 @@
     ah, al = _kmul_split(a, shift)
     assert ah.sign == 1    # the split isn't degenerate
 
-    if a == b:
+    if a is b:
         bh = ah
         bl = al
     else:
@@ -993,26 +993,21 @@
     i = ret.numdigits() - shift  # # digits after shift
     _v_isub(ret, shift, i, t2, t2.numdigits())
     _v_isub(ret, shift, i, t1, t1.numdigits())
-    del t1, t2
 
     # 6. t3 <- (ah+al)(bh+bl), and add into result.
     t1 = _x_add(ah, al)
-    del ah, al
 
-    if a == b:
+    if a is b:
         t2 = t1
     else:
         t2 = _x_add(bh, bl)
-    del bh, bl
 
     t3 = _k_mul(t1, t2)
-    del t1, t2
     assert t3.sign >=0
 
     # Add t3.  It's not obvious why we can't run out of room here.
     # See the (*) comment after this function.
     _v_iadd(ret, shift, i, t3, t3.numdigits())
-    del t3
 
     ret._normalize()
     return ret
@@ -1103,7 +1098,6 @@
         # Add into result.
         _v_iadd(ret, nbdone, ret.numdigits() - nbdone,
                  product, product.numdigits())
-        del product
 
         bsize -= nbtouse
         nbdone += nbtouse
diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py
--- a/pypy/rlib/rgc.py
+++ b/pypy/rlib/rgc.py
@@ -214,6 +214,10 @@
     func._gc_no_collect_ = True
     return func
 
+def is_light_finalizer(func):
+    func._is_light_finalizer_ = True
+    return func
+
 # ____________________________________________________________
 
 def get_rpy_roots():
@@ -255,6 +259,24 @@
     except Exception:
         return False      # don't keep objects whose _freeze_() method explodes
 
+def add_memory_pressure(estimate):
+    """Add memory pressure for OpaquePtrs."""
+    pass
+
+class AddMemoryPressureEntry(ExtRegistryEntry):
+    _about_ = add_memory_pressure
+
+    def compute_result_annotation(self, s_nbytes):
+        from pypy.annotation import model as annmodel
+        return annmodel.s_None
+
+    def specialize_call(self, hop):
+        [v_size] = hop.inputargs(lltype.Signed)
+        hop.exception_cannot_occur()
+        return hop.genop('gc_add_memory_pressure', [v_size],
+                         resulttype=lltype.Void)
+
+
 def get_rpy_memory_usage(gcref):
     "NOT_RPYTHON"
     # approximate implementation using CPython's type info
diff --git a/pypy/rlib/rmmap.py b/pypy/rlib/rmmap.py
--- a/pypy/rlib/rmmap.py
+++ b/pypy/rlib/rmmap.py
@@ -78,7 +78,7 @@
     from pypy.rlib.rwin32 import HANDLE, LPHANDLE
     from pypy.rlib.rwin32 import NULL_HANDLE, INVALID_HANDLE_VALUE
     from pypy.rlib.rwin32 import DWORD, WORD, DWORD_PTR, LPDWORD
-    from pypy.rlib.rwin32 import BOOL, LPVOID, LPCVOID, LPCSTR, SIZE_T
+    from pypy.rlib.rwin32 import BOOL, LPVOID, LPCSTR, SIZE_T
     from pypy.rlib.rwin32 import INT, LONG, PLONG
 
 # export the constants inside and outside. see __init__.py
@@ -174,9 +174,9 @@
     DuplicateHandle = winexternal('DuplicateHandle', [HANDLE, HANDLE, HANDLE, LPHANDLE, DWORD, BOOL, DWORD], BOOL)
     CreateFileMapping = winexternal('CreateFileMappingA', [HANDLE, rwin32.LPSECURITY_ATTRIBUTES, DWORD, DWORD, DWORD, LPCSTR], HANDLE)
     MapViewOfFile = winexternal('MapViewOfFile', [HANDLE, DWORD, DWORD, DWORD, SIZE_T], LPCSTR)##!!LPVOID)
-    UnmapViewOfFile = winexternal('UnmapViewOfFile', [LPCVOID], BOOL,
+    UnmapViewOfFile = winexternal('UnmapViewOfFile', [LPCSTR], BOOL,
                                   threadsafe=False)
-    FlushViewOfFile = winexternal('FlushViewOfFile', [LPCVOID, SIZE_T], BOOL)
+    FlushViewOfFile = winexternal('FlushViewOfFile', [LPCSTR, SIZE_T], BOOL)
     SetFilePointer = winexternal('SetFilePointer', [HANDLE, LONG, PLONG, DWORD], DWORD)
     SetEndOfFile = winexternal('SetEndOfFile', [HANDLE], BOOL)
     VirtualAlloc = winexternal('VirtualAlloc',
@@ -292,6 +292,9 @@
         elif _POSIX:
             self.closed = True
             if self.fd != -1:
+                # XXX this is buggy - raising in an RPython del is not a good
+                #     idea, we should swallow the exception or ignore the
+                #     underlaying close error code
                 os.close(self.fd)
                 self.fd = -1
             if self.size > 0:
diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py
--- a/pypy/rlib/ropenssl.py
+++ b/pypy/rlib/ropenssl.py
@@ -25,6 +25,7 @@
     'openssl/err.h',
     'openssl/rand.h',
     'openssl/evp.h',
+    'openssl/ossl_typ.h',
     'openssl/x509v3.h']
 
 eci = ExternalCompilationInfo(
@@ -111,7 +112,9 @@
     GENERAL_NAME_st = rffi_platform.Struct(
         'struct GENERAL_NAME_st',
         [('type', rffi.INT),
-         ]) 
+         ])
+    EVP_MD_SIZE = rffi_platform.SizeOf('EVP_MD')
+    EVP_MD_CTX_SIZE = rffi_platform.SizeOf('EVP_MD_CTX')
 
     OBJ_NAME_st = rffi_platform.Struct(
         'OBJ_NAME',
@@ -164,7 +167,7 @@
 ssl_external('CRYPTO_set_id_callback',
              [lltype.Ptr(lltype.FuncType([], rffi.LONG))],
              lltype.Void)
-             
+
 if HAVE_OPENSSL_RAND:
     ssl_external('RAND_add', [rffi.CCHARP, rffi.INT, rffi.DOUBLE], lltype.Void)
     ssl_external('RAND_status', [], rffi.INT)
@@ -265,7 +268,7 @@
              [BIO, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP], X509)
 
 EVP_MD_CTX = rffi.COpaquePtr('EVP_MD_CTX', compilation_info=eci)
-EVP_MD     = rffi.COpaquePtr('EVP_MD')
+EVP_MD     = rffi.COpaquePtr('EVP_MD', compilation_info=eci)
 
 OpenSSL_add_all_digests = external(
     'OpenSSL_add_all_digests', [], lltype.Void)
diff --git a/pypy/rlib/rsocket.py b/pypy/rlib/rsocket.py
--- a/pypy/rlib/rsocket.py
+++ b/pypy/rlib/rsocket.py
@@ -56,6 +56,7 @@
 
 
 _FAMILIES = {}
+
 class Address(object):
     """The base class for RPython-level objects representing addresses.
     Fields:  addr    - a _c.sockaddr_ptr (memory owned by the Address instance)
@@ -77,9 +78,8 @@
         self.addrlen = addrlen
 
     def __del__(self):
-        addr = self.addr_p
-        if addr:
-            lltype.free(addr, flavor='raw')
+        if self.addr_p:
+            lltype.free(self.addr_p, flavor='raw')
 
     def setdata(self, addr, addrlen):
         # initialize self.addr and self.addrlen.  'addr' can be a different
@@ -615,7 +615,10 @@
         self.timeout = defaults.timeout
         
     def __del__(self):
-        self.close()
+        fd = self.fd
+        if fd != _c.INVALID_SOCKET:
+            self.fd = _c.INVALID_SOCKET
+            _c.socketclose(fd)
 
     if hasattr(_c, 'fcntl'):
         def _setblocking(self, block):
diff --git a/pypy/rlib/rsre/rsre_core.py b/pypy/rlib/rsre/rsre_core.py
--- a/pypy/rlib/rsre/rsre_core.py
+++ b/pypy/rlib/rsre/rsre_core.py
@@ -391,6 +391,8 @@
             if self.num_pending >= min:
                 while enum is not None and ptr == ctx.match_end:
                     enum = enum.move_to_next_result(ctx)
+                    # matched marks for zero-width assertions
+                    marks = ctx.match_marks
             #
             if enum is not None:
                 # matched one more 'item'.  record it and continue.
diff --git a/pypy/rlib/rsre/test/test_re.py b/pypy/rlib/rsre/test/test_re.py
--- a/pypy/rlib/rsre/test/test_re.py
+++ b/pypy/rlib/rsre/test/test_re.py
@@ -226,6 +226,13 @@
                          (None, 'b', None))
         assert pat.match('ac').group(1, 'b2', 3) == ('a', None, 'c')
 
+    def test_bug_923(self):
+        # Issue923: grouping inside optional lookahead problem
+        assert re.match(r'a(?=(b))?', "ab").groups() == ("b",)
+        assert re.match(r'(a(?=(b))?)', "ab").groups() == ('a', 'b')
+        assert re.match(r'(a)(?=(b))?', "ab").groups() == ('a', 'b')
+        assert re.match(r'(?P<g1>a)(?=(?P<g2>b))?', "ab").groupdict() == {'g1': 'a', 'g2': 'b'}
+
     def test_re_groupref_exists(self):
         assert re.match('^(\()?([^()]+)(?(1)\))$', '(a)').groups() == (
                          ('(', 'a'))
diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py
--- a/pypy/rpython/llinterp.py
+++ b/pypy/rpython/llinterp.py
@@ -172,7 +172,7 @@
 
 def checkadr(addr):
     assert lltype.typeOf(addr) is llmemory.Address
-    
+
 def is_inst(inst):
     return isinstance(lltype.typeOf(inst), (ootype.Instance, ootype.BuiltinType, ootype.StaticMethod))
 
@@ -657,7 +657,7 @@
                 raise TypeError("graph with %r args called with wrong func ptr type: %r" %
                                 (tuple([v.concretetype for v in args_v]), ARGS)) 
         frame = self.newsubframe(graph, args)
-        return frame.eval()        
+        return frame.eval()
 
     def op_direct_call(self, f, *args):
         FTYPE = self.llinterpreter.typer.type_system.derefType(lltype.typeOf(f))
@@ -698,13 +698,13 @@
             return ptr
         except MemoryError:
             self.make_llexception()
-            
+
     def op_malloc_nonmovable(self, TYPE, flags):
         flavor = flags['flavor']
         assert flavor == 'gc'
         zero = flags.get('zero', False)
         return self.heap.malloc_nonmovable(TYPE, zero=zero)
-        
+
     def op_malloc_nonmovable_varsize(self, TYPE, flags, size):
         flavor = flags['flavor']
         assert flavor == 'gc'
@@ -716,6 +716,9 @@
         track_allocation = flags.get('track_allocation', True)
         self.heap.free(obj, flavor='raw', track_allocation=track_allocation)
 
+    def op_gc_add_memory_pressure(self, size):
+        self.heap.add_memory_pressure(size)
+
     def op_shrink_array(self, obj, smallersize):
         return self.heap.shrink_array(obj, smallersize)
 
@@ -1095,13 +1098,6 @@
             assert y >= 0
         return self.op_int_add_ovf(x, y)
 
-    def op_cast_float_to_int(self, f):
-        assert type(f) is float
-        try:
-            return ovfcheck(int(f))
-        except OverflowError:
-            self.make_llexception()
-
     def op_int_is_true(self, x):
         # special case
         if type(x) is CDefinedIntSymbolic:
@@ -1325,7 +1321,7 @@
         func_graph = fn.graph
     else:
         # obj is an instance, we want to call 'method_name' on it
-        assert fn is None        
+        assert fn is None
         self_arg = [obj]
         func_graph = obj._TYPE._methods[method_name._str].graph
 
diff --git a/pypy/rpython/lltypesystem/llheap.py b/pypy/rpython/lltypesystem/llheap.py
--- a/pypy/rpython/lltypesystem/llheap.py
+++ b/pypy/rpython/lltypesystem/llheap.py
@@ -5,8 +5,7 @@
 
 setfield = setattr
 from operator import setitem as setarrayitem
-from pypy.rlib.rgc import collect
-from pypy.rlib.rgc import can_move
+from pypy.rlib.rgc import can_move, collect, add_memory_pressure
 
 def setinterior(toplevelcontainer, inneraddr, INNERTYPE, newvalue,
                 offsets=None):
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
@@ -343,8 +343,8 @@
     'cast_uint_to_float':   LLOp(canfold=True),
     'cast_longlong_to_float' :LLOp(canfold=True),
     'cast_ulonglong_to_float':LLOp(canfold=True),
-    'cast_float_to_int':    LLOp(canraise=(OverflowError,), tryfold=True),
-    'cast_float_to_uint':   LLOp(canfold=True),    # XXX need OverflowError?
+    'cast_float_to_int':    LLOp(canfold=True),
+    'cast_float_to_uint':   LLOp(canfold=True),
     'cast_float_to_longlong' :LLOp(canfold=True),
     'cast_float_to_ulonglong':LLOp(canfold=True),
     'truncate_longlong_to_int':LLOp(canfold=True),
@@ -473,6 +473,7 @@
     'gc_is_rpy_instance'  : LLOp(),
     'gc_dump_rpy_heap'    : LLOp(),
     'gc_typeids_z'        : LLOp(),
+    'gc_add_memory_pressure': LLOp(),
 
     # ------- JIT & GC interaction, only for some GCs ----------
 
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
@@ -48,7 +48,7 @@
         self.TYPE = TYPE
     def __repr__(self):
         return '<Uninitialized %r>'%(self.TYPE,)
-        
+
 
 def saferecursive(func, defl, TLS=TLS):
     def safe(*args):
@@ -537,9 +537,9 @@
         return "Func ( %s ) -> %s" % (args, self.RESULT)
     __str__ = saferecursive(__str__, '...')
 
-    def _short_name(self):        
+    def _short_name(self):
         args = ', '.join([ARG._short_name() for ARG in self.ARGS])
-        return "Func(%s)->%s" % (args, self.RESULT._short_name())        
+        return "Func(%s)->%s" % (args, self.RESULT._short_name())
     _short_name = saferecursive(_short_name, '...')
 
     def _container_example(self):
@@ -553,7 +553,7 @@
 
 class OpaqueType(ContainerType):
     _gckind = 'raw'
-    
+
     def __init__(self, tag, hints={}):
         """ if hints['render_structure'] is set, the type is internal and not considered
             to come from somewhere else (it should be rendered as a structure) """
@@ -723,10 +723,10 @@
 
     def __str__(self):
         return '* %s' % (self.TO, )
-    
+
     def _short_name(self):
         return 'Ptr %s' % (self.TO._short_name(), )
-    
+
     def _is_atomic(self):
         return self.TO._gckind == 'raw'
 
@@ -1713,6 +1713,7 @@
         return v
 
     def setitem(self, index, value):
+        assert typeOf(value) == self._TYPE.OF
         self.items[index] = value
 
 assert not '__dict__' in dir(_array)
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
@@ -355,6 +355,10 @@
     assert type(b) is bool
     return float(b)
 
+def op_cast_float_to_int(f):
+    assert type(f) is float
+    return intmask(int(f))
+
 def op_cast_float_to_uint(f):
     assert type(f) is float
     return r_uint(long(f))
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
@@ -452,9 +452,9 @@
     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.
- at jit.dont_look_inside
+# It may be safe to look inside always, it has a few branches though, and their
+# frequencies needs to be investigated.
+ at jit.look_inside_iff(lambda d, key, value, hash, i: jit.isvirtual(d) and jit.isconstant(key))
 def _ll_dict_setitem_lookup_done(d, key, value, hash, i):
     valid = (i & HIGHEST_BIT) == 0
     i = i & MASK
@@ -508,8 +508,8 @@
         return default
 
 # XXX: Move the size checking and resize into a single call which is opauqe to
-# the JIT to avoid extra branches.
- at jit.dont_look_inside
+# the JIT when the dict isn't virtual, to avoid extra branches.
+ at jit.look_inside_iff(lambda d, i: jit.isvirtual(d) and jit.isconstant(i))
 def _ll_dict_del(d, i):
     d.entries.mark_deleted(i)
     d.num_items -= 1
@@ -549,7 +549,7 @@
 # ------- a port of CPython's dictobject.c's lookdict implementation -------
 PERTURB_SHIFT = 5
 
- at jit.dont_look_inside
+ at jit.look_inside_iff(lambda d, key, hash: jit.isvirtual(d) and jit.isconstant(key))
 def ll_dict_lookup(d, key, hash):
     entries = d.entries
     ENTRIES = lltype.typeOf(entries).TO
diff --git a/pypy/rpython/lltypesystem/rpbc.py b/pypy/rpython/lltypesystem/rpbc.py
--- a/pypy/rpython/lltypesystem/rpbc.py
+++ b/pypy/rpython/lltypesystem/rpbc.py
@@ -116,7 +116,7 @@
             fields.append((row.attrname, row.fntype))
         kwds = {'hints': {'immutable': True}}
         return Ptr(Struct('specfunc', *fields, **kwds))
-        
+
     def create_specfunc(self):
         return malloc(self.lowleveltype.TO, immortal=True)
 
@@ -149,7 +149,8 @@
         self.descriptions = list(self.s_pbc.descriptions)
         if self.s_pbc.can_be_None:
             self.descriptions.insert(0, None)
-        POINTER_TABLE = Array(self.pointer_repr.lowleveltype)
+        POINTER_TABLE = Array(self.pointer_repr.lowleveltype,
+                              hints={'nolength': True})
         pointer_table = malloc(POINTER_TABLE, len(self.descriptions),
                                immortal=True)
         for i, desc in enumerate(self.descriptions):
@@ -302,7 +303,8 @@
     if r_to in r_from._conversion_tables:
         return r_from._conversion_tables[r_to]
     else:
-        t = malloc(Array(Char), len(r_from.descriptions), immortal=True)
+        t = malloc(Array(Char, hints={'nolength': True}),
+                   len(r_from.descriptions), immortal=True)
         l = []
         for i, d in enumerate(r_from.descriptions):
             if d in r_to.descriptions:
@@ -314,7 +316,7 @@
         if l == range(len(r_from.descriptions)):
             r = None
         else:
-            r = inputconst(Ptr(Array(Char)), t)
+            r = inputconst(Ptr(Array(Char, hints={'nolength': True})), t)
         r_from._conversion_tables[r_to] = r
         return r
 
@@ -402,12 +404,12 @@
 
 # ____________________________________________________________
 
-##def rtype_call_memo(hop): 
+##def rtype_call_memo(hop):
 ##    memo_table = hop.args_v[0].value
 ##    if memo_table.s_result.is_constant():
 ##        return hop.inputconst(hop.r_result, memo_table.s_result.const)
-##    fieldname = memo_table.fieldname 
-##    assert hop.nb_args == 2, "XXX"  
+##    fieldname = memo_table.fieldname
+##    assert hop.nb_args == 2, "XXX"
 
 ##    r_pbc = hop.args_r[1]
 ##    assert isinstance(r_pbc, (MultipleFrozenPBCRepr, ClassesPBCRepr))
diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py
--- a/pypy/rpython/lltypesystem/rstr.py
+++ b/pypy/rpython/lltypesystem/rstr.py
@@ -20,6 +20,7 @@
 from pypy.rpython.rmodel import Repr
 from pypy.rpython.lltypesystem import llmemory
 from pypy.tool.sourcetools import func_with_new_name
+from pypy.rpython.lltypesystem.lloperation import llop
 
 # ____________________________________________________________
 #
@@ -364,8 +365,10 @@
             while lpos < rpos and s.chars[lpos] == ch:
                 lpos += 1
         if right:
-            while lpos < rpos and s.chars[rpos] == ch:
+            while lpos < rpos + 1 and s.chars[rpos] == ch:
                 rpos -= 1
+        if rpos < lpos:
+            return s.empty()
         r_len = rpos - lpos + 1
         result = s.malloc(r_len)
         s.copy_contents(s, result, lpos, 0, r_len)
diff --git a/pypy/rpython/memory/gc/base.py b/pypy/rpython/memory/gc/base.py
--- a/pypy/rpython/memory/gc/base.py
+++ b/pypy/rpython/memory/gc/base.py
@@ -1,4 +1,5 @@
-from pypy.rpython.lltypesystem import lltype, llmemory, llarena
+from pypy.rpython.lltypesystem import lltype, llmemory, llarena, rffi
+from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rlib.debug import ll_assert
 from pypy.rpython.memory.gcheader import GCHeaderBuilder
 from pypy.rpython.memory.support import DEFAULT_CHUNK_SIZE
@@ -62,6 +63,7 @@
     def set_query_functions(self, is_varsize, has_gcptr_in_varsize,
                             is_gcarrayofgcptr,
                             getfinalizer,
+                            getlightfinalizer,
                             offsets_to_gc_pointers,
                             fixed_size, varsize_item_sizes,
                             varsize_offset_to_variable_part,
@@ -74,6 +76,7 @@
                             get_custom_trace,
                             fast_path_tracing):
         self.getfinalizer = getfinalizer
+        self.getlightfinalizer = getlightfinalizer
         self.is_varsize = is_varsize
         self.has_gcptr_in_varsize = has_gcptr_in_varsize
         self.is_gcarrayofgcptr = is_gcarrayofgcptr
@@ -139,6 +142,7 @@
 
         size = self.fixed_size(typeid)
         needs_finalizer = bool(self.getfinalizer(typeid))
+        finalizer_is_light = bool(self.getlightfinalizer(typeid))
         contains_weakptr = self.weakpointer_offset(typeid) >= 0
         assert not (needs_finalizer and contains_weakptr)
         if self.is_varsize(typeid):
@@ -158,6 +162,7 @@
             else:
                 malloc_fixedsize = self.malloc_fixedsize
             ref = malloc_fixedsize(typeid, size, needs_finalizer,
+                                   finalizer_is_light,
                                    contains_weakptr)
         # lots of cast and reverse-cast around...
         return llmemory.cast_ptr_to_adr(ref)
diff --git a/pypy/rpython/memory/gc/generation.py b/pypy/rpython/memory/gc/generation.py
--- a/pypy/rpython/memory/gc/generation.py
+++ b/pypy/rpython/memory/gc/generation.py
@@ -167,7 +167,9 @@
         return self.nursery <= addr < self.nursery_top
 
     def malloc_fixedsize_clear(self, typeid, size,
-                               has_finalizer=False, contains_weakptr=False):
+                               has_finalizer=False,
+                               is_finalizer_light=False,
+                               contains_weakptr=False):
         if (has_finalizer or
             (raw_malloc_usage(size) > self.lb_young_fixedsize and
              raw_malloc_usage(size) > self.largest_young_fixedsize)):
@@ -179,6 +181,7 @@
             # "non-simple" case or object too big: don't use the nursery
             return SemiSpaceGC.malloc_fixedsize_clear(self, typeid, size,
                                                       has_finalizer,
+                                                      is_finalizer_light,
                                                       contains_weakptr)
         size_gc_header = self.gcheaderbuilder.size_gc_header
         totalsize = size_gc_header + size
diff --git a/pypy/rpython/memory/gc/marksweep.py b/pypy/rpython/memory/gc/marksweep.py
--- a/pypy/rpython/memory/gc/marksweep.py
+++ b/pypy/rpython/memory/gc/marksweep.py
@@ -93,7 +93,8 @@
         pass
 
     def malloc_fixedsize(self, typeid16, size,
-                         has_finalizer=False, contains_weakptr=False):
+                         has_finalizer=False, is_finalizer_light=False,
+                         contains_weakptr=False):
         self.maybe_collect()
         size_gc_header = self.gcheaderbuilder.size_gc_header
         try:
@@ -128,7 +129,9 @@
     malloc_fixedsize._dont_inline_ = True
 
     def malloc_fixedsize_clear(self, typeid16, size,
-                               has_finalizer=False, contains_weakptr=False):
+                               has_finalizer=False,
+                               is_finalizer_light=False,
+                               contains_weakptr=False):
         self.maybe_collect()
         size_gc_header = self.gcheaderbuilder.size_gc_header
         try:
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
@@ -290,6 +290,8 @@
         #
         # A list of all objects with finalizers (these are never young).
         self.objects_with_finalizers = self.AddressDeque()
+        self.young_objects_with_light_finalizers = self.AddressStack()
+        self.old_objects_with_light_finalizers = self.AddressStack()
         #
         # Two lists of the objects with weakrefs.  No weakref can be an
         # old object weakly pointing to a young object: indeed, weakrefs
@@ -457,14 +459,16 @@
 
 
     def malloc_fixedsize_clear(self, typeid, size,
-                               needs_finalizer=False, contains_weakptr=False):
+                               needs_finalizer=False,
+                               is_finalizer_light=False,
+                               contains_weakptr=False):
         size_gc_header = self.gcheaderbuilder.size_gc_header
         totalsize = size_gc_header + size
         rawtotalsize = raw_malloc_usage(totalsize)
         #
         # If the object needs a finalizer, ask for a rawmalloc.
         # The following check should be constant-folded.
-        if needs_finalizer:
+        if needs_finalizer and not is_finalizer_light:
             ll_assert(not contains_weakptr,
                      "'needs_finalizer' and 'contains_weakptr' both specified")
             obj = self.external_malloc(typeid, 0, can_make_young=False)
@@ -494,13 +498,14 @@
             #
             # Build the object.
             llarena.arena_reserve(result, totalsize)
+            obj = result + size_gc_header
+            if is_finalizer_light:
+                self.young_objects_with_light_finalizers.append(obj)
             self.init_gc_object(result, typeid, flags=0)
             #
             # If it is a weakref, record it (check constant-folded).
             if contains_weakptr:
-                self.young_objects_with_weakrefs.append(result+size_gc_header)
-            #
-            obj = result + size_gc_header
+                self.young_objects_with_weakrefs.append(obj)
         #
         return llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
 
@@ -1264,6 +1269,8 @@
         # weakrefs' targets.
         if self.young_objects_with_weakrefs.non_empty():
             self.invalidate_young_weakrefs()
+        if self.young_objects_with_light_finalizers.non_empty():
+            self.deal_with_young_objects_with_finalizers()
         #
         # Clear this mapping.
         if self.nursery_objects_shadows.length() > 0:
@@ -1584,6 +1591,9 @@
         # Weakref support: clear the weak pointers to dying objects
         if self.old_objects_with_weakrefs.non_empty():
             self.invalidate_old_weakrefs()
+        if self.old_objects_with_light_finalizers.non_empty():
+            self.deal_with_old_objects_with_finalizers()
+
         #
         # Walk all rawmalloced objects and free the ones that don't
         # have the GCFLAG_VISITED flag.
@@ -1649,8 +1659,7 @@
         if self.header(obj).tid & GCFLAG_VISITED:
             self.header(obj).tid &= ~GCFLAG_VISITED
             return False     # survives
-        else:
-            return True      # dies
+        return True      # dies
 
     def _reset_gcflag_visited(self, obj, ignored):
         self.header(obj).tid &= ~GCFLAG_VISITED
@@ -1829,6 +1838,42 @@
     # ----------
     # Finalizers
 
+    def deal_with_young_objects_with_finalizers(self):
+        """ This is a much simpler version of dealing with finalizers
+        and an optimization - we can reasonably assume that those finalizers
+        don't do anything fancy and *just* call them. Among other things
+        they won't resurrect objects
+        """
+        while self.young_objects_with_light_finalizers.non_empty():
+            obj = self.young_objects_with_light_finalizers.pop()
+            if not self.is_forwarded(obj):
+                finalizer = self.getlightfinalizer(self.get_type_id(obj))
+                ll_assert(bool(finalizer), "no light finalizer found")
+                finalizer(obj, llmemory.NULL)
+            else:
+                obj = self.get_forwarding_address(obj)
+                self.old_objects_with_light_finalizers.append(obj)
+
+    def deal_with_old_objects_with_finalizers(self):
+        """ This is a much simpler version of dealing with finalizers
+        and an optimization - we can reasonably assume that those finalizers
+        don't do anything fancy and *just* call them. Among other things
+        they won't resurrect objects
+        """
+        new_objects = self.AddressStack()
+        while self.old_objects_with_light_finalizers.non_empty():
+            obj = self.old_objects_with_light_finalizers.pop()
+            if self.header(obj).tid & GCFLAG_VISITED:
+                # surviving
+                new_objects.append(obj)
+            else:
+                # dying
+                finalizer = self.getlightfinalizer(self.get_type_id(obj))
+                ll_assert(bool(finalizer), "no light finalizer found")
+                finalizer(obj, llmemory.NULL)
+        self.old_objects_with_light_finalizers.delete()
+        self.old_objects_with_light_finalizers = new_objects
+
     def deal_with_objects_with_finalizers(self):
         # Walk over list of objects with finalizers.
         # If it is not surviving, add it to the list of to-be-called
@@ -1959,7 +2004,6 @@
             #
             self.old_objects_with_weakrefs.append(obj)
 
-
     def invalidate_old_weakrefs(self):
         """Called during a major collection."""
         # walk over list of objects that contain weakrefs
diff --git a/pypy/rpython/memory/gc/semispace.py b/pypy/rpython/memory/gc/semispace.py
--- a/pypy/rpython/memory/gc/semispace.py
+++ b/pypy/rpython/memory/gc/semispace.py
@@ -82,6 +82,7 @@
         self.free = self.tospace
         MovingGCBase.setup(self)
         self.objects_with_finalizers = self.AddressDeque()
+        self.objects_with_light_finalizers = self.AddressStack()
         self.objects_with_weakrefs = self.AddressStack()
 
     def _teardown(self):
@@ -93,7 +94,9 @@
     # because the spaces are filled with zeroes in advance.
 
     def malloc_fixedsize_clear(self, typeid16, size,
-                               has_finalizer=False, contains_weakptr=False):
+                               has_finalizer=False,
+                               is_finalizer_light=False,
+                               contains_weakptr=False):
         size_gc_header = self.gcheaderbuilder.size_gc_header
         totalsize = size_gc_header + size
         result = self.free
@@ -102,6 +105,9 @@
         llarena.arena_reserve(result, totalsize)
         self.init_gc_object(result, typeid16)
         self.free = result + totalsize
+        #if is_finalizer_light:
+        #    self.objects_with_light_finalizers.append(result + size_gc_header)
+        #else:
         if has_finalizer:
             self.objects_with_finalizers.append(result + size_gc_header)
         if contains_weakptr:
@@ -263,6 +269,8 @@
         if self.run_finalizers.non_empty():
             self.update_run_finalizers()
         scan = self.scan_copied(scan)
+        if self.objects_with_light_finalizers.non_empty():
+            self.deal_with_objects_with_light_finalizers()
         if self.objects_with_finalizers.non_empty():
             scan = self.deal_with_objects_with_finalizers(scan)
         if self.objects_with_weakrefs.non_empty():
@@ -471,6 +479,23 @@
         # immortal objects always have GCFLAG_FORWARDED set;
         # see get_forwarding_address().
 
+    def deal_with_objects_with_light_finalizers(self):
+        """ This is a much simpler version of dealing with finalizers
+        and an optimization - we can reasonably assume that those finalizers
+        don't do anything fancy and *just* call them. Among other things
+        they won't resurrect objects
+        """
+        new_objects = self.AddressStack()
+        while self.objects_with_light_finalizers.non_empty():
+            obj = self.objects_with_light_finalizers.pop()
+            if self.surviving(obj):
+                new_objects.append(self.get_forwarding_address(obj))
+            else:
+                finalizer = self.getfinalizer(self.get_type_id(obj))
+                finalizer(obj, llmemory.NULL)
+        self.objects_with_light_finalizers.delete()
+        self.objects_with_light_finalizers = new_objects
+
     def deal_with_objects_with_finalizers(self, scan):
         # walk over list of objects with finalizers
         # if it is not copied, add it to the list of to-be-called finalizers
diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py
--- a/pypy/rpython/memory/gctransform/framework.py
+++ b/pypy/rpython/memory/gctransform/framework.py
@@ -12,6 +12,7 @@
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.translator.backendopt import graphanalyze
 from pypy.translator.backendopt.support import var_needsgc
+from pypy.translator.backendopt.finalizer import FinalizerAnalyzer
 from pypy.annotation import model as annmodel
 from pypy.rpython import annlowlevel
 from pypy.rpython.rbuiltin import gen_cast
@@ -258,6 +259,7 @@
             [s_gc, s_typeid16,
              annmodel.SomeInteger(nonneg=True),
              annmodel.SomeBool(),
+             annmodel.SomeBool(),
              annmodel.SomeBool()], s_gcref,
             inline = False)
         if hasattr(GCClass, 'malloc_fixedsize'):
@@ -267,6 +269,7 @@
                 [s_gc, s_typeid16,
                  annmodel.SomeInteger(nonneg=True),
                  annmodel.SomeBool(),
+                 annmodel.SomeBool(),
                  annmodel.SomeBool()], s_gcref,
                 inline = False)
         else:
@@ -319,7 +322,7 @@
             raise NotImplementedError("GC needs write barrier, but does not provide writebarrier_before_copy functionality")
 
         # in some GCs we can inline the common case of
-        # malloc_fixedsize(typeid, size, True, False, False)
+        # malloc_fixedsize(typeid, size, False, False, False)
         if getattr(GCClass, 'inline_simple_malloc', False):
             # make a copy of this function so that it gets annotated
             # independently and the constants are folded inside
@@ -337,7 +340,7 @@
                 malloc_fast,
                 [s_gc, s_typeid16,
                  annmodel.SomeInteger(nonneg=True),
-                 s_False, s_False], s_gcref,
+                 s_False, s_False, s_False], s_gcref,
                 inline = True)
         else:
             self.malloc_fast_ptr = None
@@ -374,17 +377,24 @@
             self.malloc_varsize_nonmovable_ptr = None
 
         if getattr(GCClass, 'raw_malloc_memory_pressure', False):
-            def raw_malloc_memory_pressure(length, itemsize):
+            def raw_malloc_memory_pressure_varsize(length, itemsize):
                 totalmem = length * itemsize
                 if totalmem > 0:
                     gcdata.gc.raw_malloc_memory_pressure(totalmem)
                 #else: probably an overflow -- the following rawmalloc
                 #      will fail then
+            def raw_malloc_memory_pressure(sizehint):
+                gcdata.gc.raw_malloc_memory_pressure(sizehint)
+            self.raw_malloc_memory_pressure_varsize_ptr = getfn(
+                raw_malloc_memory_pressure_varsize,
+                [annmodel.SomeInteger(), annmodel.SomeInteger()],
+                annmodel.s_None, minimal_transform = False)
             self.raw_malloc_memory_pressure_ptr = getfn(
                 raw_malloc_memory_pressure,
-                [annmodel.SomeInteger(), annmodel.SomeInteger()],
+                [annmodel.SomeInteger()],
                 annmodel.s_None, minimal_transform = False)
 
+
         self.identityhash_ptr = getfn(GCClass.identityhash.im_func,
                                       [s_gc, s_gcref],
                                       annmodel.SomeInteger(),
@@ -668,7 +678,13 @@
         kind_and_fptr = self.special_funcptr_for_type(TYPE)
         has_finalizer = (kind_and_fptr is not None and
                          kind_and_fptr[0] == "finalizer")
+        has_light_finalizer = (kind_and_fptr is not None and
+                               kind_and_fptr[0] == "light_finalizer")
+        if has_light_finalizer:
+            has_finalizer = True
         c_has_finalizer = rmodel.inputconst(lltype.Bool, has_finalizer)
+        c_has_light_finalizer = rmodel.inputconst(lltype.Bool,
+                                                  has_light_finalizer)
 
         if not op.opname.endswith('_varsize') and not flags.get('varsize'):
             #malloc_ptr = self.malloc_fixedsize_ptr
@@ -682,7 +698,8 @@
             else:
                 malloc_ptr = self.malloc_fixedsize_ptr
             args = [self.c_const_gc, c_type_id, c_size,
-                    c_has_finalizer, rmodel.inputconst(lltype.Bool, False)]
+                    c_has_finalizer, c_has_light_finalizer,
+                    rmodel.inputconst(lltype.Bool, False)]
         else:
             assert not c_has_finalizer.value
             info_varsize = self.layoutbuilder.get_info_varsize(type_id)
@@ -847,12 +864,13 @@
         # used by the JIT (see pypy.jit.backend.llsupport.gc)
         op = hop.spaceop
         [v_typeid, v_size,
-         v_has_finalizer, v_contains_weakptr] = op.args
+         v_has_finalizer, v_has_light_finalizer, v_contains_weakptr] = op.args
         livevars = self.push_roots(hop)
         hop.genop("direct_call",
                   [self.malloc_fixedsize_clear_ptr, self.c_const_gc,
                    v_typeid, v_size,
-                   v_has_finalizer, v_contains_weakptr],
+                   v_has_finalizer, v_has_light_finalizer,
+                   v_contains_weakptr],
                   resultvar=op.result)
         self.pop_roots(hop, livevars)
 
@@ -912,10 +930,10 @@
         info = self.layoutbuilder.get_info(type_id)
         c_size = rmodel.inputconst(lltype.Signed, info.fixedsize)
         malloc_ptr = self.malloc_fixedsize_ptr
-        c_has_finalizer = rmodel.inputconst(lltype.Bool, False)
+        c_false = rmodel.inputconst(lltype.Bool, False)
         c_has_weakptr = rmodel.inputconst(lltype.Bool, True)
         args = [self.c_const_gc, c_type_id, c_size,
-                c_has_finalizer, c_has_weakptr]
+                c_false, c_false, c_has_weakptr]
 
         # push and pop the current live variables *including* the argument
         # to the weakref_create operation, which must be kept alive and
@@ -1250,6 +1268,7 @@
             lltype2vtable = translator.rtyper.lltype2vtable
         else:
             lltype2vtable = None
+        self.translator = translator
         super(TransformerLayoutBuilder, self).__init__(GCClass, lltype2vtable)
 
     def has_finalizer(self, TYPE):
@@ -1257,6 +1276,10 @@
         return rtti is not None and getattr(rtti._obj, 'destructor_funcptr',
                                             None)
 
+    def has_light_finalizer(self, TYPE):
+        special = self.special_funcptr_for_type(TYPE)
+        return special is not None and special[0] == 'light_finalizer'
+
     def has_custom_trace(self, TYPE):
         rtti = get_rtti(TYPE)
         return rtti is not None and getattr(rtti._obj, 'custom_trace_funcptr',
@@ -1264,7 +1287,7 @@
 
     def make_finalizer_funcptr_for_type(self, TYPE):
         if not self.has_finalizer(TYPE):
-            return None
+            return None, False
         rtti = get_rtti(TYPE)
         destrptr = rtti._obj.destructor_funcptr
         DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0]
@@ -1276,7 +1299,9 @@
             return llmemory.NULL
         fptr = self.transformer.annotate_finalizer(ll_finalizer,
                 [llmemory.Address, llmemory.Address], llmemory.Address)
-        return fptr
+        g = destrptr._obj.graph
+        light = not FinalizerAnalyzer(self.translator).analyze_light_finalizer(g)
+        return fptr, light
 
     def make_custom_trace_funcptr_for_type(self, TYPE):
         if not self.has_custom_trace(TYPE):
diff --git a/pypy/rpython/memory/gctransform/transform.py b/pypy/rpython/memory/gctransform/transform.py
--- a/pypy/rpython/memory/gctransform/transform.py
+++ b/pypy/rpython/memory/gctransform/transform.py
@@ -63,7 +63,7 @@
                     gct.push_alive(v_result, self.llops)
             elif opname not in ('direct_call', 'indirect_call'):
                 gct.push_alive(v_result, self.llops)
-        
+
 
 
     def rename(self, newopname):
@@ -118,7 +118,7 @@
             self.minimalgctransformer = self.MinimalGCTransformer(self)
         else:
             self.minimalgctransformer = None
-            
+
     def get_lltype_of_exception_value(self):
         if self.translator is not None:
             exceptiondata = self.translator.rtyper.getexceptiondata()
@@ -399,7 +399,7 @@
 
     def gct_gc_heap_stats(self, hop):
         from pypy.rpython.memory.gc.base import ARRAY_TYPEID_MAP
-        
+
         return hop.cast_result(rmodel.inputconst(lltype.Ptr(ARRAY_TYPEID_MAP),
                                         lltype.nullptr(ARRAY_TYPEID_MAP)))
 
@@ -427,7 +427,7 @@
         assert flavor == 'raw'
         assert not flags.get('zero')
         return self.parenttransformer.gct_malloc_varsize(hop)
-    
+
     def gct_free(self, hop):
         flags = hop.spaceop.args[1].value
         flavor = flags['flavor']
@@ -502,7 +502,7 @@
         stack_mh = mallocHelpers()
         stack_mh.allocate = lambda size: llop.stack_malloc(llmemory.Address, size)
         ll_stack_malloc_fixedsize = stack_mh._ll_malloc_fixedsize
-        
+
         if self.translator:
             self.raw_malloc_fixedsize_ptr = self.inittime_helper(
                 ll_raw_malloc_fixedsize, [lltype.Signed], llmemory.Address)
@@ -541,7 +541,7 @@
                           resulttype=llmemory.Address)
         if flags.get('zero'):
             hop.genop("raw_memclear", [v_raw, c_size])
-        return v_raw        
+        return v_raw
 
     def gct_malloc_varsize(self, hop, add_flags=None):
         flags = hop.spaceop.args[1].value
@@ -559,6 +559,14 @@
     def gct_malloc_nonmovable_varsize(self, *args, **kwds):
         return self.gct_malloc_varsize(*args, **kwds)
 
+    def gct_gc_add_memory_pressure(self, hop):
+        if hasattr(self, 'raw_malloc_memory_pressure_ptr'):
+            op = hop.spaceop
+            size = op.args[0]
+            return hop.genop("direct_call",
+                          [self.raw_malloc_memory_pressure_ptr,
+                           size])
+
     def varsize_malloc_helper(self, hop, flags, meth, extraargs):
         def intconst(c): return rmodel.inputconst(lltype.Signed, c)
         op = hop.spaceop
@@ -590,9 +598,9 @@
     def gct_fv_raw_malloc_varsize(self, hop, flags, TYPE, v_length, c_const_size, c_item_size,
                                                                     c_offset_to_length):
         if flags.get('add_memory_pressure', False):
-            if hasattr(self, 'raw_malloc_memory_pressure_ptr'):
+            if hasattr(self, 'raw_malloc_memory_pressure_varsize_ptr'):
                 hop.genop("direct_call",
-                          [self.raw_malloc_memory_pressure_ptr,
+                          [self.raw_malloc_memory_pressure_varsize_ptr,
                            v_length, c_item_size])
         if c_offset_to_length is None:
             if flags.get('zero'):
@@ -625,7 +633,7 @@
                 hop.genop("track_alloc_stop", [v])
             hop.genop('raw_free', [v])
         else:
-            assert False, "%s has no support for free with flavor %r" % (self, flavor)           
+            assert False, "%s has no support for free with flavor %r" % (self, flavor)
 
     def gct_gc_can_move(self, hop):
         return hop.cast_result(rmodel.inputconst(lltype.Bool, False))
diff --git a/pypy/rpython/memory/gctypelayout.py b/pypy/rpython/memory/gctypelayout.py
--- a/pypy/rpython/memory/gctypelayout.py
+++ b/pypy/rpython/memory/gctypelayout.py
@@ -1,7 +1,6 @@
 from pypy.rpython.lltypesystem import lltype, llmemory, llarena, llgroup
 from pypy.rpython.lltypesystem import rclass
 from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.debug import ll_assert
 from pypy.rlib.rarithmetic import intmask
 from pypy.tool.identity_dict import identity_dict
@@ -85,6 +84,13 @@
         else:
             return lltype.nullptr(GCData.FINALIZER_OR_CT_FUNC)
 
+    def q_light_finalizer(self, typeid):
+        typeinfo = self.get(typeid)
+        if typeinfo.infobits & T_HAS_LIGHTWEIGHT_FINALIZER:
+            return typeinfo.finalizer_or_customtrace
+        else:
+            return lltype.nullptr(GCData.FINALIZER_OR_CT_FUNC)        
+
     def q_offsets_to_gc_pointers(self, typeid):
         return self.get(typeid).ofstoptrs
 
@@ -142,6 +148,7 @@
             self.q_has_gcptr_in_varsize,
             self.q_is_gcarrayofgcptr,
             self.q_finalizer,
+            self.q_light_finalizer,
             self.q_offsets_to_gc_pointers,
             self.q_fixed_size,
             self.q_varsize_item_sizes,
@@ -157,16 +164,17 @@
 
 
 # the lowest 16bits are used to store group member index
-T_MEMBER_INDEX         =   0xffff
-T_IS_VARSIZE           = 0x010000
-T_HAS_GCPTR_IN_VARSIZE = 0x020000
-T_IS_GCARRAY_OF_GCPTR  = 0x040000
-T_IS_WEAKREF           = 0x080000
-T_IS_RPYTHON_INSTANCE  = 0x100000    # the type is a subclass of OBJECT
-T_HAS_FINALIZER        = 0x200000
-T_HAS_CUSTOM_TRACE     = 0x400000
-T_KEY_MASK             = intmask(0xFF000000)
-T_KEY_VALUE            = intmask(0x5A000000)    # bug detection only
+T_MEMBER_INDEX              =   0xffff
+T_IS_VARSIZE                = 0x010000
+T_HAS_GCPTR_IN_VARSIZE      = 0x020000
+T_IS_GCARRAY_OF_GCPTR       = 0x040000
+T_IS_WEAKREF                = 0x080000
+T_IS_RPYTHON_INSTANCE       = 0x100000 # the type is a subclass of OBJECT
+T_HAS_FINALIZER             = 0x200000
+T_HAS_CUSTOM_TRACE          = 0x400000
+T_HAS_LIGHTWEIGHT_FINALIZER = 0x800000
+T_KEY_MASK                  = intmask(0xFF000000)
+T_KEY_VALUE                 = intmask(0x5A000000) # bug detection only
 
 def _check_valid_type_info(p):
     ll_assert(p.infobits & T_KEY_MASK == T_KEY_VALUE, "invalid type_id")
@@ -194,6 +202,8 @@
         info.finalizer_or_customtrace = fptr
         if kind == "finalizer":
             infobits |= T_HAS_FINALIZER
+        elif kind == 'light_finalizer':
+            infobits |= T_HAS_FINALIZER | T_HAS_LIGHTWEIGHT_FINALIZER
         elif kind == "custom_trace":
             infobits |= T_HAS_CUSTOM_TRACE
         else:
@@ -367,12 +377,15 @@
     def special_funcptr_for_type(self, TYPE):
         if TYPE in self._special_funcptrs:
             return self._special_funcptrs[TYPE]
-        fptr1 = self.make_finalizer_funcptr_for_type(TYPE)
+        fptr1, is_lightweight = self.make_finalizer_funcptr_for_type(TYPE)
         fptr2 = self.make_custom_trace_funcptr_for_type(TYPE)
         assert not (fptr1 and fptr2), (
             "type %r needs both a finalizer and a custom tracer" % (TYPE,))
         if fptr1:
-            kind_and_fptr = "finalizer", fptr1
+            if is_lightweight:
+                kind_and_fptr = "light_finalizer", fptr1
+            else:
+                kind_and_fptr = "finalizer", fptr1
         elif fptr2:
             kind_and_fptr = "custom_trace", fptr2
         else:
@@ -382,7 +395,7 @@
 
     def make_finalizer_funcptr_for_type(self, TYPE):
         # must be overridden for proper finalizer support
-        return None
+        return None, False
 
     def make_custom_trace_funcptr_for_type(self, TYPE):
         # must be overridden for proper custom tracer support
diff --git a/pypy/rpython/memory/gcwrapper.py b/pypy/rpython/memory/gcwrapper.py
--- a/pypy/rpython/memory/gcwrapper.py
+++ b/pypy/rpython/memory/gcwrapper.py
@@ -1,3 +1,4 @@
+from pypy.translator.backendopt.finalizer import FinalizerAnalyzer
 from pypy.rpython.lltypesystem import lltype, llmemory, llheap
 from pypy.rpython import llinterp
 from pypy.rpython.annlowlevel import llhelper
@@ -65,6 +66,10 @@
             gctypelayout.zero_gc_pointers(result)
         return result
 
+    def add_memory_pressure(self, size):
+        if hasattr(self.gc, 'raw_malloc_memory_pressure'):
+            self.gc.raw_malloc_memory_pressure(size)
+
     def shrink_array(self, p, smallersize):
         if hasattr(self.gc, 'shrink_array'):
             addr = llmemory.cast_ptr_to_adr(p)
@@ -196,9 +201,11 @@
             DESTR_ARG = lltype.typeOf(destrptr).TO.ARGS[0]
             destrgraph = destrptr._obj.graph
         else:
-            return None
+            return None, False
 
         assert not type_contains_pyobjs(TYPE), "not implemented"
+        t = self.llinterp.typer.annotator.translator
+        light = not FinalizerAnalyzer(t).analyze_light_finalizer(destrgraph)
         def ll_finalizer(addr, dummy):
             assert dummy == llmemory.NULL
             try:
@@ -208,7 +215,7 @@
                 raise RuntimeError(
                     "a finalizer raised an exception, shouldn't happen")
             return llmemory.NULL
-        return llhelper(gctypelayout.GCData.FINALIZER_OR_CT, ll_finalizer)
+        return llhelper(gctypelayout.GCData.FINALIZER_OR_CT, ll_finalizer), light
 
     def make_custom_trace_funcptr_for_type(self, TYPE):
         from pypy.rpython.memory.gctransform.support import get_rtti, \
diff --git a/pypy/rpython/memory/test/test_gc.py b/pypy/rpython/memory/test/test_gc.py
--- a/pypy/rpython/memory/test/test_gc.py
+++ b/pypy/rpython/memory/test/test_gc.py
@@ -5,7 +5,6 @@
 from pypy.rpython.memory.test import snippet
 from pypy.rpython.test.test_llinterp import get_interpreter
 from pypy.rpython.lltypesystem import lltype
-from pypy.rpython.lltypesystem.rstr import STR
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.objectmodel import compute_unique_id
@@ -57,7 +56,7 @@
                 while j < 20:
                     j += 1
                     a.append(j)
-        res = self.interpret(malloc_a_lot, [])
+        self.interpret(malloc_a_lot, [])
         #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
         #print "size before: %s, size after %s" % (curr, simulator.current_size)
 
@@ -73,7 +72,7 @@
                 while j < 20:
                     j += 1
                     b.append((1, j, i))
-        res = self.interpret(malloc_a_lot, [])
+        self.interpret(malloc_a_lot, [])
         #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
         #print "size before: %s, size after %s" % (curr, simulator.current_size)
 
@@ -129,7 +128,7 @@
         res = self.interpret(concat, [100])
         assert res == concat(100)
         #assert simulator.current_size - curr < 16000 * INT_SIZE / 4
-        
+
     def test_finalizer(self):
         class B(object):
             pass
@@ -278,7 +277,7 @@
                                self.interpret, f, [])
 
     def test_weakref(self):
-        import weakref, gc
+        import weakref
         class A(object):
             pass


More information about the pypy-commit mailing list