Commits

wlav committed bc02a09 Merge

merge default into branch

  • Participants
  • Parent commits dc3b3a3, a9ccee5
  • Branches reflex-support

Comments (0)

Files changed (71)

lib-python/TODO

-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).

lib_pypy/stackless.py

     # 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
 
 #
         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)

pypy/annotation/description.py

         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
 

pypy/config/pypyoption.py

                    "(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),

pypy/doc/config/objspace.std.withsmalltuple.txt

+Use small tuple objects for sizes from 1 to 3

pypy/interpreter/astcompiler/misc.py

     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):

pypy/interpreter/eval.py

 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
 
         "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:
                 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

pypy/interpreter/executioncontext.py

 
         # 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 = []

pypy/interpreter/nestedscope.py

         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
                 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

pypy/interpreter/pycompiler.py

     """
     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):
     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:

pypy/interpreter/pyframe.py

 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
 
             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
         "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()."""

pypy/interpreter/pyopcode.py

 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
         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:
                         # 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
                                                           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):
             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)
         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:

pypy/interpreter/pyparser/pyparse.py

 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
 
 
 
 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.
                         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:

pypy/interpreter/test/test_compiler.py

 
 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

pypy/jit/backend/llsupport/llmodel.py

         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

pypy/jit/backend/x86/assembler.py

         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)
         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:

pypy/jit/codewriter/jtransform.py

     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

pypy/jit/codewriter/policy.py

             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):

pypy/jit/codewriter/test/test_policy.py

 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
                     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)

pypy/jit/metainterp/test/test_list.py

             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)

pypy/jit/metainterp/test/test_tl.py

             exit:
                 RETURN
         ''')
-        
+
         codes = [code, code2]
         def main(n, inputarg):
             code = codes[n]
         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
         from pypy.jit.tl.tl import Stack
         methods = [Stack.put,
                    Stack.pick,
-                   Stack.roll,
                    Stack.append,
                    Stack.pop]
         for meth in methods:

pypy/jit/tl/tl.py

         assert n >= 0
         self.stack[n] = elem
 
+    @dont_look_inside
     def roll(self, r):
         if r < -1:
             i = self.stackpos + r

pypy/module/_ast/test/test_ast.py

         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()

pypy/module/_file/interp_file.py

         # 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
 @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
+    file.errors = errors

pypy/module/_file/test/test_file.py

             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):

pypy/module/_stackless/interp_coroutine.py

 
 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):
     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.""")
 
                 "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
 
         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__:
 @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

pypy/module/_stackless/test/test_coroutine.py

         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()

pypy/module/_stackless/test/test_pickle.py

 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):
 
         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
 
         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')

pypy/module/_stackless/test/test_pickle_infrastructure.py

-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'
-
-                

pypy/module/cpyext/methodobject.py

                 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:

pypy/module/cpyext/test/test_tupleobject.py

 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
         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))

pypy/module/cpyext/tupleobject.py

     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")
 
     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):
     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

pypy/module/oracle/interp_variable.py

     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))

pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py

             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):
         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):
             # few instructions
             loop.match_by_id("contains", """
                 i1 = int_add(i0, 1)
-            """)
+            """)

pypy/module/sys/vm.py

     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().

pypy/module/test_lib_pypy/test_stackless.py

         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
 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()
 
         mod = new.module('mod')
         sys.modules['mod'] = mod
-        mod.can_unpickle = self.can_unpickle
-        mod.skip = skip
         try:
             exec '''
 import pickle, sys

pypy/module/test_lib_pypy/test_tputil.py

         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 

pypy/objspace/descroperation.py

         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__')

pypy/objspace/std/callmethod.py

 
 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
 
         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:
             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)
 
 

pypy/objspace/std/model.py

     _registered_implementations.add(implcls)
 
 option_to_typename = {
+    "withsmalltuple" : ["smalltupleobject.W_SmallTupleObject"],
     "withsmallint"   : ["smallintobject.W_SmallIntObject"],
     "withsmalllong"  : ["smalllongobject.W_SmallLongObject"],
     "withstrslice"   : ["strsliceobject.W_StringSliceObject"],
         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
                 (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] = []

pypy/objspace/std/objspace.py

         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)

pypy/objspace/std/smalltupleobject.py

+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):
+