[pypy-commit] pypy reflex-support: merge default into branch

wlav noreply at buildbot.pypy.org
Mon May 30 19:25:45 CEST 2011


Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r44595:bc02a095ea11
Date: 2011-05-30 10:38 -0700
http://bitbucket.org/pypy/pypy/changeset/bc02a095ea11/

Log:	merge default into branch

diff --git a/lib-python/TODO b/lib-python/TODO
deleted file mode 100644
--- a/lib-python/TODO
+++ /dev/null
@@ -1,100 +0,0 @@
-TODO list for 2.7.0
-===================
-
-You can find the results of the most recent buildbot run at:
-http://buildbot.pypy.org/
-
-
-Probably easy tasks
--------------------
-
-- (unicode|bytearray).(index|find) should accept None as indices (see
-  test_unicode.py)
-
-- missing posix.confstr and posix.confstr_names
-
-- remove code duplication: bit_length() and _count_bits() in rlib/rbigint.py,
-  objspace/std/longobject.py and objspace/std/longtype.py.
-
-- missing module pyexpat.errors
-
-- support for PYTHONIOENCODING, this needs a way to update file.encoding
-
-- implement format__Complex_ANY() in pypy/objspace/std/complexobject.py
-
-- Code like this does not work, for two reasons::
-
-  \
-  from __future__ import (with_statement,
-                          unicode_literals)
-  assert type("") is unicode
-
-- Code like::
-
-  assert(x is not None, "error message")
-
-  should emit a SyntaxWarning when compiled (the tuple is always true)
-
-
-Medium tasks
-------------
-
-- socket module has a couple of changes (including AF_TIPC packet range)
-
-Longer tasks
-------------
-
-- Fix usage of __cmp__ in subclasses::
-
-    class badint(int):
-        def __cmp__(self, other):
-            raise RuntimeError
-    raises(RuntimeError, cmp, 0, badint(1))
-
-- Fix comparison of objects layout: if two classes have the same __slots__, it
-  should be possible to change the instances __class__::
-
-      class A(object): __slots__ = ('a', 'b')
-      class B(object): __slots__ = ('b', 'a')
-      a = A()
-      a.__class__ = B
-
-- Show a ResourceWarning when a file/socket is not explicitely closed, like
-  CPython did for 3.2: http://svn.python.org/view?view=rev&revision=85920
-  in PyPy this should be enabled by default
-
-Won't do for this release
--------------------------
-
-Note: when you give up with a missing feature, please mention it here, as well
-as the various skips added to the test suite.
-
-- py3k warnings
-
-  * the -3 flag is accepted on the command line, but displays a warning (see
-    `translator/goal/app_main.py`)
-
-- CJK codecs.
-
-  * In `./conftest.py`, skipped all `test_codecencodings_*.py` and
-    `test_codecmaps_*.py`.
-
-  * In test_codecs, commented out various items in `all_unicode_encodings`.
-
-- Error messages about ill-formed calls (like "argument after ** must be a
-  mapping") don't always show the function name.  That's hard to fix for
-  the case of errors raised when the Argument object is created (as opposed
-  to when parsing for a given target function, which occurs later).
-
-  * Some "..." were added to doctests in test_extcall.py
-
-- CPython's builtin methods are both functions and unbound methods (for
-  example, `str.upper is dict(str.__dict__)['upper']`). This is not the case
-  in pypy, and assertions like `object.__str__ is object.__str__` are False
-  with pypy.  Use the `==` operator instead.
-
-  * pprint.py, _threading_local.py
-
-- When importing a nested module fails, the ImportError message mentions the
-  name of the package up to the component that could not be imported (CPython
-  prefers to display the names starting with the failing part).
diff --git a/lib_pypy/stackless.py b/lib_pypy/stackless.py
--- a/lib_pypy/stackless.py
+++ b/lib_pypy/stackless.py
@@ -200,14 +200,15 @@
     # I can't think of a better solution without a real transform.
 
 def rewrite_stackless_primitive(coro_state, alive, tempval):
-    flags, state, thunk, parent = coro_state
-    for i, frame in enumerate(state):
+    flags, frame, thunk, parent = coro_state
+    while frame is not None:
         retval_expr = _stackless_primitive_registry.get(frame.f_code)
         if retval_expr:
             # this tasklet needs to stop pickling here and return its value.
             tempval = eval(retval_expr, globals(), frame.f_locals)
-            state = state[:i]
-            coro_state = flags, state, thunk, parent
+            coro_state = flags, frame, thunk, parent
+            break
+        frame = frame.f_back
     return coro_state, alive, tempval
 
 #
@@ -492,23 +493,22 @@
         assert two == ()
         # we want to get rid of the parent thing.
         # for now, we just drop it
-        a, b, c, d = coro_state
-        
+        a, frame, c, d = coro_state
+
         # Removing all frames related to stackless.py.
         # They point to stuff we don't want to be pickled.
-        frame_list = list(b)
-        new_frame_list = []
-        for frame in frame_list:
+
+        pickleframe = frame
+        while frame is not None:
             if frame.f_code == schedule.func_code:
                 # Removing everything including and after the
                 # call to stackless.schedule()
+                pickleframe = frame.f_back
                 break
-            new_frame_list.append(frame)
-        b = tuple(new_frame_list)
-        
+            frame = frame.f_back
         if d:
             assert isinstance(d, coroutine)
-        coro_state = a, b, c, None
+        coro_state = a, pickleframe, c, None
         coro_state, alive, tempval = rewrite_stackless_primitive(coro_state, self.alive, self.tempval)
         inst_dict = self.__dict__.copy()
         inst_dict.pop('tempval', None)
diff --git a/pypy/annotation/description.py b/pypy/annotation/description.py
--- a/pypy/annotation/description.py
+++ b/pypy/annotation/description.py
@@ -565,7 +565,7 @@
         if self.is_exception_class():
             if self.pyobj.__module__ == 'exceptions':
                 return True
-            if self.pyobj is py.code._AssertionError:
+            if issubclass(self.pyobj, AssertionError):
                 return True
         return False
 
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -242,6 +242,10 @@
                    "(the empty string and potentially single-char strings)",
                    default=False),
 
+        BoolOption("withsmalltuple",
+                   "use small tuples",
+                   default=False),
+
         BoolOption("withrope", "use ropes as the string implementation",
                    default=False,
                    requires=[("objspace.std.withstrslice", False),
diff --git a/pypy/doc/config/objspace.std.withsmalltuple.txt b/pypy/doc/config/objspace.std.withsmalltuple.txt
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/objspace.std.withsmalltuple.txt
@@ -0,0 +1,1 @@
+Use small tuple objects for sizes from 1 to 3
diff --git a/pypy/interpreter/astcompiler/misc.py b/pypy/interpreter/astcompiler/misc.py
--- a/pypy/interpreter/astcompiler/misc.py
+++ b/pypy/interpreter/astcompiler/misc.py
@@ -31,11 +31,12 @@
     future_lineno = 0
     future_column = 0
     have_docstring = False
+    body = None
     if isinstance(tree, ast.Module):
         body = tree.body
     elif isinstance(tree, ast.Interactive):
         body = tree.body
-    else:
+    if body is None:
         return 0, 0
     for stmt in body:
         if isinstance(stmt, ast.Expr) and isinstance(stmt.value, ast.Str):
diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py
--- a/pypy/interpreter/eval.py
+++ b/pypy/interpreter/eval.py
@@ -2,6 +2,7 @@
 This module defines the abstract base classes that support execution:
 Code and Frame.
 """
+from pypy.rlib import jit
 from pypy.interpreter.error import OperationError
 from pypy.interpreter.baseobjspace import Wrappable
 
@@ -97,6 +98,7 @@
         "Abstract. Get the expected number of locals."
         raise TypeError, "abstract"
 
+    @jit.dont_look_inside
     def fast2locals(self):
         # Copy values from self.fastlocals_w to self.w_locals
         if self.w_locals is None:
@@ -110,6 +112,7 @@
                 w_name = self.space.wrap(name)
                 self.space.setitem(self.w_locals, w_name, w_value)
 
+    @jit.dont_look_inside
     def locals2fast(self):
         # Copy values from self.w_locals to self.fastlocals_w
         assert self.w_locals is not None
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -102,18 +102,16 @@
 
         # the following interface is for pickling and unpickling
         def getstate(self, space):
-            # XXX we could just save the top frame, which brings
-            # the whole frame stack, but right now we get the whole stack
-            items = [space.wrap(f) for f in self.getframestack()]
-            return space.newtuple(items)
+            if self.topframe is None:
+                return space.w_None
+            return self.topframe
 
         def setstate(self, space, w_state):
             from pypy.interpreter.pyframe import PyFrame
-            frames_w = space.unpackiterable(w_state)
-            if len(frames_w) > 0:
-                self.topframe = space.interp_w(PyFrame, frames_w[-1])
+            if space.is_w(w_state, space.w_None):
+                self.topframe = None
             else:
-                self.topframe = None
+                self.topframe = space.interp_w(PyFrame, w_state)
 
         def getframestack(self):
             lst = []
diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py
--- a/pypy/interpreter/nestedscope.py
+++ b/pypy/interpreter/nestedscope.py
@@ -127,6 +127,7 @@
         if self.cells is not None:
             self.cells[:ncellvars] = cellvars
 
+    @jit.dont_look_inside
     def fast2locals(self):
         super_fast2locals(self)
         # cellvars are values exported to inner scopes
@@ -145,6 +146,7 @@
                 w_name = self.space.wrap(name)
                 self.space.setitem(self.w_locals, w_name, w_value)
 
+    @jit.dont_look_inside
     def locals2fast(self):
         super_locals2fast(self)
         freevarnames = self.pycode.co_cellvars + self.pycode.co_freevars
diff --git a/pypy/interpreter/pycompiler.py b/pypy/interpreter/pycompiler.py
--- a/pypy/interpreter/pycompiler.py
+++ b/pypy/interpreter/pycompiler.py
@@ -101,9 +101,9 @@
     """
     def __init__(self, space, override_version=None):
         PyCodeCompiler.__init__(self, space)
-        self.parser = pyparse.PythonParser(space)
+        self.future_flags = future.futureFlags_2_7
+        self.parser = pyparse.PythonParser(space, self.future_flags)
         self.additional_rules = {}
-        self.future_flags = future.futureFlags_2_7
         self.compiler_flags = self.future_flags.allowed_flags
 
     def compile_ast(self, node, filename, mode, flags):
@@ -140,9 +140,6 @@
     def _compile_to_ast(self, source, info):
         space = self.space
         try:
-            f_flags, future_info = future.get_futures(self.future_flags, source)
-            info.last_future_import = future_info
-            info.flags |= f_flags
             parse_tree = self.parser.parse_source(source, info)
             mod = astbuilder.ast_from_node(space, parse_tree, info)
         except parseerror.IndentationError, e:
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -11,7 +11,7 @@
 from pypy.rlib.jit import hint
 from pypy.rlib.debug import make_sure_not_resized
 from pypy.rlib.rarithmetic import intmask
-from pypy.rlib import jit, rstack
+from pypy.rlib import jit
 from pypy.tool import stdlib_opcode
 from pypy.tool.stdlib_opcode import host_bytecode_spec
 
@@ -157,8 +157,6 @@
             try:
                 w_exitvalue = self.dispatch(self.pycode, next_instr,
                                             executioncontext)
-                rstack.resume_point("execute_frame", self, executioncontext,
-                                    returns=w_exitvalue)
             except Exception:
                 executioncontext.return_trace(self, self.space.w_None)
                 raise
@@ -415,6 +413,7 @@
         "Get the fast locals as a list."
         return self.fastlocals_w
 
+    @jit.dont_look_inside
     def setfastscope(self, scope_w):
         """Initialize the fast locals from a list of values,
         where the order is according to self.pycode.signature()."""
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -11,7 +11,7 @@
 from pypy.interpreter.pycode import PyCode
 from pypy.tool.sourcetools import func_with_new_name
 from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib import jit, rstackovf, rstack
+from pypy.rlib import jit, rstackovf
 from pypy.rlib.rarithmetic import r_uint, intmask
 from pypy.rlib.unroll import unrolling_iterable
 from pypy.rlib.debug import check_nonneg
@@ -83,16 +83,12 @@
         try:
             while True:
                 next_instr = self.handle_bytecode(co_code, next_instr, ec)
-                rstack.resume_point("dispatch", self, co_code, ec,
-                                    returns=next_instr)
         except ExitFrame:
             return self.popvalue()
 
     def handle_bytecode(self, co_code, next_instr, ec):
         try:
             next_instr = self.dispatch_bytecode(co_code, next_instr, ec)
-            rstack.resume_point("handle_bytecode", self, co_code, ec,
-                                returns=next_instr)
         except OperationError, operr:
             next_instr = self.handle_operation_error(ec, operr)
         except Reraise:
@@ -248,9 +244,6 @@
                         # dispatch to the opcode method
                         meth = getattr(self, opdesc.methodname)
                         res = meth(oparg, next_instr)
-                        if opdesc.index == self.opcodedesc.CALL_FUNCTION.index:
-                            rstack.resume_point("dispatch_call", self, co_code,
-                                                next_instr, ec)
                         # !! warning, for the annotator the next line is not
                         # comparing an int and None - you can't do that.
                         # Instead, it's constant-folded to either True or False
@@ -997,7 +990,6 @@
                                                           args)
         else:
             w_result = self.space.call_args(w_function, args)
-        rstack.resume_point("call_function", self, returns=w_result)
         self.pushvalue(w_result)
 
     def CALL_FUNCTION(self, oparg, next_instr):
@@ -1008,8 +1000,6 @@
             w_function = self.peekvalue(nargs)
             try:
                 w_result = self.space.call_valuestack(w_function, nargs, self)
-                rstack.resume_point("CALL_FUNCTION", self, nargs,
-                                    returns=w_result)
             finally:
                 self.dropvalues(nargs + 1)
             self.pushvalue(w_result)
@@ -1099,6 +1089,7 @@
         w_dict = self.space.newdict()
         self.pushvalue(w_dict)
 
+    @jit.unroll_safe
     def BUILD_SET(self, itemcount, next_instr):
         w_set = self.space.call_function(self.space.w_set)
         if itemcount:
diff --git a/pypy/interpreter/pyparser/pyparse.py b/pypy/interpreter/pyparser/pyparse.py
--- a/pypy/interpreter/pyparser/pyparse.py
+++ b/pypy/interpreter/pyparser/pyparse.py
@@ -1,6 +1,6 @@
 from pypy.interpreter import gateway
 from pypy.interpreter.error import OperationError
-from pypy.interpreter.pyparser import parser, pytokenizer, pygram, error
+from pypy.interpreter.pyparser import future, parser, pytokenizer, pygram, error
 from pypy.interpreter.astcompiler import consts
 
 
@@ -88,9 +88,11 @@
 
 class PythonParser(parser.Parser):
 
-    def __init__(self, space, grammar=pygram.python_grammar):
+    def __init__(self, space, future_flags=future.futureFlags_2_7,
+                 grammar=pygram.python_grammar):
         parser.Parser.__init__(self, grammar)
         self.space = space
+        self.future_flags = future_flags
 
     def parse_source(self, textsrc, compile_info):
         """Main entry point for parsing Python source.
@@ -133,6 +135,10 @@
                         raise error.SyntaxError(space.str_w(w_message))
                     raise
 
+        f_flags, future_info = future.get_futures(self.future_flags, textsrc)
+        compile_info.last_future_import = future_info
+        compile_info.flags |= f_flags
+
         flags = compile_info.flags
 
         if flags & consts.CO_FUTURE_PRINT_FUNCTION:
diff --git a/pypy/interpreter/test/test_compiler.py b/pypy/interpreter/test/test_compiler.py
--- a/pypy/interpreter/test/test_compiler.py
+++ b/pypy/interpreter/test/test_compiler.py
@@ -714,6 +714,12 @@
 
 class AppTestCompiler:
 
+    def test_bom_with_future(self):
+        s = '\xef\xbb\xbffrom __future__ import division\nx = 1/2'
+        ns = {}
+        exec s in ns
+        assert ns["x"] == .5
+
     def test_values_of_different_types(self):
         exec "a = 0; b = 0L; c = 0.0; d = 0j"
         assert type(a) is int
diff --git a/pypy/jit/backend/llsupport/llmodel.py b/pypy/jit/backend/llsupport/llmodel.py
--- a/pypy/jit/backend/llsupport/llmodel.py
+++ b/pypy/jit/backend/llsupport/llmodel.py
@@ -143,11 +143,11 @@
         STACK_CHECK_SLOWPATH = lltype.Ptr(lltype.FuncType([lltype.Signed],
                                                           lltype.Void))
         def insert_stack_check():
-            startaddr = rstack._stack_get_start_adr()
-            length = rstack._stack_get_length()
+            endaddr = rstack._stack_get_end_adr()
+            lengthaddr = rstack._stack_get_length_adr()
             f = llhelper(STACK_CHECK_SLOWPATH, rstack.stack_check_slowpath)
             slowpathaddr = rffi.cast(lltype.Signed, f)
-            return startaddr, length, slowpathaddr
+            return endaddr, lengthaddr, slowpathaddr
 
         self.pos_exception = pos_exception
         self.pos_exc_value = pos_exc_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
@@ -137,7 +137,8 @@
         self.current_clt = looptoken.compiled_loop_token
         self.pending_guard_tokens = []
         self.mc = codebuf.MachineCodeBlockWrapper()
-        assert self.datablockwrapper is None
+        #assert self.datablockwrapper is None --- but obscure case
+        # possible, e.g. getting MemoryError and continuing
         allblocks = self.get_asmmemmgr_blocks(looptoken)
         self.datablockwrapper = MachineDataBlockWrapper(self.cpu.asmmemmgr,
                                                         allblocks)
@@ -620,11 +621,11 @@
         if self.stack_check_slowpath == 0:
             pass                # no stack check (e.g. not translated)
         else:
-            startaddr, length, _ = self.cpu.insert_stack_check()
-            self.mc.MOV(eax, esp)                       # MOV eax, current
-            self.mc.SUB(eax, heap(startaddr))           # SUB eax, [startaddr]
-            self.mc.CMP(eax, imm(length))               # CMP eax, length
-            self.mc.J_il8(rx86.Conditions['B'], 0)      # JB .skip
+            endaddr, lengthaddr, _ = self.cpu.insert_stack_check()
+            self.mc.MOV(eax, heap(endaddr))             # MOV eax, [start]
+            self.mc.SUB(eax, esp)                       # SUB eax, current
+            self.mc.CMP(eax, heap(lengthaddr))          # CMP eax, [length]
+            self.mc.J_il8(rx86.Conditions['BE'], 0)     # JBE .skip
             jb_location = self.mc.get_relative_pos()
             self.mc.CALL(imm(self.stack_check_slowpath))# CALL slowpath
             # patch the JB above                        # .skip:
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
@@ -209,7 +209,6 @@
     def rewrite_op_cast_int_to_unichar(self, op): pass
     def rewrite_op_cast_int_to_uint(self, op): pass
     def rewrite_op_cast_uint_to_int(self, op): pass
-    def rewrite_op_resume_point(self, op): pass
 
     def _rewrite_symmetric(self, op):
         """Rewrite 'c1+v2' into 'v2+c1' in an attempt to avoid generating
diff --git a/pypy/jit/codewriter/policy.py b/pypy/jit/codewriter/policy.py
--- a/pypy/jit/codewriter/policy.py
+++ b/pypy/jit/codewriter/policy.py
@@ -63,12 +63,27 @@
             contains_loop = contains_loop and not getattr(
                     func, '_jit_unroll_safe_', False)
 
-        res = see_function and not contains_unsupported_variable_type(graph,
-                                                        self.supports_floats,
-                                                        self.supports_longlong)
+        unsupported = contains_unsupported_variable_type(graph,
+                                                         self.supports_floats,
+                                                         self.supports_longlong)
+        res = see_function and not unsupported
         if res and contains_loop:
             self.unsafe_loopy_graphs.add(graph)
-        return res and not contains_loop
+        res = res and not contains_loop
+        if (see_function and not res and
+            getattr(graph, "access_directly", False)):
+            # This happens when we have a function which has an argument with
+            # the access_directly flag, and the annotator has determined we will
+            # see the function. (See
+            # pypy/annotation/specialize.py:default_specialize) However,
+            # look_inside_graph just decided that we will not see it. (It has a
+            # loop or unsupported variables.) If we return False, the call will
+            # be turned into a residual call, but the graph is access_directly!
+            # If such a function is called and accesses a virtualizable, the JIT
+            # will not notice, and the virtualizable will fall out of sync. So,
+            # we fail loudly now.
+            raise ValueError("access_directly on a function which we don't see %s" % graph)
+        return res
 
 def contains_unsupported_variable_type(graph, supports_floats,
                                        supports_longlong):
diff --git a/pypy/jit/codewriter/test/test_policy.py b/pypy/jit/codewriter/test/test_policy.py
--- a/pypy/jit/codewriter/test/test_policy.py
+++ b/pypy/jit/codewriter/test/test_policy.py
@@ -1,4 +1,5 @@
 import sys
+import py
 from pypy.jit.codewriter.policy import contains_unsupported_variable_type
 from pypy.jit.codewriter.policy import JitPolicy
 from pypy.jit.codewriter import support
@@ -107,3 +108,19 @@
                     mod = called_graph.func.__module__
                     assert (mod == 'pypy.rpython.rlist' or
                             mod == 'pypy.rpython.lltypesystem.rlist')
+
+def test_access_directly_but_not_seen():
+    class X:
+        _virtualizable2_ = ["a"]
+    def h(x, y):
+        w = 0
+        for i in range(y):
+            w += 4
+        return w
+    def f(y):
+        x = jit.hint(X(), access_directly=True)
+        h(x, y)
+    rtyper = support.annotate(f, [3])
+    h_graph = rtyper.annotator.translator.graphs[1]
+    assert h_graph.func is h
+    py.test.raises(ValueError, JitPolicy().look_inside_graph, h_graph)
diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py
--- a/pypy/jit/metainterp/test/test_list.py
+++ b/pypy/jit/metainterp/test/test_list.py
@@ -236,4 +236,8 @@
             return a * b
         res = self.meta_interp(f, [37])
         assert res == f(37)
-        self.check_loops(getfield_gc=1, everywhere=True)
+        # There is the one actual field on a, plus 2 getfield's from the list
+        # itself, 1 to get the length (which is then incremented and passed to
+        # the resize func), and then a read of the items field to actually
+        # perform the setarrayitem on
+        self.check_loops(getfield_gc=5, everywhere=True)
diff --git a/pypy/jit/metainterp/test/test_tl.py b/pypy/jit/metainterp/test/test_tl.py
--- a/pypy/jit/metainterp/test/test_tl.py
+++ b/pypy/jit/metainterp/test/test_tl.py
@@ -58,7 +58,7 @@
             exit:
                 RETURN
         ''')
-        
+
         codes = [code, code2]
         def main(n, inputarg):
             code = codes[n]
@@ -116,7 +116,7 @@
         codes = [code, '']
         def main(num, arg):
             return interp(codes[num], inputarg=arg)
-        
+
         res = self.meta_interp(main, [0, 20], enable_opts='',
                                listops=listops, backendopt=True, policy=policy)
         assert res == 0
@@ -128,7 +128,6 @@
         from pypy.jit.tl.tl import Stack
         methods = [Stack.put,
                    Stack.pick,
-                   Stack.roll,
                    Stack.append,
                    Stack.pop]
         for meth in methods:
diff --git a/pypy/jit/tl/tl.py b/pypy/jit/tl/tl.py
--- a/pypy/jit/tl/tl.py
+++ b/pypy/jit/tl/tl.py
@@ -40,6 +40,7 @@
         assert n >= 0
         self.stack[n] = elem
 
+    @dont_look_inside
     def roll(self, r):
         if r < -1:
             i = self.stackpos + r
diff --git a/pypy/module/_ast/test/test_ast.py b/pypy/module/_ast/test/test_ast.py
--- a/pypy/module/_ast/test/test_ast.py
+++ b/pypy/module/_ast/test/test_ast.py
@@ -128,6 +128,9 @@
         assert ns["x"] == ns["lemon"] == 3
         assert ns["apple"] == 4
 
+    def test_empty_module(self):
+        compile(self.ast.Module([]), "<test>", "exec")
+
     def test_ast_types(self):
         ast = self.ast
         expr = ast.Expr()
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
@@ -43,7 +43,11 @@
         # assume that the file and stream objects are only visible in the
         # thread that runs __del__, so no race condition should be possible
         self.clear_all_weakrefs()
-        self.direct_close()
+        try:
+            self.direct_close()
+        except StreamErrors, e:
+            operr = wrap_streamerror(self.space, e, self.w_name)
+            operr.write_unraisable(self.space, '__del__ of ', self)
 
     def fdopenstream(self, stream, fd, mode, w_name=None):
         self.fd = fd
@@ -553,4 +557,4 @@
 @unwrap_spec(file=W_File, encoding="str_or_None", errors="str_or_None")
 def set_file_encoding(space, file, encoding=None, errors=None):
     file.encoding = encoding
-    file.errors = errors
\ No newline at end of file
+    file.errors = errors
diff --git a/pypy/module/_file/test/test_file.py b/pypy/module/_file/test/test_file.py
--- a/pypy/module/_file/test/test_file.py
+++ b/pypy/module/_file/test/test_file.py
@@ -232,6 +232,29 @@
             data = f.read()
             assert data == "15"
 
+    def test_exception_from_close(self):
+        import os
+        f = self.file(self.temppath, 'w')
+        os.close(f.fileno())
+        raises(IOError, f.close)    # bad file descriptor
+
+    def test_exception_from_del(self):
+        import os, gc, sys, cStringIO
+        f = self.file(self.temppath, 'w')
+        g = cStringIO.StringIO()
+        preverr = sys.stderr
+        try:
+            sys.stderr = g
+            os.close(f.fileno())
+            del f
+            gc.collect()     # bad file descriptor in f.__del__()
+        finally:
+            sys.stderr = preverr
+        import errno
+        assert os.strerror(errno.EBADF) in g.getvalue()
+        # the following is a "nice to have" feature that CPython doesn't have
+        if '__pypy__' in sys.builtin_module_names:
+            assert self.temppath in g.getvalue()
 
 
 class AppTestConcurrency(object):
diff --git a/pypy/module/_stackless/interp_coroutine.py b/pypy/module/_stackless/interp_coroutine.py
--- a/pypy/module/_stackless/interp_coroutine.py
+++ b/pypy/module/_stackless/interp_coroutine.py
@@ -28,7 +28,7 @@
 
 from pypy.module.exceptions.interp_exceptions import W_SystemExit, _new_exception
 
-from pypy.rlib import rstack # for resume points
+from pypy.rlib import rstack, jit # for resume points
 from pypy.tool import stdlib_opcode as pythonopcode
 
 class _AppThunk(AbstractThunk):
@@ -47,9 +47,19 @@
     def call(self):
         costate = self.costate
         w_result = self.space.call_args(self.w_func, self.args)
-        rstack.resume_point("appthunk", costate, returns=w_result)
         costate.w_tempval = w_result
 
+class _ResumeThunk(AbstractThunk):
+    def __init__(self, space, costate, w_frame):
+        self.space = space
+        self.costate = costate
+        self.w_frame = w_frame
+
+    def call(self):
+        w_result = resume_frame(self.space, self.w_frame)
+        # costate.w_tempval = w_result #XXX?
+
+
 W_CoroutineExit = _new_exception('CoroutineExit', W_SystemExit,
                         """Coroutine killed manually.""")
 
@@ -97,7 +107,6 @@
                 "cannot switch to an unbound Coroutine"))
         state = self.costate
         self.switch()
-        rstack.resume_point("w_switch", state, space)
         w_ret, state.w_tempval = state.w_tempval, space.w_None
         return w_ret
 
@@ -217,75 +226,17 @@
         self.parent = space.interp_w(AppCoroutine, w_parent)
         ec = self.space.getexecutioncontext()
         self.subctx.setstate(space, w_state)
-        self.reconstruct_framechain()
         if space.is_w(w_thunk, space.w_None):
-            self.thunk = None
+            if space.is_w(w_state, space.w_None):
+                self.thunk = None
+            else:
+                self.bind(_ResumeThunk(space, self.costate, self.subctx.topframe))
         else:
             w_func, w_args, w_kwds = space.unpackiterable(w_thunk,
                                                           expected_length=3)
             args = Arguments.frompacked(space, w_args, w_kwds)
             self.bind(_AppThunk(space, self.costate, w_func, args))
 
-    def reconstruct_framechain(self):
-        from pypy.interpreter.pyframe import PyFrame
-        from pypy.rlib.rstack import resume_state_create
-        if self.subctx.topframe is None:
-            self.frame = None
-            return
-
-        space = self.space
-        ec = space.getexecutioncontext()
-        costate = self.costate
-        # now the big fun of recreating tiny things...
-        bottom = resume_state_create(None, "yield_current_frame_to_caller_1")
-        # ("coroutine__bind", state)
-        _bind_frame = resume_state_create(bottom, "coroutine__bind", costate)
-        # ("appthunk", costate, returns=w_result)
-        appthunk_frame = resume_state_create(_bind_frame, "appthunk", costate)
-        chain = appthunk_frame
-        for frame in self.subctx.getframestack():
-            assert isinstance(frame, PyFrame)
-            # ("execute_frame", self, executioncontext, returns=w_exitvalue)
-            chain = resume_state_create(chain, "execute_frame", frame, ec)
-            code = frame.pycode.co_code
-            # ("dispatch", self, co_code, ec, returns=next_instr)
-            chain = resume_state_create(chain, "dispatch", frame, code, ec)
-            # ("handle_bytecode", self, co_code, ec, returns=next_instr)
-            chain = resume_state_create(chain, "handle_bytecode", frame, code,
-                                        ec)
-            instr = frame.last_instr
-            opcode = ord(code[instr])
-            map = pythonopcode.opmap
-            call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], 
-                        map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']]
-            assert opcode in call_ops
-            # ("dispatch_call", self, co_code, next_instr, ec)
-            chain = resume_state_create(chain, "dispatch_call", frame, code,
-                                        instr+3, ec)
-            instr += 1
-            oparg = ord(code[instr]) | ord(code[instr + 1]) << 8
-            nargs = oparg & 0xff
-            nkwds = (oparg >> 8) & 0xff
-            if space.config.objspace.opcodes.CALL_METHOD and opcode == map['CALL_METHOD']:
-                if nkwds == 0:     # only positional arguments
-                    chain = resume_state_create(chain, 'CALL_METHOD', frame,
-                                                nargs)
-                else:              # includes keyword arguments
-                    chain = resume_state_create(chain, 'CALL_METHOD_KW', frame)
-            elif opcode == map['CALL_FUNCTION'] and nkwds == 0:
-                # Only positional arguments
-                # case1: ("CALL_FUNCTION", f, nargs, returns=w_result)
-                chain = resume_state_create(chain, 'CALL_FUNCTION', frame,
-                                            nargs)
-            else:
-                # case2: ("call_function", f, returns=w_result)
-                chain = resume_state_create(chain, 'call_function', frame)
-
-        # ("w_switch", state, space)
-        w_switch_frame = resume_state_create(chain, 'w_switch', costate, space)
-        # ("coroutine_switch", state, returns=incoming_frame)
-        switch_frame = resume_state_create(w_switch_frame, "coroutine_switch", costate)
-        self.frame = switch_frame
 
 # _mixin_ did not work
 for methname in StacklessFlags.__dict__:
@@ -411,3 +362,45 @@
 @unwrap_spec(limit=int)
 def set_stack_depth_limit(space, limit):
     rstack.set_stack_depth_limit(limit)
+
+
+# ___________________________________________________________________
+# unpickling trampoline
+
+def resume_frame(space, w_frame):
+    from pypy.interpreter.pyframe import PyFrame
+    frame = space.interp_w(PyFrame, w_frame, can_be_None=True)
+    w_result = space.w_None
+    operr = None
+    executioncontext = frame.space.getexecutioncontext()
+    while frame is not None:
+        code = frame.pycode.co_code
+        instr = frame.last_instr
+        opcode = ord(code[instr])
+        map = pythonopcode.opmap
+        call_ops = [map['CALL_FUNCTION'], map['CALL_FUNCTION_KW'], map['CALL_FUNCTION_VAR'], 
+                    map['CALL_FUNCTION_VAR_KW'], map['CALL_METHOD']]
+        assert opcode in call_ops
+        instr += 1
+        oparg = ord(code[instr]) | ord(code[instr + 1]) << 8
+        nargs = oparg & 0xff
+        nkwds = (oparg >> 8) & 0xff
+        if nkwds == 0:     # only positional arguments
+            # fast paths leaves things on the stack, pop them
+            if space.config.objspace.opcodes.CALL_METHOD and opcode == map['CALL_METHOD']:
+                frame.dropvalues(nargs + 2)
+            elif opcode == map['CALL_FUNCTION']:
+                frame.dropvalues(nargs + 1)
+
+        # small hack: unlink frame out of the execution context, because
+        # execute_frame will add it there again
+        executioncontext.topframeref = jit.non_virtual_ref(frame.f_backref())
+        frame.last_instr = instr + 1 # continue after the call
+        try:
+            w_result = frame.execute_frame(w_result, operr)
+        except OperationError, operr:
+            pass
+        frame = frame.f_backref()
+    if operr:
+        raise operr
+    return w_result
diff --git a/pypy/module/_stackless/test/test_coroutine.py b/pypy/module/_stackless/test/test_coroutine.py
--- a/pypy/module/_stackless/test/test_coroutine.py
+++ b/pypy/module/_stackless/test/test_coroutine.py
@@ -8,33 +8,6 @@
         space = gettestobjspace(usemodules=('_stackless',))
         cls.space = space
 
-    def test_pickle_coroutine_empty(self):
-        # this test is limited to basic pickling.
-        # real stacks can only tested with a stackless pypy build.
-        import _stackless as stackless
-        co = stackless.coroutine()
-        import pickle
-        pckl = pickle.dumps(co)
-        co2 = pickle.loads(pckl)
-        # the empty unpickled coroutine can still be used:
-        result = []
-        co2.bind(result.append, 42)
-        co2.switch()
-        assert result == [42]
-
-    def test_pickle_coroutine_bound(self):
-        import pickle
-        import _stackless
-        lst = [4]
-        co = _stackless.coroutine()
-        co.bind(lst.append, 2)
-        pckl = pickle.dumps((co, lst))
-
-        (co2, lst2) = pickle.loads(pckl)
-        assert lst2 == [4]
-        co2.switch()
-        assert lst2 == [4, 2]
-
     def test_raise_propagate(self):
         import _stackless as stackless
         co = stackless.coroutine()
diff --git a/pypy/module/_stackless/test/test_pickle.py b/pypy/module/_stackless/test/test_pickle.py
--- a/pypy/module/_stackless/test/test_pickle.py
+++ b/pypy/module/_stackless/test/test_pickle.py
@@ -19,9 +19,35 @@
 class AppTestPickle:
 
     def setup_class(cls):
-        if not option.runappdirect:
-            py.test.skip('pure appdirect test (run with -A)')
-        cls.space = gettestobjspace(usemodules=('_stackless',))
+        cls.space = gettestobjspace(usemodules=('_stackless',), CALL_METHOD=True)
+
+    def test_pickle_coroutine_empty(self):
+        # this test is limited to basic pickling.
+        # real stacks can only tested with a stackless pypy build.
+        import _stackless as stackless
+        co = stackless.coroutine()
+        import pickle
+        pckl = pickle.dumps(co)
+        co2 = pickle.loads(pckl)
+        # the empty unpickled coroutine can still be used:
+        result = []
+        co2.bind(result.append, 42)
+        co2.switch()
+        assert result == [42]
+
+    def test_pickle_coroutine_bound(self):
+        import pickle
+        import _stackless
+        lst = [4]
+        co = _stackless.coroutine()
+        co.bind(lst.append, 2)
+        pckl = pickle.dumps((co, lst))
+
+        (co2, lst2) = pickle.loads(pckl)
+        assert lst2 == [4]
+        co2.switch()
+        assert lst2 == [4, 2]
+
 
     def test_simple_ish(self):
 
@@ -58,6 +84,113 @@
         finally:
             del sys.modules['mod']
 
+    def test_pickle_again(self):
+
+        import new, sys
+
+        mod = new.module('mod')
+        sys.modules['mod'] = mod
+        try:
+            exec '''
+output = []
+import _stackless
+def f(coro, n, x):
+    if n == 0:
+        coro.switch()
+        return
+    f(coro, n-1, 2*x)
+    output.append(x)
+
+def example():
+    main_coro = _stackless.coroutine.getcurrent()
+    sub_coro = _stackless.coroutine()
+    sub_coro.bind(f, main_coro, 5, 1)
+    sub_coro.switch()
+
+    import pickle
+    pckl = pickle.dumps(sub_coro)
+    new_coro = pickle.loads(pckl)
+    pckl = pickle.dumps(new_coro)
+    newer_coro = pickle.loads(pckl)
+
+    newer_coro.switch()
+
+example()
+assert output == [16, 8, 4, 2, 1]
+''' in mod.__dict__
+        finally:
+            del sys.modules['mod']
+
+    def test_kwargs(self):
+
+        import new, sys
+
+        mod = new.module('mod')
+        sys.modules['mod'] = mod
+        try:
+            exec '''
+output = []
+import _stackless
+def f(coro, n, x, step=4):
+    if n == 0:
+        coro.switch()
+        return
+    f(coro, n-1, 2*x, step=1)
+    output.append(x)
+
+def example():
+    main_coro = _stackless.coroutine.getcurrent()
+    sub_coro = _stackless.coroutine()
+    sub_coro.bind(f, main_coro, 5, 1, 1)
+    sub_coro.switch()
+
+    import pickle
+    pckl = pickle.dumps(sub_coro)
+    new_coro = pickle.loads(pckl)
+
+    new_coro.switch()
+
+example()
+assert output == [16, 8, 4, 2, 1]
+''' in mod.__dict__
+        finally:
+            del sys.modules['mod']
+
+    def test_starstarargs(self):
+
+        import new, sys
+
+        mod = new.module('mod')
+        sys.modules['mod'] = mod
+        try:
+            exec '''
+output = []
+import _stackless
+def f(coro, n, x, step=4):
+    if n == 0:
+        coro.switch()
+        return
+    f(coro, n-1, 2*x, **{'step': 1})
+    output.append(x)
+
+def example():
+    main_coro = _stackless.coroutine.getcurrent()
+    sub_coro = _stackless.coroutine()
+    sub_coro.bind(f, main_coro, 5, 1, 1)
+    sub_coro.switch()
+
+    import pickle
+    pckl = pickle.dumps(sub_coro)
+    new_coro = pickle.loads(pckl)
+
+    new_coro.switch()
+
+example()
+assert output == [16, 8, 4, 2, 1]
+''' in mod.__dict__
+        finally:
+            del sys.modules['mod']
+
     def test_closure(self):
         import new, sys
 
@@ -130,8 +263,55 @@
         finally:
             del sys.modules['mod']
 
+    def test_exception_after_unpickling(self):
+
+        import new, sys
+
+        mod = new.module('mod')
+        sys.modules['mod'] = mod
+        try:
+            exec '''
+output = []
+import _stackless
+def f(coro, n, x):
+    if n == 0:
+        coro.switch()
+        raise ValueError
+    try:
+        f(coro, n-1, 2*x)
+    finally:
+        output.append(x)
+
+def example():
+    main_coro = _stackless.coroutine.getcurrent()
+    sub_coro = _stackless.coroutine()
+    sub_coro.bind(f, main_coro, 5, 1)
+    sub_coro.switch()
+
+    import pickle
+    pckl = pickle.dumps(sub_coro)
+    new_coro = pickle.loads(pckl)
+
+    try:
+        sub_coro.switch()
+    except ValueError:
+        pass
+    else:
+        assert 0
+    try:
+        new_coro.switch()
+    except ValueError:
+        pass
+    else:
+        assert 0
+
+example()
+assert output == [16, 8, 4, 2, 1] * 2
+''' in mod.__dict__
+        finally:
+            del sys.modules['mod']
+
     def test_loop(self):
-        #skip("happily segfaulting")
         import new, sys
 
         mod = new.module('mod')
diff --git a/pypy/module/_stackless/test/test_pickle_infrastructure.py b/pypy/module/_stackless/test/test_pickle_infrastructure.py
deleted file mode 100644
--- a/pypy/module/_stackless/test/test_pickle_infrastructure.py
+++ /dev/null
@@ -1,301 +0,0 @@
-from pypy.conftest import gettestobjspace
-from py.test import skip
-
-
-class BaseAppTestPicklePrerequisites(object):
-    OPTIONS = {}
-    def setup_class(cls):
-        space = gettestobjspace(usemodules=('_stackless',), **cls.OPTIONS)
-        cls.space = space
-
-    def test_pickle_switch_function(object):
-        import _stackless, pickle
-
-        sw = _stackless.coroutine.switch.im_func
-        dump = pickle.dumps(sw)
-        res = pickle.loads(dump)
-
-        assert res is sw
-        assert res.func_code is sw.func_code
-        assert res.func_doc is sw.func_doc
-        assert res.func_globals is sw.func_globals
-
-    def test_pickle_switch_function_code(object):
-        import _stackless, pickle
-
-        sw = _stackless.coroutine.switch.im_func.func_code
-        dump = pickle.dumps(sw)
-        res = pickle.loads(dump)
-
-        assert res is sw
-        
-class AppTestPicklePrerequisites(BaseAppTestPicklePrerequisites):
-    pass
-
-class AppTestPicklePrerequisitesBuiltinShortcut(BaseAppTestPicklePrerequisites):
-    OPTIONS = {"objspace.std.builtinshortcut": True}
-
-class FrameCheck(object):
-
-    def __init__(self, name):
-        self.name = name
-
-    def __eq__(self, frame):
-        return frame.pycode.co_name == self.name
-
-class BytecodeCheck(object):
-
-    def __init__(self, code, op, arg):
-        self.code = code
-        self.op = chr(op)+chr(arg & 0xff) + chr(arg >> 8 & 0xff)
-
-    def __eq__(self, pos):
-        return self.code[pos-3:pos] == self.op
-
-class BaseTestReconstructFrameChain(object):
-    OPTIONS = {}
-
-    def setup_class(cls):
-        space = gettestobjspace(usemodules=('_stackless',), **cls.OPTIONS)
-        cls.space = space
-
-        from pypy.rlib import rstack
-        cls.old_resume_state_create = rstack.resume_state_create
-
-        def tr(prevstate, label, *args):
-            if prevstate is None:
-                prevstate = []
-            return prevstate+[(label, args)]
-        rstack.resume_state_create = tr
-
-        w_opmap = space.appexec([], """():
-        import opcode
-
-        return opcode.opmap
-        """)
-
-        opmap = space.unwrap(w_opmap)
-        cls.CALL_FUNCTION = opmap['CALL_FUNCTION']
-        cls.CALL_FUNCTION_VAR = opmap['CALL_FUNCTION_VAR']
-        cls.CALL_METHOD = opmap['CALL_METHOD']
-
-        cls.callmethod = getattr(cls, cls.callmethod_label)
-
-    def teardown_class(cls):
-        from pypy.rlib import rstack
-        rstack.resume_state_create = cls.old_resume_state_create
-
-    def start(self, w_coro):
-        self.i = 0
-        self.frame_to_check = w_coro.frame
-        w_coro.frame = None # avoid exploding in kill > __del__
-
-    def end(self):
-        assert self.i == len(self.frame_to_check)
-
-    def check_entry(self, label, *args):
-        frame = self.frame_to_check
-        assert frame[self.i] == (label, args)
-        self.i += 1
-
-        
-    def test_two_frames_simple(self):
-        space = self.space
-
-        w_res = space.appexec([], """():
-        import _stackless as stackless
-        import pickle
-
-        main = stackless.coroutine.getcurrent()
-        d = {'main': main}        
-
-        exec \"\"\"
-def f():
-    g(1)
-
-def g(x):
-    main.switch()
-\"\"\" in d
-        f = d['f']
-        g = d['g']
-
-        co = stackless.coroutine()
-        co.bind(f)
-        co.switch()
-
-        s = pickle.dumps(co)
-        co = pickle.loads(s)
-
-        return co, f, g
-        """)
-
-        w_co, w_f, w_g = space.fixedview(w_res)
-
-        ec = space.getexecutioncontext()
-        fcode = w_f.code.co_code
-        gcode = w_g.code.co_code        
-
-        self.start(w_co)
-        e = self.check_entry
-        e('yield_current_frame_to_caller_1')
-        e('coroutine__bind', w_co.costate)
-        e('appthunk', w_co.costate)
-        # f
-        e('execute_frame', FrameCheck('f'), ec)
-        e('dispatch', FrameCheck('f'), fcode, ec)
-        e('handle_bytecode', FrameCheck('f'), fcode, ec)
-        e('dispatch_call', FrameCheck('f'), fcode,
-          BytecodeCheck(fcode, self.CALL_FUNCTION, 1), ec)
-        e('CALL_FUNCTION', FrameCheck('f'), 1)
-        # g
-        e('execute_frame', FrameCheck('g'), ec)
-        e('dispatch', FrameCheck('g'), gcode, ec)
-        e('handle_bytecode', FrameCheck('g'), gcode, ec)
-        e('dispatch_call', FrameCheck('g'), gcode,
-          BytecodeCheck(gcode, self.callmethod, 0), ec)
-        e(self.callmethod_label, FrameCheck('g'), 0)
-        e('w_switch', w_co.costate, space)
-        e('coroutine_switch', w_co.costate)
-        self.end()
-
-    def test_two_frames_stararg(self):
-        space = self.space
-
-        w_res = space.appexec([], """():
-        import _stackless as stackless
-        import pickle
-        
-        main = stackless.coroutine.getcurrent()
-        d = {'main': main}        
-
-        exec \"\"\"        
-def f():
-    g(4, 3, d=2, *(1,))
-
-def g(a, b, c, d):
-    main.switch()
-\"\"\" in d
-        f = d['f']
-        g = d['g']    
-
-        co = stackless.coroutine()
-        co.bind(f)
-        co.switch()
-
-        s = pickle.dumps(co)
-        co = pickle.loads(s)
-
-        return co, f, g
-        """)
-
-        w_co, w_f, w_g = space.fixedview(w_res)
-
-        ec = space.getexecutioncontext()
-        fcode = w_f.code.co_code
-        gcode = w_g.code.co_code        
-
-        self.start(w_co)
-        e = self.check_entry
-        e('yield_current_frame_to_caller_1')
-        e('coroutine__bind', w_co.costate)
-        e('appthunk', w_co.costate)
-        # f
-        e('execute_frame', FrameCheck('f'), ec)
-        e('dispatch', FrameCheck('f'), fcode, ec)
-        e('handle_bytecode', FrameCheck('f'), fcode, ec)
-        e('dispatch_call', FrameCheck('f'), fcode,
-          BytecodeCheck(fcode, self.CALL_FUNCTION_VAR, 2+(1<<8)), ec)
-        e('call_function', FrameCheck('f'))
-        # g
-        e('execute_frame', FrameCheck('g'), ec)
-        e('dispatch', FrameCheck('g'), gcode, ec)
-        e('handle_bytecode', FrameCheck('g'), gcode, ec)
-        e('dispatch_call', FrameCheck('g'), gcode,
-          BytecodeCheck(gcode, self.callmethod, 0), ec)
-        e(self.callmethod_label, FrameCheck('g'), 0)
-        e('w_switch', w_co.costate, space)
-        e('coroutine_switch', w_co.costate)
-        self.end()        
-    
-    def test_two_frames_method(self):
-        space = self.space
-
-        w_res = space.appexec([], """():
-        import _stackless as stackless
-        import pickle
-        import new, sys
-
-        mod = new.module('mod')
-        sys.modules['mod'] = mod
-        
-        main = stackless.coroutine.getcurrent()
-        d = {'main': main}        
-
-        exec \"\"\"                
-def f():
-    a = A()
-    a.m(1)
-
-def g(_, x):
-    main.switch()
-
-class A(object):
-    m = g
-\"\"\" in d
-        f = d['f']
-        g = d['g']
-        A = d['A']
-
-        # to make pickling work
-        mod.A = A
-        A.__module__ = 'mod'
-
-        co = stackless.coroutine()
-        co.bind(f)
-        co.switch()
-
-        s = pickle.dumps(co)
-        co = pickle.loads(s)
-
-        return co, f, g
-        """)
-
-        w_co, w_f, w_g = space.fixedview(w_res)
-
-        ec = space.getexecutioncontext()
-        fcode = w_f.code.co_code
-        gcode = w_g.code.co_code        
-
-        self.start(w_co)
-        e = self.check_entry
-        e('yield_current_frame_to_caller_1')
-        e('coroutine__bind', w_co.costate)
-        e('appthunk', w_co.costate)
-        # f
-        e('execute_frame', FrameCheck('f'), ec)
-        e('dispatch', FrameCheck('f'), fcode, ec)
-        e('handle_bytecode', FrameCheck('f'), fcode, ec)
-        e('dispatch_call', FrameCheck('f'), fcode,
-          BytecodeCheck(fcode, self.callmethod, 1), ec)
-        e(self.callmethod_label, FrameCheck('f'), 1)
-        # g
-        e('execute_frame', FrameCheck('g'), ec)
-        e('dispatch', FrameCheck('g'), gcode, ec)
-        e('handle_bytecode', FrameCheck('g'), gcode, ec)
-        e('dispatch_call', FrameCheck('g'), gcode,
-          BytecodeCheck(gcode, self.callmethod, 0), ec)
-        e(self.callmethod_label, FrameCheck('g'), 0)
-        e('w_switch', w_co.costate, space)
-        e('coroutine_switch', w_co.costate)
-        self.end()
-
-class TestReconstructFrameChain(BaseTestReconstructFrameChain):
-    callmethod_label = 'CALL_FUNCTION'
-
-class TestReconstructFrameChain_CALL_METHOD(BaseTestReconstructFrameChain):
-    OPTIONS = {"objspace.opcodes.CALL_METHOD": True,
-               }
-
-    callmethod_label = 'CALL_METHOD'
-
-                
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
@@ -73,29 +73,29 @@
                 rffi.charp2str(self.ml.c_ml_name) + "() takes no keyword arguments"))
 
         func = rffi.cast(PyCFunction, self.ml.c_ml_meth)
+        length = space.int_w(space.len(w_args))
         if flags & METH_KEYWORDS:
             func = rffi.cast(PyCFunctionKwArgs, self.ml.c_ml_meth)
             return generic_cpy_call(space, func, w_self, w_args, w_kw)
         elif flags & METH_NOARGS:
-            if len(w_args.wrappeditems) == 0:
+            if length == 0:
                 return generic_cpy_call(space, func, w_self, None)
             raise OperationError(space.w_TypeError, space.wrap(
                 rffi.charp2str(self.ml.c_ml_name) + "() takes no arguments"))
         elif flags & METH_O:
-            assert isinstance(w_args, W_TupleObject)
-            if len(w_args.wrappeditems) != 1:
+            if length != 1:
                 raise OperationError(space.w_TypeError,
                         space.wrap("%s() takes exactly one argument (%d given)" %  (
                         rffi.charp2str(self.ml.c_ml_name), 
-                        len(w_args.wrappeditems))))
-            w_arg = w_args.wrappeditems[0]
+                        length)))
+            w_arg = space.getitem(w_args, space.wrap(0))
             return generic_cpy_call(space, func, w_self, w_arg)
         elif flags & METH_VARARGS:
             return generic_cpy_call(space, func, w_self, w_args)
         else: # METH_OLDARGS, the really old style
-            size = len(w_args.wrappeditems)
+            size = length
             if size == 1:
-                w_arg = w_args.wrappeditems[0]
+                w_arg = space.getitem(w_args, space.wrap(0))
             elif size == 0:
                 w_arg = None
             else:
diff --git a/pypy/module/cpyext/test/test_tupleobject.py b/pypy/module/cpyext/test/test_tupleobject.py
--- a/pypy/module/cpyext/test/test_tupleobject.py
+++ b/pypy/module/cpyext/test/test_tupleobject.py
@@ -3,8 +3,10 @@
 from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref
 from pypy.module.cpyext.test.test_api import BaseApiTest
 from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.conftest import gettestobjspace
 
 class TestTupleObject(BaseApiTest):
+
     def test_tupleobject(self, space, api):
         assert not api.PyTuple_Check(space.w_None)
         assert api.PyTuple_SetItem(space.w_None, 0, space.w_None) == -1
@@ -20,11 +22,23 @@
         ar[0] = rffi.cast(PyObject, make_ref(space, py_tuple))
         api._PyTuple_Resize(ar, 2)
         py_tuple = from_ref(space, ar[0])
-        assert len(py_tuple.wrappeditems) == 2
+        assert space.int_w(space.len(py_tuple)) == 2
         
         api._PyTuple_Resize(ar, 10)
         py_tuple = from_ref(space, ar[0])
-        assert len(py_tuple.wrappeditems) == 10
+        assert space.int_w(space.len(py_tuple)) == 10
         
         api.Py_DecRef(ar[0])
         lltype.free(ar, flavor='raw')
+
+    def test_setitem(self, space, api):
+        atuple = space.newtuple([space.wrap(0), space.wrap("hello")])
+        assert api.PyTuple_Size(atuple) == 2
+        assert space.eq_w(space.getitem(atuple, space.wrap(0)), space.wrap(0))
+        assert space.eq_w(space.getitem(atuple, space.wrap(1)), space.wrap("hello"))
+        w_obj = space.wrap(1)
+        api.Py_IncRef(w_obj)
+        api.PyTuple_SetItem(atuple, 1, w_obj)
+        assert api.PyTuple_Size(atuple) == 2
+        assert space.eq_w(space.getitem(atuple, space.wrap(0)), space.wrap(0))
+        assert space.eq_w(space.getitem(atuple, space.wrap(1)), space.wrap(1))
diff --git a/pypy/module/cpyext/tupleobject.py b/pypy/module/cpyext/tupleobject.py
--- a/pypy/module/cpyext/tupleobject.py
+++ b/pypy/module/cpyext/tupleobject.py
@@ -6,7 +6,7 @@
     borrow_from, make_ref, from_ref)
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
 from pypy.objspace.std.tupleobject import W_TupleObject
-
+from pypy.objspace.std.smalltupleobject import W_SmallTupleObject
 
 PyTuple_Check, PyTuple_CheckExact = build_type_checkers("Tuple")
 
@@ -19,25 +19,30 @@
     if not PyTuple_Check(space, w_t):
         # XXX this should also steal a reference, test it!!!
         PyErr_BadInternalCall(space)
-    assert isinstance(w_t, W_TupleObject)
-    w_t.wrappeditems[pos] = w_obj
+    _setitem_tuple(w_t, pos, w_obj)
     Py_DecRef(space, w_obj) # SetItem steals a reference!
     return 0
 
+def _setitem_tuple(w_t, pos, w_obj):
+    if isinstance(w_t, W_TupleObject):
+        w_t.wrappeditems[pos] = w_obj
+    elif isinstance(w_t, W_SmallTupleObject):
+        w_t.setitem(pos, w_obj)
+    else:
+        assert False
+
 @cpython_api([PyObject, Py_ssize_t], PyObject)
 def PyTuple_GetItem(space, w_t, pos):
     if not PyTuple_Check(space, w_t):
         PyErr_BadInternalCall(space)
-    assert isinstance(w_t, W_TupleObject)
-    w_obj = w_t.wrappeditems[pos]
+    w_obj = space.getitem(w_t, space.wrap(pos))
     return borrow_from(w_t, w_obj)
 
 @cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
 def PyTuple_GET_SIZE(space, w_t):
     """Return the size of the tuple p, which must be non-NULL and point to a tuple;
     no error checking is performed. """
-    assert isinstance(w_t, W_TupleObject)
-    return len(w_t.wrappeditems)
+    return space.int_w(space.len(w_t))
 
 @cpython_api([PyObject], Py_ssize_t, error=-1)
 def PyTuple_Size(space, ref):
@@ -63,15 +68,14 @@
     py_tuple = from_ref(space, ref[0])
     if not PyTuple_Check(space, py_tuple):
         PyErr_BadInternalCall(space)
-    assert isinstance(py_tuple, W_TupleObject)
     py_newtuple = PyTuple_New(space, newsize)
     
     to_cp = newsize
-    oldsize = len(py_tuple.wrappeditems)
+    oldsize = space.int_w(space.len(py_tuple))
     if oldsize < newsize:
         to_cp = oldsize
     for i in range(to_cp):
-        py_newtuple.wrappeditems[i] = py_tuple.wrappeditems[i]
+        _setitem_tuple(py_newtuple, i, space.getitem(py_tuple, space.wrap(i)))
     Py_DecRef(space, ref[0])
     ref[0] = make_ref(space, py_newtuple)
     return 0
diff --git a/pypy/module/oracle/interp_variable.py b/pypy/module/oracle/interp_variable.py
--- a/pypy/module/oracle/interp_variable.py
+++ b/pypy/module/oracle/interp_variable.py
@@ -601,6 +601,7 @@
     def getValueProc(self, space, pos):
         ptr = rffi.ptradd(self.data, pos * self.bufferSize)
         length = rffi.cast(roci.Ptr(roci.ub4), ptr)[0]
+        length = rffi.cast(lltype.Signed, length)
 
         ptr = rffi.ptradd(ptr, rffi.sizeof(roci.ub4))
         return space.wrap(rffi.charpsize2str(ptr, length))
diff --git a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
--- a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
@@ -270,9 +270,8 @@
             i17 = int_add_ovf(i8, 1)
             guard_no_overflow(descr=<Guard5>)
             i18 = force_token()
-            i20 = int_sub(i17, 1)
             --TICK--
-            jump(p0, p1, p2, p3, p4, p5, i20, p7, i17, i9, p10, p11, p12, descr=<Loop0>)
+            jump(p0, p1, p2, p3, p4, p5, i8, p7, i17, i9, p10, p11, p12, descr=<Loop0>)
         """)
 
     def test_default_and_kw(self):
@@ -481,10 +480,14 @@
         assert log.result == (1000, 998)
         loop, = log.loops_by_filename(self.filepath)
         assert loop.match_by_id('append', """
-            p14 = new_with_vtable(ConstClass(W_IntObject))
-            setfield_gc(p14, i12, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
-            call(ConstClass(ll_append__listPtr_objectPtr), p8, p14, descr=...)
+            i13 = getfield_gc(p8, descr=<SignedFieldDescr list.length .*>)
+            i15 = int_add(i13, 1)
+            call(ConstClass(_ll_list_resize_ge__listPtr_Signed), p8, i15, descr=<VoidCallDescr>)
             guard_no_exception(descr=<Guard4>)
+            p17 = getfield_gc(p8, descr=<GcPtrFieldDescr list.items .*>)
+            p19 = new_with_vtable(ConstClass(W_IntObject))
+            setfield_gc(p19, i12, descr=<SignedFieldDescr .*W_IntObject.inst_intval .*>)
+            setarrayitem_gc(p17, i13, p19, descr=<GcPtrArrayDescr>)
         """)
 
     def test_range_iter(self):
@@ -1727,4 +1730,4 @@
             # few instructions
             loop.match_by_id("contains", """
                 i1 = int_add(i0, 1)
-            """)
\ No newline at end of file
+            """)
diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py
--- a/pypy/module/sys/vm.py
+++ b/pypy/module/sys/vm.py
@@ -43,21 +43,20 @@
     return space.wrap(f)
 
 def setrecursionlimit(space, w_new_limit):
-    """setrecursionlimit() is ignored (and not needed) on PyPy.
-
-On CPython it would set the maximum number of nested calls that can
-occur before a RuntimeError is raised.  On PyPy overflowing the stack
-also causes RuntimeErrors, but the limit is checked at a lower level.
-(The limit is currenty hard-coded at 768 KB, corresponding to roughly
-1480 Python calls on Linux.)"""
+    """setrecursionlimit() sets the maximum number of nested calls that
+can occur before a RuntimeError is raised.  On PyPy the limit is
+approximative and checked at a lower level.  The default 1000
+reserves 768KB of stack space, which should suffice (on Linux,
+depending on the compiler settings) for ~1400 calls.  Setting the
+value to N reserves N/1000 times 768KB of stack space.
+"""
+    from pypy.rlib.rstack import _stack_set_length_fraction
     new_limit = space.int_w(w_new_limit)
     if new_limit <= 0:
         raise OperationError(space.w_ValueError,
                              space.wrap("recursion limit must be positive"))
-    # for now, don't rewrite a warning but silently ignore the
-    # recursion limit.
-    #space.warn('setrecursionlimit() is ignored (and not needed) on PyPy', space.w_RuntimeWarning)
     space.sys.recursionlimit = new_limit
+    _stack_set_length_fraction(new_limit * 0.001)
 
 def getrecursionlimit(space):
     """Return the last value set by setrecursionlimit().
diff --git a/pypy/module/test_lib_pypy/test_stackless.py b/pypy/module/test_lib_pypy/test_stackless.py
--- a/pypy/module/test_lib_pypy/test_stackless.py
+++ b/pypy/module/test_lib_pypy/test_stackless.py
@@ -8,15 +8,12 @@
         space = gettestobjspace(usemodules=('_stackless', '_socket'))
         cls.space = space
         # cannot test the unpickle part on top of py.py
-        cls.w_can_unpickle = space.wrap(bool(option.runappdirect))
 
     def test_pickle(self):
         import new, sys
 
         mod = new.module('mod')
         sys.modules['mod'] = mod
-        mod.can_unpickle = self.can_unpickle
-        mod.skip = skip
         try:
             exec '''
 import pickle, sys
@@ -45,8 +42,6 @@
 t = stackless.tasklet(demo)(lev)
 stackless.run()
 assert seen == range(1, lev+1) + range(lev, 0, -1)
-if not can_unpickle:
-    skip("cannot test the unpickling part on top of py.py")
 print "now running the clone"
 tt = pickle.loads(blob)
 tt.insert()
@@ -64,8 +59,6 @@
 
         mod = new.module('mod')
         sys.modules['mod'] = mod
-        mod.can_unpickle = self.can_unpickle
-        mod.skip = skip
         try:
             exec '''
 import pickle, sys
diff --git a/pypy/module/test_lib_pypy/test_tputil.py b/pypy/module/test_lib_pypy/test_tputil.py
--- a/pypy/module/test_lib_pypy/test_tputil.py
+++ b/pypy/module/test_lib_pypy/test_tputil.py
@@ -28,9 +28,9 @@
         from tputil import make_proxy 
         l = []
         tp = make_proxy(l.append, type=list)
-        x = len(tp)
+        x = tp[0:1]
         assert len(l) == 1
-        assert l[0].opname == '__len__'
+        assert l[0].opname == '__getslice__'
        
     def test_simple(self):
         from tputil import make_proxy 
diff --git a/pypy/objspace/descroperation.py b/pypy/objspace/descroperation.py
--- a/pypy/objspace/descroperation.py
+++ b/pypy/objspace/descroperation.py
@@ -207,35 +207,51 @@
         return space.get_and_call_function(w_descr, w_obj, w_name)
 
     def is_true(space, w_obj):
-        w_descr = space.lookup(w_obj, '__nonzero__')
+        method = "__nonzero__"
+        w_descr = space.lookup(w_obj, method)
         if w_descr is None:
-            w_descr = space.lookup(w_obj, '__len__')
+            method = "__len__"
+            w_descr = space.lookup(w_obj, method)
             if w_descr is None:
                 return True
         w_res = space.get_and_call_function(w_descr, w_obj)
         # more shortcuts for common cases
-        if w_res is space.w_False:
+        if space.is_w(w_res, space.w_False):
             return False
-        if w_res is space.w_True:
+        if space.is_w(w_res, space.w_True):
             return True
         w_restype = space.type(w_res)
-        if (space.is_w(w_restype, space.w_bool) or
-            space.is_w(w_restype, space.w_int) or
+        # Note there is no check for bool here because the only possible
+        # instances of bool are w_False and w_True, which are checked above.
+        if (space.is_w(w_restype, space.w_int) or
             space.is_w(w_restype, space.w_long)):
             return space.int_w(w_res) != 0
         else:
-            raise OperationError(space.w_TypeError,
-                                 space.wrap('__nonzero__ should return '
-                                            'bool or integer'))
+            msg = "%s should return bool or integer" % (method,)
+            raise OperationError(space.w_TypeError, space.wrap(msg))
 
-    def nonzero(self, w_obj):
-        if self.is_true(w_obj):
-            return self.w_True
+    def nonzero(space, w_obj):
+        if space.is_true(w_obj):
+            return space.w_True
         else:
-            return self.w_False
+            return space.w_False
 
-##    def len(self, w_obj):
-##        XXX needs to check that the result is an int (or long?) >= 0
+    def len(space, w_obj):
+        w_descr = space.lookup(w_obj, '__len__')
+        if w_descr is None:
+            name = space.type(w_obj).getname(space)
+            msg = "'%s' has no length" % (name,)
+            raise OperationError(space.w_TypeError, space.wrap(msg))
+        w_res = space.get_and_call_function(w_descr, w_obj)
+        space._check_len_result(w_res)
+        return w_res
+
+    def _check_len_result(space, w_obj):
+        # Will complain if result is too big.
+        result = space.int_w(w_obj)
+        if result < 0:
+            raise OperationError(space.w_ValueError,
+                                 space.wrap("__len__() should return >= 0"))
 
     def iter(space, w_obj):
         w_descr = space.lookup(w_obj, '__iter__')
diff --git a/pypy/objspace/std/callmethod.py b/pypy/objspace/std/callmethod.py
--- a/pypy/objspace/std/callmethod.py
+++ b/pypy/objspace/std/callmethod.py
@@ -12,7 +12,7 @@
 
 from pypy.interpreter import function
 from pypy.objspace.descroperation import object_getattribute
-from pypy.rlib import jit, rstack # for resume points
+from pypy.rlib import jit
 from pypy.objspace.std.mapdict import LOOKUP_METHOD_mapdict, \
     LOOKUP_METHOD_mapdict_fill_cache_method
 
@@ -84,7 +84,6 @@
         w_callable = f.peekvalue(n_args + (2 * n_kwargs) + 1)
         try:
             w_result = f.space.call_valuestack(w_callable, n, f)
-            rstack.resume_point("CALL_METHOD", f, n_args, returns=w_result)
         finally:
             f.dropvalues(n_args + 2)
     else:
@@ -109,7 +108,6 @@
             w_result = f.space.call_args_and_c_profile(f, w_callable, args)
         else:
             w_result = f.space.call_args(w_callable, args)
-        rstack.resume_point("CALL_METHOD_KW", f, returns=w_result)
     f.pushvalue(w_result)
 
 
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
@@ -15,6 +15,7 @@
     _registered_implementations.add(implcls)
 
 option_to_typename = {
+    "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"],
     "withsmallint"   : ["smallintobject.W_SmallIntObject"],
     "withsmalllong"  : ["smalllongobject.W_SmallLongObject"],
     "withstrslice"   : ["strsliceobject.W_StringSliceObject"],
@@ -71,6 +72,7 @@
         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
@@ -253,6 +255,9 @@
                 (listobject.W_ListObject,
                                        rangeobject.delegate_range2list),
                 ]
+        if config.objspace.std.withsmalltuple:
+            self.typeorder[smalltupleobject.W_SmallTupleObject] += [
+                (tupleobject.W_TupleObject, smalltupleobject.delegate_SmallTuple2Tuple)]
 
         # put W_Root everywhere
         self.typeorder[W_Root] = []
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
@@ -296,9 +296,10 @@
         return newlong(self, val)
 
     def newtuple(self, list_w):
+        from pypy.objspace.std.tupletype import wraptuple
         assert isinstance(list_w, list)
         make_sure_not_resized(list_w)
-        return W_TupleObject(list_w)
+        return wraptuple(self, list_w)
 
     def newlist(self, list_w):
         return W_ListObject(list_w)
diff --git a/pypy/objspace/std/smalltupleobject.py b/pypy/objspace/std/smalltupleobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/smalltupleobject.py
@@ -0,0 +1,157 @@
+from pypy.interpreter.error import OperationError
+from pypy.objspace.std.model import registerimplementation, W_Object
+from pypy.objspace.std.register_all import register_all
+from pypy.objspace.std.inttype import wrapint
+from pypy.objspace.std.multimethod import FailedToImplement
+from pypy.rlib.rarithmetic import intmask
+from pypy.objspace.std.sliceobject import W_SliceObject, normalize_simple_slice
+from pypy.objspace.std import slicetype
+from pypy.interpreter import gateway
+from pypy.rlib.debug import make_sure_not_resized
+from pypy.rlib.unroll import unrolling_iterable
+from pypy.objspace.std.tupleobject import W_TupleObject
+
+class W_SmallTupleObject(W_Object):
+    from pypy.objspace.std.tupletype import tuple_typedef as typedef
+
+    def tolist(self):
+        raise NotImplementedError
+
+    def length(self):
+        raise NotImplementedError
+
+    def getitem(self, index):
+        raise NotImplementedError
+
+    def hash(self, space):
+        raise NotImplementedError
+
+    def eq(self, space, w_other):
+        raise NotImplementedError
+
+    def setitem(self, index, w_item):
+        raise NotImplementedError
+
+    def unwrap(w_tuple, space):
+        items = [space.unwrap(w_item) for w_item in w_tuple.tolist()]
+        return tuple(items)
+
+def make_specialized_class(n):
+    iter_n = unrolling_iterable(range(n))
+    class cls(W_SmallTupleObject):
+
+        def __init__(self, values):
+            assert len(values) == n
+            for i in iter_n:
+                setattr(self, 'w_value%s' % i, values[i])
+
+        def tolist(self):
+            l = [None] * n
+            for i in iter_n:
+                l[i] = getattr(self, 'w_value%s' % i)
+            return l
+
+        def length(self):
+            return n
+
+        def getitem(self, index):
+            for i in iter_n:
+                if index == i:
+                    return getattr(self,'w_value%s' % i)
+            raise IndexError
+
+        def setitem(self, index, w_item):
+            for i in iter_n:
+                if index == i:
+                    setattr(self, 'w_value%s' % i, w_item)
+                    return
+            raise IndexError
+
+        def eq(self, space, w_other):
+            if self.length() != w_other.length():
+                return space.w_False
+            for i in iter_n:
+                item1 = self.getitem(i)
+                item2 = w_other.getitem(i)
+                if not space.eq_w(item1, item2):
+                    return space.w_False
+            return space.w_True
+
+        def hash(self, space):
+            mult = 1000003
+            x = 0x345678
+            z = self.length()
+            for i in iter_n:
+                w_item = self.getitem(i)
+                y = space.int_w(space.hash(w_item))
+                x = (x ^ y) * mult
+                z -= 1
+                mult += 82520 + z + z
+            x += 97531
+            return space.wrap(intmask(x))
+
+    cls.__name__ = "W_SmallTupleObject%s" % n
+    return cls
+
+W_SmallTupleObject2 = make_specialized_class(2)
+W_SmallTupleObject3 = make_specialized_class(3)
+W_SmallTupleObject4 = make_specialized_class(4)
+W_SmallTupleObject5 = make_specialized_class(5)
+W_SmallTupleObject6 = make_specialized_class(6)
+W_SmallTupleObject7 = make_specialized_class(7)
+W_SmallTupleObject8 = make_specialized_class(8)
+
+registerimplementation(W_SmallTupleObject)
+
+def delegate_SmallTuple2Tuple(space, w_small):
+    return W_TupleObject(w_small.tolist())
+
+def len__SmallTuple(space, w_tuple):
+    return space.wrap(w_tuple.length())
+
+def getitem__SmallTuple_ANY(space, w_tuple, w_index):
+    index = space.getindex_w(w_index, space.w_IndexError, "tuple index")
+    if index < 0:
+        index += w_tuple.length()
+    try:
+        return w_tuple.getitem(index)
+    except IndexError:
+        raise OperationError(space.w_IndexError,
+                             space.wrap("tuple index out of range"))
+
+def getitem__SmallTuple_Slice(space, w_tuple, w_slice):
+    length = w_tuple.length()
+    start, stop, step, slicelength = w_slice.indices4(space, length)
+    assert slicelength >= 0
+    subitems = [None] * slicelength
+    for i in range(slicelength):
+        subitems[i] = w_tuple.getitem(start)
+        start += step
+    return space.newtuple(subitems)
+
+def mul_smalltuple_times(space, w_tuple, w_times):
+    try:
+        times = space.getindex_w(w_times, space.w_OverflowError)
+    except OperationError, e:
+        if e.match(space, space.w_TypeError):
+            raise FailedToImplement
+        raise
+    if times == 1 and space.type(w_tuple) == space.w_tuple:
+        return w_tuple
+    items = w_tuple.tolist()
+    return space.newtuple(items * times)
+
+def mul__SmallTuple_ANY(space, w_tuple, w_times):
+    return mul_smalltuple_times(space, w_tuple, w_times)
+
+def mul__ANY_SmallTuple(space, w_times, w_tuple):
+    return mul_smalltuple_times(space, w_tuple, w_times)
+
+def eq__SmallTuple_SmallTuple(space, w_tuple1, w_tuple2):
+    return w_tuple1.eq(space, w_tuple2)
+
+def hash__SmallTuple(space, w_tuple):
+    return w_tuple.hash(space)
+
+from pypy.objspace.std import tupletype
+register_all(vars(), tupletype)
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
@@ -252,15 +252,30 @@
 
     res_w = []
     start = 0
-    while maxsplit != 0:
-        next = value.find(by, start)
-        if next < 0:
-            break
-        res_w.append(sliced(space, value, start, next, w_self))
-        start = next + bylen
-        maxsplit -= 1   # NB. if it's already < 0, it stays < 0
+    if bylen == 1 and maxsplit < 0:
+        # fast path: uses str.rfind(character) and str.count(character)
+        by = by[0]    # annotator hack: string -> char
+        count = value.count(by)
+        res_w = [None] * (count + 1)
+        end = len(value)
+        while count >= 0:
+            assert end >= 0
+            prev = value.rfind(by, 0, end)
+            start = prev + 1
+            assert start >= 0
+            res_w[count] = sliced(space, value, start, end, w_self)
+            count -= 1
+            end = prev
+    else:
+        while maxsplit != 0:
+            next = value.find(by, start)
+            if next < 0:
+                break
+            res_w.append(sliced(space, value, start, next, w_self))
+            start = next + bylen
+            maxsplit -= 1   # NB. if it's already < 0, it stays < 0
+        res_w.append(sliced(space, value, start, len(value), w_self))
 
-    res_w.append(sliced(space, value, start, len(value), w_self))
     return space.newlist(res_w)
 
 def str_rsplit__String_None_ANY(space, w_self, w_none, w_maxsplit=-1):
diff --git a/pypy/objspace/std/test/test_smalltupleobject.py b/pypy/objspace/std/test/test_smalltupleobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/test/test_smalltupleobject.py
@@ -0,0 +1,86 @@
+from pypy.objspace.std.tupleobject import W_TupleObject
+from pypy.objspace.std.smalltupleobject import W_SmallTupleObject
+from pypy.interpreter.error import OperationError
+from pypy.objspace.std.test.test_tupleobject import AppTestW_TupleObject
+from pypy.conftest import gettestobjspace
+
+class AppTestW_SmallTupleObject(AppTestW_TupleObject):
+
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withsmalltuple": True})
+        cls.w_issmall = cls.space.appexec([], """():
+            import __pypy__
+            def issmall(obj):
+                assert "SmallTuple" in __pypy__.internal_repr(obj)
+            return issmall
+        """)
+
+    def test_smalltuple(self):
+        self.issmall((1,2))
+        self.issmall((1,2,3))
+
+    def test_slicing_to_small(self):
+        self.issmall((1, 2, 3)[0:2])    # SmallTuple2
+        self.issmall((1, 2, 3)[0:2:1])
+
+        self.issmall((1, 2, 3, 4)[0:3])    # SmallTuple3
+        self.issmall((1, 2, 3, 4)[0:3:1])
+
+    def test_adding_to_small(self):
+        self.issmall((1,)+(2,))       # SmallTuple2
+        self.issmall((1,1)+(2,))      # SmallTuple3
+        self.issmall((1,)+(2,3))
+
+    def test_multiply_to_small(self):
+        self.issmall((1,)*2)
+        self.issmall((1,)*3)
+
+    def test_slicing_from_small(self):
+        assert (1,2)[0:1:1] == (1,)
+        assert (1,2,3)[0:2:1] == (1,2)
+
+    def test_eq(self):
+        a = (1,2,3)
+        b = (1,2,3)
+        assert a == b
+
+        c = (1,3,2)
+        assert a != c
+
+    def test_hash(self):
+        a = (1,2,3)
+        b = (1,2,3)
+        assert hash(a) == hash(b)
+
+        c = (1,3,2)
+        assert hash(a) != hash(c)
+
+class TestW_SmallTupleObject():
+
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withsmalltuple": True})
+
+    def test_issmalltupleobject(self):
+        w_tuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)])
+        assert isinstance(w_tuple, W_SmallTupleObject)
+
+    def test_hash_agains_normal_tuple(self):
+        normalspace = gettestobjspace(**{"objspace.std.withsmalltuple": False})
+        w_tuple = normalspace.newtuple([self.space.wrap(1), self.space.wrap(2)])
+
+        smallspace = gettestobjspace(**{"objspace.std.withsmalltuple": True})
+        w_smalltuple = smallspace.newtuple([self.space.wrap(1), self.space.wrap(2)])
+
+        assert isinstance(w_smalltuple, W_SmallTupleObject)
+        assert isinstance(w_tuple, W_TupleObject)
+        assert not normalspace.is_true(normalspace.eq(w_tuple, w_smalltuple))
+        assert smallspace.is_true(smallspace.eq(w_tuple, w_smalltuple))
+        assert smallspace.is_true(smallspace.eq(normalspace.hash(w_tuple), smallspace.hash(w_smalltuple)))
+
+    def test_setitem(self):
+        w_smalltuple = self.space.newtuple([self.space.wrap(1), self.space.wrap(2)])
+        w_smalltuple.setitem(0, self.space.wrap(5))
+        list_w = w_smalltuple.tolist()
+        assert len(list_w) == 2
+        assert self.space.eq_w(list_w[0], self.space.wrap(5))
+        assert self.space.eq_w(list_w[1], self.space.wrap(2))
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
@@ -23,7 +23,7 @@
         return "%s(%s)" % (w_self.__class__.__name__, ', '.join(reprlist))
 
     def unwrap(w_tuple, space):
-        items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems] # XXX generic mixed types unwrap
+        items = [space.unwrap(w_item) for w_item in w_tuple.wrappeditems]
         return tuple(items)
 
 registerimplementation(W_TupleObject)
@@ -56,12 +56,12 @@
     for i in range(slicelength):
         subitems[i] = items[start]
         start += step
-    return W_TupleObject(subitems)
+    return space.newtuple(subitems)
 
 def getslice__Tuple_ANY_ANY(space, w_tuple, w_start, w_stop):
     length = len(w_tuple.wrappeditems)
     start, stop = normalize_simple_slice(space, length, w_start, w_stop)
-    return W_TupleObject(w_tuple.wrappeditems[start:stop])
+    return space.newtuple(w_tuple.wrappeditems[start:stop])
 
 def contains__Tuple_ANY(space, w_tuple, w_obj):
     for w_item in w_tuple.wrappeditems:
@@ -76,7 +76,7 @@
 def add__Tuple_Tuple(space, w_tuple1, w_tuple2):
     items1 = w_tuple1.wrappeditems
     items2 = w_tuple2.wrappeditems
-    return W_TupleObject(items1 + items2)
+    return space.newtuple(items1 + items2)
 
 def mul_tuple_times(space, w_tuple, w_times):
     try:
@@ -88,7 +88,7 @@
     if times == 1 and space.type(w_tuple) == space.w_tuple:
         return w_tuple
     items = w_tuple.wrappeditems
-    return W_TupleObject(items * times)
+    return space.newtuple(items * times)
 
 def mul__Tuple_ANY(space, w_tuple, w_times):
     return mul_tuple_times(space, w_tuple, w_times)
@@ -162,7 +162,7 @@
     return intmask(x)
 
 def getnewargs__Tuple(space, w_tuple):
-    return space.newtuple([W_TupleObject(w_tuple.wrappeditems)])
+    return space.newtuple([space.newtuple(w_tuple.wrappeditems)])
 
 def tuple_count__Tuple_ANY(space, w_tuple, w_obj):
     count = 0
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
@@ -3,6 +3,31 @@
 from pypy.objspace.std.register_all import register_all
 from pypy.objspace.std.stdtypedef import StdTypeDef, SMM
 
+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:
+        if len(list_w) == 2:
+            return W_SmallTupleObject2(list_w)
+        if len(list_w) == 3:
+            return W_SmallTupleObject3(list_w)
+        if len(list_w) == 4:
+            return W_SmallTupleObject4(list_w)
+        if len(list_w) == 5:
+            return W_SmallTupleObject5(list_w)
+        if len(list_w) == 6:
+            return W_SmallTupleObject6(list_w)
+        if len(list_w) == 7:
+            return W_SmallTupleObject7(list_w)
+        if len(list_w) == 8:
+            return W_SmallTupleObject8(list_w)
+    return W_TupleObject(list_w)
 
 tuple_count = SMM("count", 2,
                   doc="count(obj) -> number of times obj appears in the tuple")
diff --git a/pypy/objspace/test/test_descroperation.py b/pypy/objspace/test/test_descroperation.py
--- a/pypy/objspace/test/test_descroperation.py
+++ b/pypy/objspace/test/test_descroperation.py
@@ -532,5 +532,23 @@
         del X.__nonzero__
         assert X()
 
+    def test_len_overflow(self):
+        import sys
+        class X(object):
+            def __len__(self):
+                return sys.maxsize + 1
+        raises(OverflowError, len, X())
+
+    def test_len_underflow(self):
+        import sys
+        class X(object):
+            def __len__(self):
+                return -1
+        raises(ValueError, len, X())
+        class Y(object):
+            def __len__(self):
+                return -1L
+        raises(ValueError, len, Y())
+
 class AppTestWithBuiltinShortcut(AppTest_Descroperation):
     OPTIONS = {'objspace.std.builtinshortcut': True}
diff --git a/pypy/rlib/rbigint.py b/pypy/rlib/rbigint.py
--- a/pypy/rlib/rbigint.py
+++ b/pypy/rlib/rbigint.py
@@ -1345,6 +1345,7 @@
 # XXX make sure that we don't ignore this!
 # YYY no, we decided to do ignore this!
 
+ at jit.dont_look_inside
 def _AsDouble(n):
     """ Get a C double from a bigint object. """
     # This is a "correctly-rounded" version from Python 2.7.
diff --git a/pypy/rlib/rcoroutine.py b/pypy/rlib/rcoroutine.py
--- a/pypy/rlib/rcoroutine.py
+++ b/pypy/rlib/rcoroutine.py
@@ -29,7 +29,7 @@
 The type of a switch is determined by the target's costate.
 """
 
-from pypy.rlib.rstack import yield_current_frame_to_caller, resume_point
+from pypy.rlib.rstack import yield_current_frame_to_caller
 from pypy.rlib.objectmodel import we_are_translated
 
 from pypy.interpreter.error import OperationError
@@ -228,7 +228,6 @@
                         self.thunk = None
                         syncstate.switched(incoming_frame)
                         thunk.call()
-                        resume_point("coroutine__bind", state)
                     except Exception, e:
                         exc = e
                         raise
@@ -257,7 +256,6 @@
                 raise CoroutineDamage
             state = self.costate
             incoming_frame = state.update(self).switch()
-            resume_point("coroutine_switch", state, returns=incoming_frame)
             syncstate.switched(incoming_frame)
 
         def kill(self):
diff --git a/pypy/rlib/rstack.py b/pypy/rlib/rstack.py
--- a/pypy/rlib/rstack.py
+++ b/pypy/rlib/rstack.py
@@ -42,15 +42,19 @@
                            sandboxsafe=True, _nowrapper=True,
                            _callable=_callable)
 
-_stack_get_start = llexternal('LL_stack_get_start', [], lltype.Signed,
-                              lambda: 0)
+_stack_get_end = llexternal('LL_stack_get_end', [], lltype.Signed,
+                            lambda: 0)
 _stack_get_length = llexternal('LL_stack_get_length', [], lltype.Signed,
                                lambda: 1)
+_stack_set_length_fraction = llexternal('LL_stack_set_length_fraction',
+                                        [lltype.Float], lltype.Void,
+                                        lambda frac: None)
 _stack_too_big_slowpath = llexternal('LL_stack_too_big_slowpath',
                                      [lltype.Signed], lltype.Char,
                                      lambda cur: '\x00')
 # the following is used by the JIT
-_stack_get_start_adr = llexternal('LL_stack_get_start_adr', [], lltype.Signed)
+_stack_get_end_adr   = llexternal('LL_stack_get_end_adr',   [], lltype.Signed)
+_stack_get_length_adr= llexternal('LL_stack_get_length_adr',[], lltype.Signed)
 
 
 def stack_check():
@@ -62,13 +66,13 @@
     current = llop.stack_current(lltype.Signed)
     #
     # Load these variables from C code
-    start = _stack_get_start()
+    end = _stack_get_end()
     length = _stack_get_length()
     #
-    # Common case: if 'current' is within [start:start+length], everything
+    # Common case: if 'current' is within [end-length:end], everything
     # is fine
-    ofs = r_uint(current - start)
-    if ofs < r_uint(length):
+    ofs = r_uint(end - current)
+    if ofs <= r_uint(length):
         return
     #
     # Else call the slow path
@@ -140,111 +144,6 @@
         return var
 
 
-def resume_point(label, *args, **kwds):
-    pass
-
-
-
-class ResumePointFnEntry(ExtRegistryEntry):
-    _about_ = resume_point
-
-    def compute_result_annotation(self, s_label, *args_s, **kwds_s):
-        from pypy.annotation import model as annmodel
-        return annmodel.s_None
-
-    def specialize_call(self, hop, **kwds_i):
-        from pypy.rpython.lltypesystem import lltype
-        from pypy.objspace.flow import model
-
-        assert hop.args_s[0].is_constant()
-        c_label = hop.inputconst(lltype.Void, hop.args_s[0].const)
-        args_v = hop.args_v[1:]
-        if 'i_returns' in kwds_i:
-            assert len(kwds_i) == 1
-            returns_index = kwds_i['i_returns']
-            v_return = args_v.pop(returns_index-1)
-            assert isinstance(v_return, model.Variable), \
-                   "resume_point returns= argument must be a Variable"
-        else:
-            assert not kwds_i
-            v_return = hop.inputconst(lltype.Void, None)
-
-        for v in args_v:
-            assert isinstance(v, model.Variable), "resume_point arguments must be Variables"
-
-        hop.exception_is_here()
-        return hop.genop('resume_point', [c_label, v_return] + args_v,
-                         hop.r_result)
-
-def resume_state_create(prevstate, label, *args):
-    raise RuntimeError("cannot resume states in non-translated versions")
-
-def concretify_argument(hop, index):
-    from pypy.objspace.flow import model
-
-    v_arg = hop.args_v[index]
-    if isinstance(v_arg, model.Variable):
-        return v_arg
-
-    r_arg = hop.rtyper.bindingrepr(v_arg)
-    return hop.inputarg(r_arg, arg=index)
-
-class ResumeStateCreateFnEntry(FrameStackTopReturningFnEntry):
-    _about_ = resume_state_create
-
-    def compute_result_annotation(self, s_prevstate, s_label, *args_s):
-        return FrameStackTopReturningFnEntry.compute_result_annotation(self)
-
-    def specialize_call(self, hop):
-        from pypy.rpython.lltypesystem import lltype
-
-        assert hop.args_s[1].is_constant()
-        c_label = hop.inputconst(lltype.Void, hop.args_s[1].const)
-
-        v_state = hop.inputarg(hop.r_result, arg=0)
-
-        args_v = []
-        for i in range(2, len(hop.args_v)):
-            args_v.append(concretify_argument(hop, i))
-
-        hop.exception_is_here()
-        return hop.genop('resume_state_create', [v_state, c_label] + args_v,
-                         hop.r_result)
-
-def resume_state_invoke(type, state, **kwds):
-    raise NotImplementedError("only works in translated versions")
-
-class ResumeStateInvokeFnEntry(ExtRegistryEntry):
-    _about_ = resume_state_invoke
-
-    def compute_result_annotation(self, s_type, s_state, **kwds):
-        from pypy.annotation.bookkeeper import getbookkeeper
-        assert s_type.is_constant()
-        return getbookkeeper().valueoftype(s_type.const)
-
-    def specialize_call(self, hop, **kwds_i):
-        from pypy.rpython.lltypesystem import lltype
-        v_state = hop.args_v[1]
-        
-        if 'i_returning' in kwds_i:
-            assert len(kwds_i) == 1
-            returning_index = kwds_i['i_returning']
-            v_returning = concretify_argument(hop, returning_index)
-            v_raising = hop.inputconst(lltype.Void, None)
-        elif 'i_raising' in kwds_i:
-            assert len(kwds_i) == 1
-            raising_index = kwds_i['i_raising']
-            v_returning = hop.inputconst(lltype.Void, None)
-            v_raising = concretify_argument(hop, raising_index)
-        else:
-            assert not kwds_i
-            v_returning = hop.inputconst(lltype.Void, None)
-            v_raising = hop.inputconst(lltype.Void, None)
-
-        hop.exception_is_here()
-        return hop.genop('resume_state_invoke', [v_state, v_returning, v_raising],
-                         hop.r_result)
-        
 # ____________________________________________________________
 
 def get_stack_depth_limit():
diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py
--- a/pypy/rpython/llinterp.py
+++ b/pypy/rpython/llinterp.py
@@ -563,15 +563,6 @@
     def op_hint(self, x, hints):
         return x
 
-    def op_resume_point(self, *args):
-        pass
-
-    def op_resume_state_create(self, *args):
-        raise RuntimeError("resume_state_create can not be called.")
-
-    def op_resume_state_invoke(self, *args):
-        raise RuntimeError("resume_state_invoke can not be called.")
-
     def op_decode_arg(self, fname, i, name, vargs, vkwds):
         raise NotImplementedError("decode_arg")
 
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
@@ -521,10 +521,6 @@
                                                     RuntimeError)),
     #                               can always unwind, not just if stackless gc
 
-    'resume_point':         LLOp(canraise=(Exception,)),
-    'resume_state_create':  LLOp(canraise=(MemoryError,), canunwindgc=True),
-    'resume_state_invoke':  LLOp(canraise=(Exception, StackException,
-                                           RuntimeError)),
     'stack_frames_depth':   LLOp(sideeffects=False, canraise=(StackException,
                                                               RuntimeError)),
     'stack_switch':         LLOp(canraise=(StackException, RuntimeError)),
diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py
--- a/pypy/rpython/lltypesystem/rlist.py
+++ b/pypy/rpython/lltypesystem/rlist.py
@@ -237,6 +237,7 @@
         l.length = newsize
     else:
         _ll_list_resize_really(l, newsize)
+_ll_list_resize_ge.oopspec = 'list._resize_ge(l, newsize)'
 
 def _ll_list_resize_le(l, newsize):
     if newsize >= (len(l.items) >> 1) - 5:
diff --git a/pypy/rpython/rlist.py b/pypy/rpython/rlist.py
--- a/pypy/rpython/rlist.py
+++ b/pypy/rpython/rlist.py
@@ -568,7 +568,6 @@
     length = l.ll_length()
     l._ll_resize_ge(length+1)           # see "a note about overflows" above
     l.ll_setitem_fast(length, newitem)
-ll_append.oopspec = 'list.append(l, newitem)'
 
 # this one is for the special case of insert(0, x)
 def ll_prepend(l, newitem):
@@ -793,7 +792,6 @@
         raise MemoryError
     l1._ll_resize_ge(newlength)
     ll_arraycopy(l2, l1, 0, len1, len2)
-ll_extend.oopspec = 'list.extend(l1, l2)'
 
 def ll_extend_with_str(lst, s, getstrlen, getstritem):
     return ll_extend_with_str_slice_startonly(lst, s, getstrlen, getstritem, 0)
diff --git a/pypy/translator/backendopt/inline.py b/pypy/translator/backendopt/inline.py
--- a/pypy/translator/backendopt/inline.py
+++ b/pypy/translator/backendopt/inline.py
@@ -541,7 +541,6 @@
               'cast_pointer': 0,
               'malloc': 2,
               'yield_current_frame_to_caller': sys.maxint, # XXX bit extreme
-              'resume_point': sys.maxint, # XXX bit extreme
               'instrument_count': 0,
               'debug_assert': -1,
               }
diff --git a/pypy/translator/backendopt/removenoops.py b/pypy/translator/backendopt/removenoops.py
--- a/pypy/translator/backendopt/removenoops.py
+++ b/pypy/translator/backendopt/removenoops.py
@@ -81,8 +81,6 @@
                     num_removed += 1
                 else:
                     available[key] = op.result
-            elif op.opname == 'resume_point':
-                available.clear()
     if num_removed:
         remove_same_as(graph)
         # remove casts with unused results
diff --git a/pypy/translator/c/src/debug_print.c b/pypy/translator/c/src/debug_print.c
--- a/pypy/translator/c/src/debug_print.c
+++ b/pypy/translator/c/src/debug_print.c
@@ -6,6 +6,8 @@
 #include <stdio.h>
 #ifndef _WIN32
 #include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
 #else
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
diff --git a/pypy/translator/c/src/debug_print.h b/pypy/translator/c/src/debug_print.h
--- a/pypy/translator/c/src/debug_print.h
+++ b/pypy/translator/c/src/debug_print.h
@@ -53,8 +53,6 @@
 #  ifdef _WIN32
 #    define READ_TIMESTAMP(val) QueryPerformanceCounter((LARGE_INTEGER*)&(val))
 #  else
-#    include <time.h>
-#    include <sys/time.h>
 
 long long pypy_read_timestamp();
 
diff --git a/pypy/translator/c/src/stack.h b/pypy/translator/c/src/stack.h
--- a/pypy/translator/c/src/stack.h
+++ b/pypy/translator/c/src/stack.h
@@ -11,15 +11,18 @@
  * It is needed to have RPyThreadStaticTLS, too. */
 #include "thread.h"
 
-extern char *_LLstacktoobig_stack_start;
+extern char *_LLstacktoobig_stack_end;
+extern long _LLstacktoobig_stack_length;
 
 void LL_stack_unwind(void);
 char LL_stack_too_big_slowpath(long);    /* returns 0 (ok) or 1 (too big) */
+void LL_stack_set_length_fraction(double);
 
 /* some macros referenced from pypy.rlib.rstack */
-#define LL_stack_get_start() ((long)_LLstacktoobig_stack_start)
-#define LL_stack_get_length() MAX_STACK_SIZE
-#define LL_stack_get_start_adr() ((long)&_LLstacktoobig_stack_start)  /* JIT */
+#define LL_stack_get_end() ((long)_LLstacktoobig_stack_end)
+#define LL_stack_get_length() _LLstacktoobig_stack_length
+#define LL_stack_get_end_adr()    ((long)&_LLstacktoobig_stack_end)   /* JIT */
+#define LL_stack_get_length_adr() ((long)&_LLstacktoobig_stack_length)/* JIT */
 
 
 #ifdef __GNUC__
@@ -32,93 +35,65 @@
 #ifndef PYPY_NOT_MAIN_FILE
 #include <stdio.h>
 
-#ifndef PYPY_NOINLINE
-# if defined __GNUC__
-#  define PYPY_NOINLINE __attribute__((noinline))
-# else
-// add hints for other compilers here ...
-#  define PYPY_NOINLINE
-# endif
-#endif
+/* the current stack is in the interval [end-length:end].  We assume a
+   stack that grows downward here. */
+char *_LLstacktoobig_stack_end = NULL;
+long _LLstacktoobig_stack_length = MAX_STACK_SIZE;
+static RPyThreadStaticTLS end_tls_key;
 
-long PYPY_NOINLINE _LL_stack_growing_direction(char *parent)
+void LL_stack_set_length_fraction(double fraction)
 {
-	char local;
-	if (parent == NULL)
-		return _LL_stack_growing_direction(&local);
-	else
-		return &local - parent;
+	_LLstacktoobig_stack_length = (long)(MAX_STACK_SIZE * fraction);
 }
 
-char *_LLstacktoobig_stack_start = NULL;
-int stack_direction = 0;
-RPyThreadStaticTLS start_tls_key;
-
 char LL_stack_too_big_slowpath(long current)
 {
-	long diff;
+	long diff, max_stack_size;
 	char *baseptr, *curptr = (char*)current;
 
-	/* The stack_start variable is updated to match the current value
+	/* The stack_end variable is updated to match the current value
 	   if it is still 0 or if we later find a 'curptr' position
-	   that is below it.  The real stack_start pointer is stored in
+	   that is above it.  The real stack_end pointer is stored in
 	   thread-local storage, but we try to minimize its overhead by
-	   keeping a local copy in _LLstacktoobig_stack_start. */
+	   keeping a local copy in _LLstacktoobig_stack_end. */
 
-	if (stack_direction == 0) {
+	if (_LLstacktoobig_stack_end == NULL) {
 		/* not initialized */
 		/* XXX We assume that initialization is performed early,
 		   when there is still only one thread running.  This
 		   allows us to ignore race conditions here */
-		char *errmsg = RPyThreadStaticTLS_Create(&start_tls_key);
+		char *errmsg = RPyThreadStaticTLS_Create(&end_tls_key);
 		if (errmsg) {
 			/* XXX should we exit the process? */
 			fprintf(stderr, "Internal PyPy error: %s\n", errmsg);
 			return 1;
 		}
-		if (_LL_stack_growing_direction(NULL) > 0)
-			stack_direction = +1;
-		else
-			stack_direction = -1;
 	}
 
-	baseptr = (char *) RPyThreadStaticTLS_Get(start_tls_key);
-	if (baseptr != NULL) {
-		diff = curptr - baseptr;
-		if (((unsigned long)diff) < (unsigned long)MAX_STACK_SIZE) {
+	baseptr = (char *) RPyThreadStaticTLS_Get(end_tls_key);
+	max_stack_size = _LLstacktoobig_stack_length;
+	if (baseptr == NULL) {
+		/* first time we see this thread */
+	}
+	else {
+		diff = baseptr - curptr;
+		if (((unsigned long)diff) <= (unsigned long)max_stack_size) {
 			/* within bounds, probably just had a thread switch */
-			_LLstacktoobig_stack_start = baseptr;
+			_LLstacktoobig_stack_end = baseptr;
 			return 0;
 		}
-
-		if (stack_direction > 0) {
-			if (diff < 0 && diff > -MAX_STACK_SIZE)
-				;           /* stack underflow */
-			else
-				return 1;   /* stack overflow (probably) */
+		if (((unsigned long)-diff) <= (unsigned long)max_stack_size) {
+			/* stack underflowed: the initial estimation of
+			   the stack base must be revised */
 		}
-		else {
-			if (diff >= MAX_STACK_SIZE && diff < 2*MAX_STACK_SIZE)
-				;           /* stack underflow */
-			else
-				return 1;   /* stack overflow (probably) */
-		}
-		/* else we underflowed the stack, which means that
-		   the initial estimation of the stack base must
-		   be revised */
+		else
+			return 1;   /* stack overflow (probably) */
 	}
 
 	/* update the stack base pointer to the current value */
-	if (stack_direction > 0) {
-		/* the valid range is [curptr:curptr+MAX_STACK_SIZE] */
-		baseptr = curptr;
-	}
-	else {
-		/* the valid range is [curptr-MAX_STACK_SIZE+1:curptr+1] */
-		baseptr = curptr - MAX_STACK_SIZE + 1;
-	}
-	RPyThreadStaticTLS_Set(start_tls_key, baseptr);
-	_LLstacktoobig_stack_start = baseptr;
+	baseptr = curptr;
+	RPyThreadStaticTLS_Set(end_tls_key, baseptr);
+	_LLstacktoobig_stack_end = baseptr;
 	return 0;
 }
 
diff --git a/pypy/translator/c/test/test_standalone.py b/pypy/translator/c/test/test_standalone.py
--- a/pypy/translator/c/test/test_standalone.py
+++ b/pypy/translator/c/test/test_standalone.py
@@ -689,6 +689,44 @@
         out = cbuilder.cmdexec("")
         assert out.strip() == "hi!"
 
+    def test_set_length_fraction(self):
+        # check for pypy.rlib.rstack._stack_set_length_fraction()
+        from pypy.rlib.rstack import _stack_set_length_fraction
+        from pypy.rlib.rstackovf import StackOverflow
+        class A:
+            n = 0
+        glob = A()
+        def f(n):
+            glob.n += 1
+            if n <= 0:
+                return 42
+            return f(n+1)
+        def entry_point(argv):
+            _stack_set_length_fraction(0.1)
+            try:
+                return f(1)
+            except StackOverflow:
+                glob.n = 0
+            _stack_set_length_fraction(float(argv[1]))
+            try:
+                return f(1)
+            except StackOverflow:
+                print glob.n
+                return 0
+        t, cbuilder = self.compile(entry_point, stackcheck=True)
+        counts = {}
+        for fraction in [0.1, 0.4, 1.0]:
+            out = cbuilder.cmdexec(str(fraction))
+            print 'counts[%s]: %r' % (fraction, out)
+            counts[fraction] = int(out.strip())
+        #
+        assert counts[1.0] >= 1000
+        # ^^^ should actually be much more than 1000 for this small test
+        assert counts[0.1] < counts[0.4] / 3
+        assert counts[0.4] < counts[1.0] / 2
+        assert counts[0.1] > counts[0.4] / 7
+        assert counts[0.4] > counts[1.0] / 4
+
 class TestMaemo(TestStandalone):
     def setup_class(cls):
         py.test.skip("TestMaemo: tests skipped for now")
diff --git a/pypy/translator/cli/opcodes.py b/pypy/translator/cli/opcodes.py
--- a/pypy/translator/cli/opcodes.py
+++ b/pypy/translator/cli/opcodes.py
@@ -77,7 +77,6 @@
     'cast_ptr_to_weakadr':      [PushAllArgs, 'newobj instance void class %s::.ctor(object)' % WEAKREF],
     'gc__collect':              'call void class [mscorlib]System.GC::Collect()',
     'gc_set_max_heap_size':     Ignore,
-    'resume_point':             Ignore,
     'debug_assert':             Ignore,
     'debug_start_traceback':    Ignore,
     'debug_record_traceback':   Ignore,
@@ -85,6 +84,8 @@
     'debug_reraise_traceback':  Ignore,
     'debug_print_traceback':    Ignore,
     'debug_print':              [DebugPrint],
+    'debug_flush':              [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_FLUSH()'],
+    'debug_offset':             [PushAllArgs, 'call int32 [pypylib]pypy.runtime.DebugPrint::DEBUG_OFFSET()'],
     'debug_start':              [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_START(string)'],
     'debug_stop':               [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_STOP(string)'],
     'have_debug_prints':        [PushAllArgs, 'call bool [pypylib]pypy.runtime.DebugPrint::HAVE_DEBUG_PRINTS()'],
diff --git a/pypy/translator/cli/src/debug.cs b/pypy/translator/cli/src/debug.cs
--- a/pypy/translator/cli/src/debug.cs
+++ b/pypy/translator/cli/src/debug.cs
@@ -38,6 +38,20 @@
             return false;
         }
 
+        public static void DEBUG_FLUSH()
+        {
+            if (debug_file != null)
+                debug_file.Flush();
+        }
+
+        public static int DEBUG_OFFSET()
+        {
+            StreamWriter sw = debug_file as StreamWriter;
+            if (sw == null)
+                return -1;
+            return (int)sw.BaseStream.Position; // XXX: the cast might be incorrect
+        }
+
         public static bool HAVE_DEBUG_PRINTS()
         {
             if ((have_debug_prints & 1) != 0) {
diff --git a/pypy/translator/goal/targetpypystandalone.py b/pypy/translator/goal/targetpypystandalone.py
--- a/pypy/translator/goal/targetpypystandalone.py
+++ b/pypy/translator/goal/targetpypystandalone.py
@@ -105,7 +105,8 @@
         return parser
 
     def handle_config(self, config, translateconfig):
-        if translateconfig._cfgimpl_value_owners['opt'] == 'default':
+        if (not translateconfig.help and
+            translateconfig._cfgimpl_value_owners['opt'] == 'default'):
             raise Exception("You have to specify the --opt level.\n"
                     "Try --opt=2 or --opt=jit, or equivalently -O2 or -Ojit .")
         self.translateconfig = translateconfig
diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py
--- a/pypy/translator/jvm/opcodes.py
+++ b/pypy/translator/jvm/opcodes.py
@@ -95,7 +95,6 @@
 
     'gc__collect':              jvm.SYSTEMGC,
     'gc_set_max_heap_size':     Ignore,
-    'resume_point':             Ignore,
     'jit_marker':               Ignore,
     'jit_force_virtualizable':  Ignore,
     'jit_force_virtual':        DoNothing,
diff --git a/pypy/translator/oosupport/test_template/operations.py b/pypy/translator/oosupport/test_template/operations.py
--- a/pypy/translator/oosupport/test_template/operations.py
+++ b/pypy/translator/oosupport/test_template/operations.py
@@ -107,12 +107,6 @@
             return res
         assert self.interpret(fn, [sys.maxint, 2]) == 1
 
-    def test_ignore_resume_point(self):
-        def fn(x):
-            rstack.resume_point('hello world', x)
-            return x
-        assert self.interpret(fn, [42]) == 42
-
     def test_rshift(self):
         def fn(x, y):
             return x >> y
diff --git a/pypy/translator/platform/posix.py b/pypy/translator/platform/posix.py
--- a/pypy/translator/platform/posix.py
+++ b/pypy/translator/platform/posix.py
@@ -129,7 +129,9 @@
         m.cfiles = rel_cfiles
 
         rel_includedirs = [pypyrel(incldir) for incldir in
-                           self._preprocess_include_dirs(eci.include_dirs)]
+                           self.preprocess_include_dirs(eci.include_dirs)]
+        rel_libdirs = [pypyrel(libdir) for libdir in
+                       self.preprocess_library_dirs(eci.library_dirs)]
 
         m.comment('automatically generated makefile')
         definitions = [
@@ -139,7 +141,7 @@
             ('SOURCES', rel_cfiles),
             ('OBJECTS', rel_ofiles),
             ('LIBS', self._libs(eci.libraries)),
-            ('LIBDIRS', self._libdirs(eci.library_dirs)),
+            ('LIBDIRS', self._libdirs(rel_libdirs)),
             ('INCLUDEDIRS', self._includedirs(rel_includedirs)),
             ('CFLAGS', cflags),
             ('CFLAGSEXTRA', list(eci.compile_extra)),
diff --git a/pypy/translator/platform/test/test_posix.py b/pypy/translator/platform/test/test_posix.py
--- a/pypy/translator/platform/test/test_posix.py
+++ b/pypy/translator/platform/test/test_posix.py
@@ -3,7 +3,7 @@
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
 from pypy.tool.udir import udir
 from StringIO import StringIO
-import sys
+import sys, os
 
 def test_echo():
     res = host.execute('echo', '42 24')
@@ -49,6 +49,19 @@
         mk.write()
         assert 'LINKFILES = /foo/bar.a' in tmpdir.join('Makefile').read()
 
+    def test_preprocess_localbase(self):
+        tmpdir = udir.join('test_preprocess_localbase').ensure(dir=1)
+        eci = ExternalCompilationInfo()
+        os.environ['PYPY_LOCALBASE'] = '/foo/baz'
+        try:
+            mk = self.platform.gen_makefile(['blip.c'], eci, path=tmpdir)
+            mk.write()
+        finally:
+            del os.environ['PYPY_LOCALBASE']
+        Makefile = tmpdir.join('Makefile').read()
+        assert 'INCLUDEDIRS = -I/foo/baz/include' in Makefile
+        assert 'LIBDIRS = -L/foo/baz/lib' in Makefile
+
 class TestMaemo(TestMakefile):
     strict_on_stderr = False
     
diff --git a/pypy/translator/stackless/frame.py b/pypy/translator/stackless/frame.py
--- a/pypy/translator/stackless/frame.py
+++ b/pypy/translator/stackless/frame.py
@@ -104,10 +104,8 @@
 
 class RestartInfo(object):
 
-    """A RestartInfo is created (briefly) for each graph that contains
-    a resume point.
-
-    In addition, a RestartInfo is created for each function that needs
+    """
+    A RestartInfo is created for each function that needs
     to do explicit stackless manipulations
     (e.g. code.yield_current_frame_to_caller)."""
 
diff --git a/pypy/translator/stackless/test/test_coroutine_reconstruction.py b/pypy/translator/stackless/test/test_coroutine_reconstruction.py
deleted file mode 100644
--- a/pypy/translator/stackless/test/test_coroutine_reconstruction.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from pypy.rlib import rcoroutine
-from pypy.rlib import rstack
-from pypy.rlib.rstack import resume_state_create
-from pypy.translator.stackless.test.test_transform import llinterp_stackless_function
-from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rpython.lltypesystem import lltype
-
-namespace = rcoroutine.make_coroutine_classes(object)
-syncstate = namespace['syncstate']
-AbstractThunk = namespace['AbstractThunk']
-Coroutine = namespace['Coroutine']
-
-class TestCoroutineReconstruction:
-
-    def setup_meth(self):
-        syncstate.reset()
-
-    def test_simple_ish(self):
-
-        output = []
-        def f(coro, n, x):
-            if n == 0:
-                coro.switch()
-                rstack.resume_point("f_0")
-                assert rstack.stack_frames_depth() == 9
-                return
-            f(coro, n-1, 2*x)
-            rstack.resume_point("f_1", coro, n, x)
-            output.append(x)
-
-        class T(AbstractThunk):
-            def __init__(self, arg_coro, arg_n, arg_x):
-                self.arg_coro = arg_coro
-                self.arg_n = arg_n
-                self.arg_x = arg_x
-            def call(self):
-                f(self.arg_coro, self.arg_n, self.arg_x)
-
-        def example():
-            main_coro = Coroutine.getcurrent()
-            sub_coro = Coroutine()
-            thunk_f = T(main_coro, 5, 1)
-            sub_coro.bind(thunk_f)
-            sub_coro.switch()
-
-            new_coro = Coroutine()
-            new_thunk_f = T(main_coro, 5, 1)
-            new_coro.bind(new_thunk_f)
-
-            costate = Coroutine._get_default_costate()
-            bottom = resume_state_create(None, "yield_current_frame_to_caller_1")
-            _bind_frame = resume_state_create(bottom, "coroutine__bind", costate)
-            f_frame_1 = resume_state_create(_bind_frame, "f_1", main_coro, 5, 1)
-            f_frame_2 = resume_state_create(f_frame_1, "f_1", main_coro, 4, 2)
-            f_frame_3 = resume_state_create(f_frame_2, "f_1", main_coro, 3, 4)
-            f_frame_4 = resume_state_create(f_frame_3, "f_1", main_coro, 2, 8)
-            f_frame_5 = resume_state_create(f_frame_4, "f_1", main_coro, 1, 16)
-            f_frame_0 = resume_state_create(f_frame_5, "f_0")
-            switch_frame = resume_state_create(f_frame_0, "coroutine_switch", costate)
-
-            new_coro.frame = switch_frame
-
-            new_coro.switch()
-            return output == [16, 8, 4, 2, 1]
-
-        res = llinterp_stackless_function(example)
-        assert res == 1
-
diff --git a/pypy/translator/stackless/test/test_resume_point.py b/pypy/translator/stackless/test/test_resume_point.py
deleted file mode 100644
--- a/pypy/translator/stackless/test/test_resume_point.py
+++ /dev/null
@@ -1,457 +0,0 @@
-from pypy.translator.stackless.transform import StacklessTransformer
-from pypy.translator.stackless.test.test_transform import llinterp_stackless_function, rtype_stackless_function, one, run_stackless_function
-from pypy import conftest
-import py
-from pypy.rlib import rstack
-
-def do_backendopt(t):
-    from pypy.translator.backendopt import all
-    all.backend_optimizations(t)
-
-def transform_stackless_function(fn, callback_for_transform=None):
-    def wrapper(argv):
-        return fn()
-    t = rtype_stackless_function(wrapper)
-    if callback_for_transform:
-        callback_for_transform(t)
-    if conftest.option.view:
-        t.view()
-    st = StacklessTransformer(t, wrapper, False)
-    st.transform_all()
-
-def test_no_call():
-    def f(x, y):
-        x = x-1
-        rstack.resume_point("rp0", x, y) 
-        r = x+y
-        rstack.stack_unwind()
-        return r
-    def example():
-        v1 = f(one(),one()+one())
-        state = rstack.resume_state_create(None, "rp0", one(), one()+one()+one())
-        v2 = rstack.resume_state_invoke(int, state)
-        return v1*10 + v2
-##     transform_stackless_function(example)
-    res = llinterp_stackless_function(example, assert_unwind=False)
-    assert res == 24
-
-def test_bogus_restart_state_create():
-    def f(x, y):
-        x = x-1
-        rstack.resume_point("rp0", x, y) 
-        return x+y
-    def example():
-        v1 = f(one(),one()+one())
-        state = rstack.resume_state_create(None, "rp0", one())
-        return v1
-    info = py.test.raises(AssertionError, "transform_stackless_function(example)")
-    assert 'rp0' in str(info.value)
-    
-
-def test_call():
-    def g(x,y):
-        return x*y
-    def f(x, y):
-        z = g(x,y)
-        rstack.resume_point("rp1", y, returns=z) 
-        return z+y
-    def example():
-        v1 = f(one(),one()+one())
-        s = rstack.resume_state_create(None, "rp1", 5*one())
-        v2 = rstack.resume_state_invoke(int, s, returning=one()*7)
-        return v1*100 + v2
-    res = llinterp_stackless_function(example)
-    assert res == 412
-    res = run_stackless_function(example)
-    assert res == 412
-
-def test_returns_with_instance():
-    class C:
-        def __init__(self, x):
-            self.x = x
-    def g(x):
-        return C(x+1)
-    def f(x, y):
-        r = g(x)
-        rstack.resume_point("rp1", y, returns=r)
-        return r.x + y
-    def example():
-        v1 = f(one(),one()+one())
-        s = rstack.resume_state_create(None, "rp1", 5*one())
-        v2 = rstack.resume_state_invoke(int, s, returning=C(one()*3))
-        return v1*100 + v2
-    res = llinterp_stackless_function(example, assert_unwind=False)
-    assert res == 408
-    res = run_stackless_function(example)
-    assert res == 408
-
-def test_call_uncovered():
-    def g(x,y):
-        return x*y
-    def f(x, y):
-        z = g(x,y)
-        rstack.resume_point("rp1", y, returns=z)
-        return z+y+x
-    def example():
-        f(one(),one()+one())
-        return 0
-    e = py.test.raises(Exception, transform_stackless_function, example)
-    msg, = e.value.args
-    assert msg.startswith('not covered needed value at resume_point') and 'rp1' in msg
-
-def test_chained_states():
-    def g(x, y):
-        x += 1
-        rstack.resume_point("rp1", x, y)
-        return x + y
-    def f(x, y, z):
-        y += 1
-        r = g(x, y)
-        rstack.resume_point("rp2", z, returns=r)
-        return r + z
-    def example():
-        v1 = f(one(), 2*one(), 3*one())
-        s2 = rstack.resume_state_create(None, "rp2", 2*one())
-        s1 = rstack.resume_state_create(s2, "rp1", 4*one(), 5*one())
-        return 100*v1 + rstack.resume_state_invoke(int, s1)
-    res = llinterp_stackless_function(example)
-    assert res == 811
-    res = run_stackless_function(example)
-    assert res == 811
-
-def test_return_instance():
-    class C:
-        pass
-    def g(x):
-        c = C()
-        c.x = x + 1
-        rstack.resume_point("rp1", c)
-        return c
-    def f(x, y):
-        r = g(x)
-        rstack.resume_point("rp2", y, returns=r)
-        return r.x + y
-    def example():
-        v1 = f(one(), 2*one())
-        s2 = rstack.resume_state_create(None, "rp2", 2*one())
-        c = C()
-        c.x = 4*one()
-        s1 = rstack.resume_state_create(s2, "rp1", c)
-        return v1*100 + rstack.resume_state_invoke(int, s1)
-    res = llinterp_stackless_function(example)
-    assert res == 406
-    res = run_stackless_function(example)
-    assert res == 406
-
-def test_really_return_instance():
-    class C:
-        pass
-    def g(x):
-        c = C()
-        c.x = x + 1
-        rstack.resume_point("rp1", c)
-        return c
-    def example():
-        v1 = g(one()).x
-        c = C()
-        c.x = 4*one()
-        s1 = rstack.resume_state_create(None, "rp1", c)
-        return v1*100 + rstack.resume_state_invoke(C, s1).x
-    res = llinterp_stackless_function(example)
-    assert res == 204
-    res = run_stackless_function(example)
-    assert res == 204
-
-def test_resume_and_raise():
-    def g(x):
-        rstack.resume_point("rp0", x)
-        if x == 0:
-            raise KeyError
-        return x + 1
-    def example():
-        v1 = g(one())
-        s = rstack.resume_state_create(None, "rp0", one()-1)
-        try:
-            v2 = rstack.resume_state_invoke(int, s)
-        except KeyError:
-            v2 = 42
-        return v1*100 + v2
-    res = llinterp_stackless_function(example)
-    assert res == 242
-    res = run_stackless_function(example)
-    assert res == 242
-    
-def test_resume_and_raise_and_catch():
-    def g(x):
-        rstack.resume_point("rp0", x)
-        if x == 0:
-            raise KeyError
-        return x + 1
-    def f(x):
-        x = x - 1
-        try:
-            r = g(x)
-            rstack.resume_point("rp1", returns=r)
-        except KeyError:
-            r = 42
-        return r - 1
-    def example():
-        v1 = f(one()+one())
-        s1 = rstack.resume_state_create(None, "rp1")
-        s0 = rstack.resume_state_create(s1, "rp0", one()-1)
-        v2 = rstack.resume_state_invoke(int, s0)
-        return v1*100 + v2
-    res = llinterp_stackless_function(example)
-    assert res == 141
-    res = run_stackless_function(example)
-    assert res == 141
-
-def test_invoke_raising():
-    def g(x):
-        rstack.resume_point("rp0", x)
-        return x + 1
-    def f(x):
-        x = x - 1
-        try:
-            r = g(x)
-            rstack.resume_point("rp1", returns=r)
-        except KeyError:
-            r = 42
-        return r - 1
-    def example():
-        v1 = f(one()+one())
-        s1 = rstack.resume_state_create(None, "rp1")
-        s0 = rstack.resume_state_create(s1, "rp0", 0)
-        v2 = rstack.resume_state_invoke(int, s0, raising=KeyError())
-        return v1*100 + v2
-    res = llinterp_stackless_function(example)
-    assert res == 141
-    res = run_stackless_function(example)
-    assert res == 141
-    
-
-def test_finally():
-    def f(x):
-        rstack.resume_point("rp1", x)        
-        return 1/x
-    def in_finally(x): 
-        rstack.resume_point("rp1.5", x)
-        return 2/x
-    def g(x):
-        r = y = 0
-        r += f(x)
-        try:
-            y = f(x)
-            rstack.resume_point("rp0", x, r, returns=y)
-        finally:
-            r += in_finally(x)
-        return r + y
-    def example():
-        return g(one())
-    transform_stackless_function(example)
-
-def test_except():
-    py.test.skip("please don't write code like this")
-    def f(x):
-        rstack.resume_point("rp1", x)        
-        return 1/x
-    def g(x):
-        r = y = 0
-        r += f(x)
-        try:
-            y = f(x)
-            rstack.resume_point("rp0", x, r, y, returns=y)
-        except ZeroDivisionError:
-            r += f(x)
-        return r + y
-    def example():
-        return g(one())
-    transform_stackless_function(example)
-
-def test_using_pointers():
-    from pypy.interpreter.miscutils import FixedStack
-    class Arguments:
-        def __init__(self, a, b, c, d, e):
-            pass
-    class W_Root:
-        pass
-    class FakeFrame:
-        def __init__(self, space):
-            self.space = space
-            self.valuestack = FixedStack()
-            self.valuestack.setup(10)
-            self.valuestack.push(W_Root())
-    class FakeSpace:
-        def call_args(self, args, kw):
-            return W_Root()
-        def str_w(self, ob):
-            return 'a string'
-    def call_function(f, oparg, w_star=None, w_starstar=None):
-        n_arguments = oparg & 0xff
-        n_keywords = (oparg>>8) & 0xff
-        keywords = None
-        if n_keywords:
-            keywords = {}
-            for i in range(n_keywords):
-                w_value = f.valuestack.pop()
-                w_key   = f.valuestack.pop()
-                key = f.space.str_w(w_key)
-                keywords[key] = w_value
-        arguments = [None] * n_arguments
-        for i in range(n_arguments - 1, -1, -1):
-            arguments[i] = f.valuestack.pop()
-        args = Arguments(f.space, arguments, keywords, w_star, w_starstar)
-        w_function  = f.valuestack.pop()
-        w_result = f.space.call_args(w_function, args)
-        rstack.resume_point("call_function", f, returns=w_result)
-        f.valuestack.push(w_result)
-    def example():
-        s = FakeSpace()
-        f = FakeFrame(s)
-        call_function(f, 100, W_Root(), W_Root())
-        return one()
-    transform_stackless_function(example, do_backendopt)
-
-def test_always_raising():
-    def g(out):
-        out.append(3)
-        rstack.resume_point('g')
-        raise KeyError
-
-    def h(out):
-        try:
-            # g is always raising, good enough to put the resume point
-            # before, instead of after!
-            rstack.resume_point('h', out)
-            g(out)
-        except KeyError:
-            return 0
-        return -1
-
-    def example():
-        out = []
-        x = h(out)
-        l  = len(out)
-        chain = rstack.resume_state_create(None, 'h', out)
-        chain = rstack.resume_state_create(chain, 'g')
-        x += rstack.resume_state_invoke(int, chain)
-        l += len(out)
-        return l*100+x
-
-    res = llinterp_stackless_function(example)
-    assert res == 200
-    res = run_stackless_function(example)
-    assert res == 200
-
-def test_more_mess():
-    from pypy.interpreter.miscutils import Stack
-
-    def new_framestack():
-        return Stack()
-
-    class FakeFrame:
-        pass
-    class FakeSlpFrame:
-        def switch(self):
-            rstack.stack_unwind()
-            return FakeSlpFrame()
-
-    class FakeCoState:
-        def update(self, new):
-            self.last, self.current = self.current, new
-            frame, new.frame = new.frame, None
-            return frame
-        def do_things_to_do(self):
-            self.do_things_to_do()
-
-    costate = FakeCoState()
-    costate.current = None
-
-    class FakeExecutionContext:
-        def __init__(self):
-            self.space = space
-            self.framestack = new_framestack()
-
-        def subcontext_new(coobj):
-            coobj.framestack = new_framestack()
-        subcontext_new = staticmethod(subcontext_new)
-
-        def subcontext_enter(self, next):
-            self.framestack = next.framestack
-
-        def subcontext_leave(self, current):
-            current.framestack = self.framestack
-
-    class FakeSpace:
-        def __init__(self):
-            self.ec = None
-        def getexecutioncontext(self):
-            if self.ec is None:
-                self.ec = FakeExecutionContext()
-            return self.ec
-
-    space = FakeSpace()
-
-    class MainCoroutineGetter(object):
-        def __init__(self):
-            self.costate = None
-        def _get_default_costate(self):
-            if self.costate is None:
-                costate = FakeCoState()
-                self.costate = costate
-                return costate
-            return self.costate
-
-    main_coroutine_getter = MainCoroutineGetter()
-    
-    class FakeCoroutine:
-        def __init__(self):
-            self.frame = None
-            self.costate = costate
-            space.getexecutioncontext().subcontext_new(self)
-            
-        def switch(self):
-            if self.frame is None:
-                raise RuntimeError
-            state = self.costate
-            incoming_frame = state.update(self).switch()
-            rstack.resume_point("coroutine_switch", self, state, returns=incoming_frame)
-            left = state.last
-            left.frame = incoming_frame
-            left.goodbye()
-            self.hello()
-            #main_coroutine_getter._get_default_costate().do_things_to_do()
-
-        def hello(self):
-            pass
-
-        def goodbye(self):
-            pass
-
-    class FakeAppCoroutine(FakeCoroutine):
-        def __init__(self):
-            FakeCoroutine.__init__(self)
-            self.space = space
-            
-        def hello(self):
-            ec = self.space.getexecutioncontext()
-            ec.subcontext_enter(self)
-
-        def goodbye(self):
-            ec = self.space.getexecutioncontext()
-            ec.subcontext_leave(self)
-
-    def example():
-        coro = FakeAppCoroutine()
-        othercoro = FakeCoroutine()
-        othercoro.frame = FakeSlpFrame()
-        if one():
-            coro.frame = FakeSlpFrame()
-        if one() - one():
-            coro.costate = FakeCoState()
-            coro.costate.last = coro.costate.current = othercoro
-        space.getexecutioncontext().framestack.push(FakeFrame())
-        coro.switch()
-        return one()
-
-    transform_stackless_function(example, do_backendopt)
diff --git a/pypy/translator/stackless/transform.py b/pypy/translator/stackless/transform.py
--- a/pypy/translator/stackless/transform.py
+++ b/pypy/translator/stackless/transform.py
@@ -112,19 +112,6 @@
 #         abort()
 #     return retval + x + 1
 
-class SymbolicRestartNumber(ComputedIntSymbolic):
-    def __init__(self, label, value=None):
-        ComputedIntSymbolic.__init__(self, self._getvalue)
-        self.label = label
-        self.value = value
-
-    def _getvalue(self):
-        # argh, we'd like to assert-fail if value is None here, but we
-        # get called too early (during databasing) for this to be
-        # valid.  so we might return None and rely on the database
-        # checking that this only happens before the database is
-        # complete.
-        return self.value
 
 # the strategy for sharing parts of the resume code:
 #
@@ -248,8 +235,7 @@
         self.stackless_gc = stackless_gc
 
     def analyze_simple_operation(self, op, graphinfo):
-        if op.opname in ('yield_current_frame_to_caller', 'resume_point',
-                'resume_state_invoke', 'resume_state_create', 'stack_frames_depth',
+        if op.opname in ('yield_current_frame_to_caller', 'stack_frames_depth',
                 'stack_switch', 'stack_unwind', 'stack_capture',
                 'get_stack_depth_limit', 'set_stack_depth_limit'):
             return True
@@ -458,24 +444,11 @@
 
         self.is_finished = False
 
-        # only for sanity checking, but still very very important
-        self.explicit_resume_point_data = {}
-        
-        self.symbolic_restart_numbers = {}
-
-        # register the prebuilt restartinfos & give them names for use
-        # with resume_state_create
         # the mauling of frame_typer internals should be a method on FrameTyper.
         for restartinfo in frame.RestartInfo.prebuilt:
             name = restartinfo.func_or_graph.__name__
             for i in range(len(restartinfo.frame_types)):
-                label = name + '_' + str(i)
-                assert label not in self.symbolic_restart_numbers
-                # XXX we think this is right:
-                self.symbolic_restart_numbers[label] = SymbolicRestartNumber(
-                    label, len(self.masterarray1) + i)
                 frame_type = restartinfo.frame_types[i]
-                self.explicit_resume_point_data[label] = frame_type
                 self.frametyper.ensure_frame_type_for_types(frame_type)
             self.register_restart_info(restartinfo)
 
@@ -589,156 +562,6 @@
                 # yes
                 convertblock.exits[0].args[index] = newvar
         # end ouch!
-        
-    def handle_resume_point(self, block, i):
-        # in some circumstances we might be able to reuse
-        # an already inserted resume point
-        op = block.operations[i]
-        if i == len(block.operations) - 1:
-            link = block.exits[0]
-            nextblock = None
-        else:
-            link = split_block(None, block, i+1)
-            i = 0
-            nextblock = link.target
-
-        label = op.args[0].value
-
-        parms = op.args[1:]
-        if not isinstance(parms[0], model.Variable):
-            assert parms[0].value is None
-            parms[0] = None
-        args = vars_to_save(block)
-        for a in args:
-            if a not in parms:
-                raise Exception, "not covered needed value at resume_point %r"%(label,)
-        if parms[0] is not None: # returns= case
-            res = parms[0]
-            args = [arg for arg in args if arg is not res]
-        else:
-            args = args
-            res = op.result
-
-        (FRAME_TYPE, varsforcall, saver) = self.frametyper.frame_type_for_vars(parms[1:])
-
-        if label in self.explicit_resume_point_data:
-            OTHER_TYPE = self.explicit_resume_point_data[label]
-            assert FRAME_TYPE == OTHER_TYPE, "inconsistent types for label %r"%(label,)
-        else:
-            self.explicit_resume_point_data[label] = FRAME_TYPE
-
-        self._make_resume_handling(FRAME_TYPE, varsforcall, res, block.exits)
-
-        restart_number = len(self.masterarray1) + len(self.resume_blocks) - 1
-
-        if label in self.symbolic_restart_numbers:
-            symb = self.symbolic_restart_numbers[label]
-            assert symb.value is None
-            symb.value = restart_number
-        else:
-            symb = SymbolicRestartNumber(label, restart_number)
-            self.symbolic_restart_numbers[label] = symb
-
-        return nextblock
-
-    def handle_resume_state_create(self, block, i):
-        op = block.operations[i]
-        llops = LowLevelOpList()
-        label = op.args[1].value
-        parms = op.args[2:]
-        FRAME_TYPE, varsforcall, saver = self.frametyper.frame_type_for_vars(parms)
-
-        if label in self.explicit_resume_point_data:
-            OTHER_TYPE = self.explicit_resume_point_data[label]
-            assert FRAME_TYPE == OTHER_TYPE, "inconsistent types for label %r"%(label,)
-        else:
-            self.explicit_resume_point_data[label] = FRAME_TYPE
-
-        if label in self.symbolic_restart_numbers:
-            symb = self.symbolic_restart_numbers[label]
-        else:
-            symb = SymbolicRestartNumber(label)
-            self.symbolic_restart_numbers[label] = symb
-
-        # this is rather insane: we create an exception object, pass
-        # it to the saving function, then read the thus created state
-        # out of and then clear global_state.top
-        c_EXC = model.Constant(self.unwind_exception_type.TO, lltype.Void)
-        c_flags = model.Constant({'flavor': 'gc'}, lltype.Void)
-        v_exc = llops.genop('malloc', [c_EXC, c_flags],
-                            resulttype = self.unwind_exception_type)
-        llops.genop('setfield', [v_exc,
-                                 model.Constant('inst_depth', lltype.Void),
-                                 model.Constant(0, lltype.Signed)])
-
-        realvarsforcall = []
-        for v in varsforcall:
-            if v.concretetype != lltype.Void:
-                realvarsforcall.append(gen_cast(llops, storage_type(v.concretetype), v))
-        
-        llops.genop('direct_call',
-                    [model.Constant(saver, lltype.typeOf(saver)), v_exc,
-                     model.Constant(symb, lltype.Signed)] + realvarsforcall,
-                    resulttype = lltype.Void)
-        v_state = varoftype(lltype.Ptr(frame.STATE_HEADER))
-        v_state_hdr = llops.genop("getfield",
-                                  [self.ll_global_state, self.c_inst_top_name],
-                                  resulttype=lltype.Ptr(STATE_HEADER))
-        v_state = gen_cast(llops, lltype.Ptr(FRAME_TYPE), v_state_hdr)
-        llops.genop("setfield",
-                    [self.ll_global_state, self.c_inst_top_name, self.c_null_state])
-
-        v_prevstate = gen_cast(llops, lltype.Ptr(frame.STATE_HEADER), op.args[0])
-        llops.genop('direct_call', [self.set_back_pointer_ptr,
-                                    v_state_hdr, v_prevstate])
-        llops.append(model.SpaceOperation('cast_opaque_ptr', [v_state_hdr], op.result))
-        block.operations[i:i+1] = llops
-
-    def handle_resume_state_invoke(self, block):
-        op = block.operations[-1]
-        assert op.opname == 'resume_state_invoke'
-        # some commentary.
-        #
-        # we don't want to write 155 or so different versions of
-        # resume_after_foo that appear to the annotator to return
-        # different types.  we take advantage of the fact that this
-        # function always raises UnwindException and have it (appear
-        # to) return Void.  then to placate all the other machinery,
-        # we pass a constant zero-of-the-appropriate-type along the
-        # non-exceptional link (which we know will never be taken).
-        # Nota Bene: only mutate a COPY of the non-exceptional link
-        # because the non-exceptional link has been stored in
-        # self.resume_blocks and we don't want a constant "zero" in
-        # there.
-        v_state = op.args[0]
-        v_returning = op.args[1]
-        v_raising = op.args[2]
-        llops = LowLevelOpList()
-
-        if v_raising.concretetype == lltype.Void:
-            erased_type = storage_type(v_returning.concretetype)
-            resume_after_ptr = self.resume_afters[erased_type]
-            v_param = v_returning
-        else:
-            assert v_returning.concretetype == lltype.Void
-            erased_type = self.exception_type
-            resume_after_ptr = self.resume_after_raising_ptr
-            v_param = v_raising
-
-        if erased_type != v_param.concretetype:
-            v_param = gen_cast(llops, erased_type, v_param)
-        llops.genop('direct_call', [resume_after_ptr, v_state, v_param],
-                    resulttype=lltype.Void)
-
-        del block.operations[-1]
-        block.operations.extend(llops)
-
-        noexclink = block.exits[0].copy()
-        realrettype = op.result.concretetype
-        for i, a in enumerate(noexclink.args):
-            if a is op.result:
-                noexclink.args[i] = model.Constant(realrettype._defl(), realrettype)
-        block.recloseblock(*((noexclink,) + block.exits[1:]))        
 
     def insert_unwind_handling(self, block, i):
         # for the case where we are resuming to an except:
@@ -821,19 +644,8 @@
                 op = replace_with_call(self.operation_replacement[op.opname])
                 stackless_op = True
 
-            if op.opname == 'resume_state_create':
-                self.handle_resume_state_create(block, i)
-                continue # go back and look at that malloc
-                        
             if (op.opname in ('direct_call', 'indirect_call')
                 or self.analyzer.analyze(op)):
-                if op.opname == 'resume_point':
-                    block = self.handle_resume_point(block, i)
-                    if block is None:
-                        return
-                    else:
-                        i = 0
-                        continue
 
                 if not stackless_op and not self.analyzer.analyze(op):
                     i += 1
@@ -849,9 +661,7 @@
                     continue
 
                 nextblock = self.insert_unwind_handling(block, i)
-                if op.opname == 'resume_state_invoke':
-                    self.handle_resume_state_invoke(block)
-                
+
                 if nextblock is None:
                     return
 


More information about the pypy-commit mailing list