Author: Ronan Lamy <ronan.l...@gmail.com>
Branch: py3.5
Changeset: r91355:64deec640157
Date: 2017-05-20 21:58 +0100
http://bitbucket.org/pypy/pypy/changeset/64deec640157/

Log:    hg merge default

diff --git a/lib_pypy/_ctypes/function.py b/lib_pypy/_ctypes/function.py
--- a/lib_pypy/_ctypes/function.py
+++ b/lib_pypy/_ctypes/function.py
@@ -1,4 +1,3 @@
-
 from _ctypes.basics import _CData, _CDataMeta, cdata_from_address
 from _ctypes.primitive import SimpleType, _SimpleCData
 from _ctypes.basics import ArgumentError, keepalive_key
@@ -9,13 +8,16 @@
 import sys
 import traceback
 
-try: from __pypy__ import builtinify
-except ImportError: builtinify = lambda f: f
+
+try:
+    from __pypy__ import builtinify
+except ImportError:
+    builtinify = lambda f: f
 
 # XXX this file needs huge refactoring I fear
 
-PARAMFLAG_FIN   = 0x1
-PARAMFLAG_FOUT  = 0x2
+PARAMFLAG_FIN = 0x1
+PARAMFLAG_FOUT = 0x2
 PARAMFLAG_FLCID = 0x4
 PARAMFLAG_COMBINED = PARAMFLAG_FIN | PARAMFLAG_FOUT | PARAMFLAG_FLCID
 
@@ -24,7 +26,7 @@
     PARAMFLAG_FIN,
     PARAMFLAG_FIN | PARAMFLAG_FOUT,
     PARAMFLAG_FIN | PARAMFLAG_FLCID
-    )
+)
 
 WIN64 = sys.platform == 'win32' and sys.maxsize == 2**63 - 1
 
@@ -35,6 +37,7 @@
     from _ctypes import COMError
     return COMError(errcode, None, None)
 
+
 @builtinify
 def call_function(func, args):
     "Only for debugging so far: So that we can call CFunction instances"
@@ -93,14 +96,9 @@
                         "item %d in _argtypes_ has no from_param method" % (
                             i + 1,))
             self._argtypes_ = list(argtypes)
-            self._check_argtypes_for_fastpath()
+
     argtypes = property(_getargtypes, _setargtypes)
 
-    def _check_argtypes_for_fastpath(self):
-        if all([hasattr(argtype, '_ffiargshape_') for argtype in 
self._argtypes_]):
-            fastpath_cls = make_fastpath_subclass(self.__class__)
-            fastpath_cls.enable_fastpath_maybe(self)
-
     def _getparamflags(self):
         return self._paramflags
 
@@ -125,27 +123,26 @@
                 raise TypeError(
                     "paramflags must be a sequence of (int [,string [,value]]) 
"
                     "tuples"
-                    )
+                )
             if not isinstance(flag, int):
                 raise TypeError(
                     "paramflags must be a sequence of (int [,string [,value]]) 
"
                     "tuples"
-                    )
+                )
             _flag = flag & PARAMFLAG_COMBINED
             if _flag == PARAMFLAG_FOUT:
                 typ = self._argtypes_[idx]
                 if getattr(typ, '_ffiargshape_', None) not in ('P', 'z', 'Z'):
                     raise TypeError(
                         "'out' parameter %d must be a pointer type, not %s"
-                        % (idx+1, type(typ).__name__)
-                        )
+                        % (idx + 1, type(typ).__name__)
+                    )
             elif _flag not in VALID_PARAMFLAGS:
                 raise TypeError("paramflag value %d not supported" % flag)
         self._paramflags = paramflags
 
     paramflags = property(_getparamflags, _setparamflags)
 
-
     def _getrestype(self):
         return self._restype_
 
@@ -155,7 +152,7 @@
             from ctypes import c_int
             restype = c_int
         if not (isinstance(restype, _CDataMeta) or restype is None or
-                callable(restype)):
+                    callable(restype)):
             raise TypeError("restype must be a type, a callable, or None")
         self._restype_ = restype
 
@@ -167,15 +164,18 @@
 
     def _geterrcheck(self):
         return getattr(self, '_errcheck_', None)
+
     def _seterrcheck(self, errcheck):
         if not callable(errcheck):
             raise TypeError("The errcheck attribute must be callable")
         self._errcheck_ = errcheck
+
     def _delerrcheck(self):
         try:
             del self._errcheck_
         except AttributeError:
             pass
+
     errcheck = property(_geterrcheck, _seterrcheck, _delerrcheck)
 
     def _ffishapes(self, args, restype):
@@ -187,7 +187,7 @@
                 raise TypeError("invalid result type for callback function")
             restype = restype._ffiargshape_
         else:
-            restype = 'O' # void
+            restype = 'O'  # void
         return argtypes, restype
 
     def _set_address(self, address):
@@ -200,7 +200,7 @@
 
     def __init__(self, *args):
         self.name = None
-        self._objects = {keepalive_key(0):self}
+        self._objects = {keepalive_key(0): self}
         self._needs_free = True
 
         # Empty function object -- this is needed for casts
@@ -221,10 +221,8 @@
             if self._argtypes_ is None:
                 self._argtypes_ = []
             self._ptr = self._getfuncptr_fromaddress(self._argtypes_, restype)
-            self._check_argtypes_for_fastpath()
             return
 
-
         # A callback into python
         if callable(argument) and not argsl:
             self.callable = argument
@@ -258,7 +256,7 @@
         if (sys.platform == 'win32' and isinstance(argument, int)
             and argsl):
             ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_)
-            self._com_index =  argument + 0x1000
+            self._com_index = argument + 0x1000
             self.name = argsl.pop(0)
             if argsl:
                 self.paramflags = argsl.pop(0)
@@ -280,6 +278,7 @@
             except SystemExit as e:
                 handle_system_exit(e)
                 raise
+
         return f
 
     def __call__(self, *args, **kwargs):
@@ -328,7 +327,7 @@
             # really slow".  Now we don't worry that much about slowness
             # of ctypes, and it's strange to get warnings for perfectly-
             # legal code.
-            #warnings.warn('C function without declared arguments called',
+            # warnings.warn('C function without declared arguments called',
             #              RuntimeWarning, stacklevel=2)
             argtypes = []
 
@@ -337,7 +336,7 @@
             if not args:
                 raise ValueError(
                     "native COM method call without 'this' parameter"
-                    )
+                )
             thisvalue = args[0]
             thisarg = cast(thisvalue, POINTER(POINTER(c_void_p)))
             keepalives, newargs, argtypes, outargs, errcheckargs = (
@@ -366,7 +365,6 @@
         return tuple(outargs)
 
     def _call_funcptr(self, funcptr, *newargs):
-
         if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO:
             tmp = _rawffi.get_errno()
             _rawffi.set_errno(get_errno())
@@ -431,7 +429,7 @@
             ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes]
             ffires = restype.get_ffi_argtype()
             return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires, 
self._flags_)
-        
+
         cdll = self.dll._handle
         try:
             ffi_argtypes = [argtype.get_ffi_argtype() for argtype in argtypes]
@@ -450,7 +448,7 @@
             # funcname -> _funcname@<n>
             # where n is 0, 4, 8, 12, ..., 128
             for i in range(33):
-                mangled_name = "_%s@%d" % (self.name, i*4)
+                mangled_name = "_%s@%d" % (self.name, i * 4)
                 try:
                     return cdll.getfunc(mangled_name,
                                         ffi_argtypes, ffi_restype,
@@ -492,7 +490,7 @@
         for argtype, arg in zip(argtypes, args):
             param = argtype.from_param(arg)
             _type_ = getattr(argtype, '_type_', None)
-            if _type_ == 'P': # special-case for c_void_p
+            if _type_ == 'P':  # special-case for c_void_p
                 param = param._get_buffer_value()
             elif self._is_primitive(argtype):
                 param = param.value
@@ -668,69 +666,11 @@
             self._needs_free = False
 
 
-def make_fastpath_subclass(CFuncPtr):
-    if CFuncPtr._is_fastpath:
-        return CFuncPtr
-    #
-    try:
-        return make_fastpath_subclass.memo[CFuncPtr]
-    except KeyError:
-        pass
-
-    class CFuncPtrFast(CFuncPtr):
-
-        _is_fastpath = True
-        _slowpath_allowed = True # set to False by tests
-
-        @classmethod
-        def enable_fastpath_maybe(cls, obj):
-            if (obj.callable is None and
-                obj._com_index is None):
-                obj.__class__ = cls
-
-        def __rollback(self):
-            assert self._slowpath_allowed
-            self.__class__ = CFuncPtr
-
-        # disable the fast path if we reset argtypes
-        def _setargtypes(self, argtypes):
-            self.__rollback()
-            self._setargtypes(argtypes)
-        argtypes = property(CFuncPtr._getargtypes, _setargtypes)
-
-        def _setcallable(self, func):
-            self.__rollback()
-            self.callable = func
-        callable = property(lambda x: None, _setcallable)
-
-        def _setcom_index(self, idx):
-            self.__rollback()
-            self._com_index = idx
-        _com_index = property(lambda x: None, _setcom_index)
-
-        def __call__(self, *args):
-            thisarg = None
-            argtypes = self._argtypes_
-            restype = self._restype_
-            funcptr = self._getfuncptr(argtypes, restype, thisarg)
-            try:
-                result = self._call_funcptr(funcptr, *args)
-                result, _ = self._do_errcheck(result, args)
-            except (TypeError, ArgumentError, UnicodeDecodeError):
-                assert self._slowpath_allowed
-                return CFuncPtr.__call__(self, *args)
-            return result
-
-    make_fastpath_subclass.memo[CFuncPtr] = CFuncPtrFast
-    return CFuncPtrFast
-make_fastpath_subclass.memo = {}
-
-
 def handle_system_exit(e):
     # issue #1194: if we get SystemExit here, then exit the interpreter.
     # Highly obscure imho but some people seem to depend on it.
     if sys.flags.inspect:
-        return   # Don't exit if -i flag was given.
+        return  # Don't exit if -i flag was given.
     else:
         code = e.code
         if isinstance(code, int):
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -46,8 +46,9 @@
 from rpython.jit.backend import detect_cpu
 try:
     if detect_cpu.autodetect().startswith('x86'):
-        working_modules.add('_vmprof')
-        working_modules.add('faulthandler')
+        if not sys.platform.startswith('openbsd'):
+            working_modules.add('_vmprof')
+            working_modules.add('faulthandler')
 except detect_cpu.ProcessorAutodetectError:
     pass
 
@@ -222,9 +223,6 @@
         BoolOption("withsmalllong", "use a version of 'long' in a C long long",
                    default=False),
 
-        BoolOption("withstrbuf", "use strings optimized for addition (ver 2)",
-                   default=False),
-
         BoolOption("withspecialisedtuple",
                    "use specialised tuples",
                    default=False),
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -39,3 +39,20 @@
 
 Internal refactoring of buffers and memoryviews. Memoryviews will now be
 accepted in a few more places, e.g. in compile().
+
+.. branch: sthalik/fix-signed-integer-sizes-1494493539409
+
+.. branch: cpyext-obj-stealing
+
+Redo much of the refcount semantics in PyList_{SG}etItem to closer match
+CPython and ensure the same PyObject stored in the list can be later
+retrieved
+
+.. branch: cpyext-recursionlimit
+
+Implement Py_EnterRecursiveCall and associated functions
+
+.. branch: pypy_ctypes_nosegfault_nofastpath
+
+Remove faulty fastpath from ctypes
+
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -690,7 +690,8 @@
         }.items():
         register_global(cpyname, 'PyTypeObject*', pypyexpr, header=pypy_decl)
 
-    for cpyname in '''PyMethodObject PyListObject PyLongObject'''.split():
+    for cpyname in '''PyMethodObject PyListObject PyLongObject
+                      PyBaseExceptionObject'''.split():
         FORWARD_DECLS.append('typedef struct { PyObject_HEAD } %s'
                              % (cpyname, ))
 build_exported_objects()
@@ -1613,7 +1614,6 @@
 
 @specialize.memo()
 def make_generic_cpy_call(FT, expect_null, convert_result):
-    from pypy.module.cpyext.pyobject import make_ref, from_ref
     from pypy.module.cpyext.pyobject import is_pyobj, as_pyobj
     from pypy.module.cpyext.pyobject import get_w_obj_and_decref
     from pypy.module.cpyext.pyerrors import PyErr_Occurred
diff --git a/pypy/module/cpyext/dictobject.py b/pypy/module/cpyext/dictobject.py
--- a/pypy/module/cpyext/dictobject.py
+++ b/pypy/module/cpyext/dictobject.py
@@ -257,7 +257,8 @@
 
     if w_dict is None:
         return 0
-
+    if not space.isinstance_w(w_dict, space.w_dict):
+        return 0 
     pos = ppos[0]
     py_obj = as_pyobj(space, w_dict)
     py_dict = rffi.cast(PyDictObject, py_obj)
@@ -268,6 +269,9 @@
         py_dict.c__tmpkeys = create_ref(space, w_keys)
         Py_IncRef(space, py_dict.c__tmpkeys)
     else:
+        if not py_dict.c__tmpkeys:
+            # pos should have been 0, cannot fail so return 0
+            return 0;
         w_keys = from_ref(space, py_dict.c__tmpkeys)
     ppos[0] += 1
     if pos >= space.len_w(w_keys):
diff --git a/pypy/module/cpyext/eval.py b/pypy/module/cpyext/eval.py
--- a/pypy/module/cpyext/eval.py
+++ b/pypy/module/cpyext/eval.py
@@ -1,6 +1,8 @@
 from pypy.interpreter.error import oefmt
 from pypy.interpreter.astcompiler import consts
 from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.rarithmetic import widen
 from pypy.module.cpyext.api import (
     cpython_api, CANNOT_FAIL, CONST_STRING, FILEP, fread, feof, Py_ssize_tP,
     cpython_struct, is_valid_fp)
@@ -227,4 +229,51 @@
     cf.c_cf_flags = rffi.cast(rffi.INT, flags)
     return result
 
+@cpython_api([], rffi.INT_real, error=CANNOT_FAIL)
+def Py_GetRecursionLimit(space):
+    from pypy.module.sys.vm import getrecursionlimit
+    return space.int_w(getrecursionlimit(space))
 
+@cpython_api([rffi.INT_real], lltype.Void, error=CANNOT_FAIL)
+def Py_SetRecursionLimit(space, limit):
+    from pypy.module.sys.vm import setrecursionlimit
+    setrecursionlimit(space, widen(limit))
+
+limit = 0 # for testing
+
+@cpython_api([rffi.CCHARP], rffi.INT_real, error=1)
+def Py_EnterRecursiveCall(space, where):
+    """Marks a point where a recursive C-level call is about to be performed.
+
+    If USE_STACKCHECK is defined, this function checks if the the OS
+    stack overflowed using PyOS_CheckStack().  In this is the case, it
+    sets a MemoryError and returns a nonzero value.
+
+    The function then checks if the recursion limit is reached.  If this is the
+    case, a RuntimeError is set and a nonzero value is returned.
+    Otherwise, zero is returned.
+
+    where should be a string such as " in instance check" to be
+    concatenated to the RuntimeError message caused by the recursion depth
+    limit."""
+    if not we_are_translated():
+        # XXX hack since the stack checks only work translated
+        global limit
+        limit += 1
+        if limit > 10:
+            raise oefmt(space.w_RuntimeError, 
+                 "maximum recursion depth exceeded%s", rffi.charp2str(where))
+        return 0
+    from rpython.rlib.rstack import stack_almost_full
+    if stack_almost_full():
+        raise oefmt(space.w_RuntimeError,
+                 "maximum recursion depth exceeded%s", rffi.charp2str(where))
+    return 0
+
+@cpython_api([], lltype.Void)
+def Py_LeaveRecursiveCall(space):
+    """Ends a Py_EnterRecursiveCall().  Must be called once for each
+    successful invocation of Py_EnterRecursiveCall()."""
+    # A NOP in PyPy
+    if not we_are_translated():
+        limit = 0
diff --git a/pypy/module/cpyext/include/listobject.h 
b/pypy/module/cpyext/include/listobject.h
--- a/pypy/module/cpyext/include/listobject.h
+++ b/pypy/module/cpyext/include/listobject.h
@@ -1,1 +1,1 @@
-#define PyList_GET_ITEM(o, i) PyList_GetItem((PyObject*)(o), (i))
+/* empty */
diff --git a/pypy/module/cpyext/listobject.py b/pypy/module/cpyext/listobject.py
--- a/pypy/module/cpyext/listobject.py
+++ b/pypy/module/cpyext/listobject.py
@@ -1,9 +1,10 @@
 
+from rpython.rlib.objectmodel import always_inline
 from rpython.rtyper.lltypesystem import rffi, lltype
 from pypy.module.cpyext.api import (cpython_api, CANNOT_FAIL, Py_ssize_t,
                                     build_type_checkers)
 from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
-from pypy.module.cpyext.pyobject import Py_DecRef, PyObject, make_ref
+from pypy.module.cpyext.pyobject import decref, incref, PyObject, make_ref
 from pypy.objspace.std.listobject import W_ListObject
 from pypy.interpreter.error import oefmt
 
@@ -19,59 +20,68 @@
     PySequence_SetItem()  or expose the object to Python code before
     setting all items to a real object with PyList_SetItem().
     """
-    return space.newlist([None] * len)
+    w_list = space.newlist([None] * len)
+    #w_list.convert_to_cpy_strategy(space)
+    return w_list
 
-@cpython_api([rffi.VOIDP, Py_ssize_t, PyObject], PyObject, error=CANNOT_FAIL,
-             result_borrowed=True)
-def PyList_SET_ITEM(space, w_list, index, w_item):
-    """Macro form of PyList_SetItem() without error checking. This is normally
+@always_inline
+def get_list_storage(space, w_list):
+    from pypy.module.cpyext.sequence import CPyListStrategy
+    assert isinstance(w_list, W_ListObject)
+    w_list.convert_to_cpy_strategy(space)
+    return CPyListStrategy.unerase(w_list.lstorage)
+
+@cpython_api([rffi.VOIDP, Py_ssize_t, PyObject], lltype.Void, 
error=CANNOT_FAIL)
+def PyList_SET_ITEM(space, w_list, index, py_item):
+    """Form of PyList_SetItem() without error checking. This is normally
     only used to fill in new lists where there is no previous content.
 
-    This function "steals" a reference to item, and, unlike PyList_SetItem(),
-    does not discard a reference to any item that it being replaced; any
-    reference in list at position i will be leaked.
+    "steals" a reference to item, and, unlike PyList_SetItem(), does not
+    discard a reference to any item that it being replaced; any reference in
+    list at position i will be leaked.
     """
-    assert isinstance(w_list, W_ListObject)
+    storage = get_list_storage(space, w_list)
     assert 0 <= index < w_list.length()
-    # Deliberately leak, so that it can be safely decref'd.
-    make_ref(space, w_list.getitem(index))
-    Py_DecRef(space, w_item)
-    w_list.setitem(index, w_item)
-    return w_item
-
+    storage._elems[index] = py_item
 
 @cpython_api([PyObject, Py_ssize_t, PyObject], rffi.INT_real, error=-1)
-def PyList_SetItem(space, w_list, index, w_item):
+def PyList_SetItem(space, w_list, index, py_item):
     """Set the item at index index in list to item.  Return 0 on success
     or -1 on failure.
-    
+
     This function "steals" a reference to item and discards a reference to
     an item already in the list at the affected position.
     """
-    Py_DecRef(space, w_item)
     if not isinstance(w_list, W_ListObject):
+        decref(space, w_item)
         PyErr_BadInternalCall(space)
     if index < 0 or index >= w_list.length():
+        decref(space, w_item)
         raise oefmt(space.w_IndexError, "list assignment index out of range")
-    w_list.setitem(index, w_item)
+    storage = get_list_storage(space, w_list)
+    py_old = storage._elems[index]
+    storage._elems[index] = py_item
+    decref(w_list.space, py_old)
     return 0
 
-@cpython_api([PyObject, Py_ssize_t], PyObject, result_borrowed=True)
+@cpython_api([rffi.VOIDP, Py_ssize_t], PyObject, result_is_ll=True)
+def PyList_GET_ITEM(space, w_list, index):
+    storage = get_list_storage(space, w_list)
+    assert 0 <= index < w_list.length()
+    return storage._elems[index]     # borrowed ref
+
+@cpython_api([PyObject, Py_ssize_t], PyObject, result_is_ll=True)
 def PyList_GetItem(space, w_list, index):
     """Return the object at position pos in the list pointed to by p.  The
     position must be positive, indexing from the end of the list is not
     supported.  If pos is out of bounds, return NULL and set an
     IndexError exception."""
-    from pypy.module.cpyext.sequence import CPyListStrategy
     if not isinstance(w_list, W_ListObject):
         PyErr_BadInternalCall(space)
     if index < 0 or index >= w_list.length():
         raise oefmt(space.w_IndexError, "list index out of range")
-    cpy_strategy = space.fromcache(CPyListStrategy)
-    if w_list.strategy is not cpy_strategy:
-        w_list.ensure_object_strategy() # make sure we can return a borrowed 
obj
-    w_res = w_list.getitem(index)
-    return w_res     # borrowed ref
+    storage = get_list_storage(space, w_list)
+    return storage._elems[index]     # borrowed ref
 
 
 @cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -30,8 +30,7 @@
         return subtype_dealloc.api_func
 
     def allocate(self, space, w_type, itemcount=0):
-        # similar to PyType_GenericAlloc?
-        # except that it's not related to any pypy object.
+        # typically called from PyType_GenericAlloc via typedescr.allocate
         # this returns a PyObject with ob_refcnt == 1.
 
         pytype = as_pyobj(space, w_type)
@@ -250,6 +249,8 @@
     w_obj = rawrefcount.to_obj(W_Root, pyobj)
     return w_obj is not None and w_obj is not w_marker_deallocating
 
+def w_obj_has_pyobj(w_obj):
+    return bool(rawrefcount.from_obj(PyObject, w_obj))
 
 def is_pyobj(x):
     if x is None or isinstance(x, W_Root):
@@ -275,13 +276,14 @@
     """
     if is_pyobj(obj):
         pyobj = rffi.cast(PyObject, obj)
+        at_least = 1
     else:
         pyobj = as_pyobj(space, obj, w_userdata)
+        at_least = rawrefcount.REFCNT_FROM_PYPY
     if pyobj:
-        assert pyobj.c_ob_refcnt > 0
+        assert pyobj.c_ob_refcnt >= at_least
         pyobj.c_ob_refcnt += 1
-        if not is_pyobj(obj):
-            keepalive_until_here(obj)
+        keepalive_until_here(obj)
     return pyobj
 
 
@@ -315,9 +317,14 @@
         obj = rffi.cast(PyObject, obj)
         if obj:
             assert obj.c_ob_refcnt > 0
+            assert obj.c_ob_pypy_link == 0 or obj.c_ob_refcnt > 
rawrefcount.REFCNT_FROM_PYPY
             obj.c_ob_refcnt -= 1
             if obj.c_ob_refcnt == 0:
                 _Py_Dealloc(space, obj)
+            #else:
+            #    w_obj = rawrefcount.to_obj(W_Root, ref)
+            #    if w_obj is not None:
+            #        assert obj.c_ob_refcnt >= rawrefcount.REFCNT_FROM_PYPY
     else:
         get_w_obj_and_decref(space, obj)
 
diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py
--- a/pypy/module/cpyext/sequence.py
+++ b/pypy/module/cpyext/sequence.py
@@ -256,8 +256,9 @@
     def setitem(self, w_list, index, w_obj):
         storage = self.unerase(w_list.lstorage)
         index = self._check_index(index, storage._length)
-        decref(w_list.space, storage._elems[index])
+        py_old = storage._elems[index]
         storage._elems[index] = make_ref(w_list.space, w_obj)
+        decref(w_list.space, py_old)
 
     def length(self, w_list):
         storage = self.unerase(w_list.lstorage)
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -14,7 +14,7 @@
     ssizessizeargfunc, ssizeobjargproc, iternextfunc, initproc, richcmpfunc,
     cmpfunc, hashfunc, descrgetfunc, descrsetfunc, objobjproc, objobjargproc,
     getbufferproc, releasebufferproc, ssizessizeobjargproc)
-from pypy.module.cpyext.pyobject import make_ref, decref, as_pyobj
+from pypy.module.cpyext.pyobject import make_ref, decref, as_pyobj, from_ref
 from pypy.module.cpyext.pyerrors import PyErr_Occurred
 from pypy.module.cpyext.memoryobject import fill_Py_buffer
 from pypy.module.cpyext.state import State
@@ -256,7 +256,7 @@
     check_num_args(space, w_args, 1)
     args_w = space.fixedview(w_args)
     index = space.int_w(space.index(args_w[0]))
-    null = lltype.nullptr(PyObject.TO)
+    null = rffi.cast(PyObject, 0)
     res = generic_cpy_call(space, func_target, w_self, index, null)
     if rffi.cast(lltype.Signed, res) == -1:
         space.fromcache(State).check_and_raise_exception(always=True)
@@ -285,7 +285,8 @@
     func_target = rffi.cast(objobjargproc, func)
     check_num_args(space, w_args, 1)
     w_key, = space.fixedview(w_args)
-    res = generic_cpy_call(space, func_target, w_self, w_key, None)
+    null = rffi.cast(PyObject, 0)
+    res = generic_cpy_call(space, func_target, w_self, w_key, null)
     if rffi.cast(lltype.Signed, res) == -1:
         space.fromcache(State).check_and_raise_exception(always=True)
     return space.w_None
@@ -611,6 +612,8 @@
             handled = True
 
     for tp_name, attr in [('tp_hash', '__hash__'),
+                          ('tp_as_sequence.c_sq_length', '__len__'),
+                          ('tp_as_mapping.c_mp_length', '__len__'),
                          ]:
         if name == tp_name:
             slot_fn = w_type.getdictvalue(space, attr)
@@ -636,7 +639,8 @@
                           ('tp_as_number.c_nb_xor', '__xor__'),
                           ('tp_as_number.c_nb_or', '__or__'),
                           ('tp_as_sequence.c_sq_concat', '__add__'),
-                          ('tp_as_sequence.c_sq_inplace_concat', '__iadd__')
+                          ('tp_as_sequence.c_sq_inplace_concat', '__iadd__'),
+                          ('tp_as_mapping.c_mp_subscript', '__getitem__'),
                           ]:
         if name == tp_name:
             slot_fn = w_type.getdictvalue(space, attr)
@@ -650,7 +654,7 @@
             handled = True
 
     # binary-with-Py_ssize_t-type
-    for tp_name, attr in [('tp_as_sequence.c_sq_item', '__getitem'),
+    for tp_name, attr in [('tp_as_sequence.c_sq_item', '__getitem__'),
                           ('tp_as_sequence.c_sq_repeat', '__mul__'),
                           ('tp_as_sequence.c_sq_repeat', '__mul__'),
                           ('tp_as_sequence.c_sq_inplace_repeat', '__imul__'),
@@ -679,7 +683,48 @@
             def slot_func(space, w_self, w_arg1, w_arg2):
                 return space.call_function(slot_fn, w_self, w_arg1, w_arg2)
             handled = True
+    # ternary-with-void returning-Py_size_t-type
+    for tp_name, attr in [('tp_as_mapping.c_mp_ass_subscript', '__setitem__'),
+                         ]:
+        if name == tp_name:
+            slot_ass = w_type.getdictvalue(space, attr)
+            if slot_ass is None:
+                return
+            slot_del = w_type.getdictvalue(space, '__delitem__')
+            if slot_del is None:
+                return
 
+            @slot_function([PyObject, PyObject, PyObject], rffi.INT_real, 
error=-1)
+            @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), 
typedef.name))
+            def slot_func(space, w_self, w_arg1, arg2):
+                if arg2:
+                    w_arg2 = from_ref(space, rffi.cast(PyObject, arg2))
+                    space.call_function(slot_ass, w_self, w_arg1, w_arg2)
+                else:
+                    space.call_function(slot_del, w_self, w_arg1)
+                return 0
+            handled = True
+    # ternary-Py_size_t-void returning-Py_size_t-type
+    for tp_name, attr in [('tp_as_sequence.c_sq_ass_item', '__setitem__'),
+                         ]:
+        if name == tp_name:
+            slot_ass = w_type.getdictvalue(space, attr)
+            if slot_ass is None:
+                return
+            slot_del = w_type.getdictvalue(space, '__delitem__')
+            if slot_del is None:
+                return
+
+            @slot_function([PyObject, lltype.Signed, PyObject], rffi.INT_real, 
error=-1)
+            @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), 
typedef.name))
+            def slot_func(space, w_self, arg1, arg2):
+                if arg2:
+                    w_arg2 = from_ref(space, rffi.cast(PyObject, arg2))
+                    space.call_function(slot_ass, w_self, space.newint(arg1), 
w_arg2)
+                else:
+                    space.call_function(slot_del, w_self, space.newint(arg1))
+                return 0
+            handled = True
     if handled:
         pass
     elif name == 'tp_setattro':
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -483,29 +483,6 @@
     0 on success, -1 on failure."""
     raise NotImplementedError
 
-@cpython_api([rffi.CCHARP], rffi.INT_real, error=-1)
-def Py_EnterRecursiveCall(space, where):
-    """Marks a point where a recursive C-level call is about to be performed.
-
-    If USE_STACKCHECK is defined, this function checks if the the OS
-    stack overflowed using PyOS_CheckStack().  In this is the case, it
-    sets a MemoryError and returns a nonzero value.
-
-    The function then checks if the recursion limit is reached.  If this is the
-    case, a RuntimeError is set and a nonzero value is returned.
-    Otherwise, zero is returned.
-
-    where should be a string such as " in instance check" to be
-    concatenated to the RuntimeError message caused by the recursion depth
-    limit."""
-    raise NotImplementedError
-
-@cpython_api([], lltype.Void)
-def Py_LeaveRecursiveCall(space):
-    """Ends a Py_EnterRecursiveCall().  Must be called once for each
-    successful invocation of Py_EnterRecursiveCall()."""
-    raise NotImplementedError
-
 @cpython_api([PyObject], rffi.INT_real, error=-1)
 def Py_ReprEnter(space, object):
     """Called at the beginning of the tp_repr implementation to
diff --git a/pypy/module/cpyext/test/array.c b/pypy/module/cpyext/test/array.c
--- a/pypy/module/cpyext/test/array.c
+++ b/pypy/module/cpyext/test/array.c
@@ -2330,6 +2330,7 @@
             for (nn = 0; nn < n; nn++)
             {
                 v = PyList_GetItem(obj1, nn);
+                Py_INCREF(v);
                 PyList_SetItem(ret, nn+ii*n, v);
             }
         return ret;
@@ -2345,6 +2346,7 @@
             for (nn = 0; nn < n; nn++)
             {
                 v = PyList_GetItem(obj2, nn);
+                Py_INCREF(v);
                 PyList_SetItem(ret, nn+ii*n, v);
             }
         return ret;
diff --git a/pypy/module/cpyext/test/test_dictobject.py 
b/pypy/module/cpyext/test/test_dictobject.py
--- a/pypy/module/cpyext/test/test_dictobject.py
+++ b/pypy/module/cpyext/test/test_dictobject.py
@@ -260,4 +260,60 @@
             ])
         d = module.get_type_dict(1)
         assert d['real'].__get__(1, 1) == 1
-
+    def test_advanced(self):
+        module = self.import_extension('foo', [
+            ("dict_len", "METH_O",
+            '''
+                int ret = args->ob_type->tp_as_mapping->mp_length(args);
+                return PyLong_FromLong(ret);
+            '''),
+            ("dict_setitem", "METH_VARARGS",
+            '''
+                int ret;
+                PyObject * dict = PyTuple_GetItem(args, 0);
+                if (PyTuple_Size(args) < 3 || !dict || 
+                        !dict->ob_type->tp_as_mapping ||
+                        !dict->ob_type->tp_as_mapping->mp_ass_subscript)
+                    return PyLong_FromLong(-1);
+                ret = dict->ob_type->tp_as_mapping->mp_ass_subscript(
+                        dict, PyTuple_GetItem(args, 1),
+                        PyTuple_GetItem(args, 2));
+                return PyLong_FromLong(ret);
+            '''),
+            ("dict_delitem", "METH_VARARGS",
+            '''
+                int ret;
+                PyObject * dict = PyTuple_GetItem(args, 0);
+                if (PyTuple_Size(args) < 2 || !dict || 
+                        !dict->ob_type->tp_as_mapping ||
+                        !dict->ob_type->tp_as_mapping->mp_ass_subscript)
+                    return PyLong_FromLong(-1);
+                ret = dict->ob_type->tp_as_mapping->mp_ass_subscript(
+                        dict, PyTuple_GetItem(args, 1), NULL);
+                return PyLong_FromLong(ret);
+            '''),
+            ("dict_next", "METH_VARARGS",
+            '''
+                PyObject *key, *value;
+                PyObject *arg = NULL;
+                Py_ssize_t pos = 0;
+                int ret = 0;
+                if ((PyArg_ParseTuple(args, "|O", &arg))) {
+                    if (arg && PyDict_Check(arg)) {
+                        while (PyDict_Next(arg, &pos, &key, &value))
+                            ret ++;
+                        /* test no crash if pos is not reset to 0*/
+                        while (PyDict_Next(arg, &pos, &key, &value))
+                            ret ++;
+                    }
+                }
+                return PyLong_FromLong(ret);
+            '''),
+            ])
+        d = {'a': 1, 'b':2}
+        assert module.dict_len(d) == 2
+        assert module.dict_setitem(d, 'a', 'c') == 0
+        assert d['a'] == 'c'
+        assert module.dict_delitem(d, 'a') == 0
+        r = module.dict_next({'a': 1, 'b': 2})
+        assert r == 2
diff --git a/pypy/module/cpyext/test/test_eval.py 
b/pypy/module/cpyext/test/test_eval.py
--- a/pypy/module/cpyext/test/test_eval.py
+++ b/pypy/module/cpyext/test/test_eval.py
@@ -339,3 +339,30 @@
                 def nested_flags():
                     return module.get_flags()""", ns)
         assert ns['nested_flags']() == (0, 0)
+
+    def test_recursive_function(self):
+        module = self.import_extension('foo', [
+            ("call_recursive", "METH_NOARGS",
+             """
+                int res = 0;
+                int recurse(void) {
+                    if (Py_EnterRecursiveCall(" while calling recurse"))
+                        return -1;
+                    res ++;
+                    return recurse();
+                }
+                int oldlimit = Py_GetRecursionLimit();
+                Py_SetRecursionLimit(200);
+                res = recurse();
+                Py_SetRecursionLimit(oldlimit);
+                if (PyErr_Occurred())
+                    return NULL;
+                return PyLong_FromLong(res);
+             """),], prologue= ''' int recurse(void); '''
+            )
+        try:
+            res = module.call_recursive()
+        except RuntimeError as e:
+            assert 'while calling recurse' in str(e)
+        else:
+            assert False, "expected RuntimeError"  
diff --git a/pypy/module/cpyext/test/test_listobject.py 
b/pypy/module/cpyext/test/test_listobject.py
--- a/pypy/module/cpyext/test/test_listobject.py
+++ b/pypy/module/cpyext/test/test_listobject.py
@@ -38,10 +38,12 @@
         assert api.PyList_Insert(w_l, 0, space.wrap(1)) == 0
         assert api.PyList_Size(w_l) == 3
         assert api.PyList_Insert(w_l, 99, space.wrap(2)) == 0
-        assert space.unwrap(api.PyList_GetItem(w_l, 3)) == 2
+        assert api.PyObject_Compare(api.PyList_GetItem(w_l, 3),
+                                    space.wrap(2)) == 0
         # insert at index -1: next-to-last
         assert api.PyList_Insert(w_l, -1, space.wrap(3)) == 0
-        assert space.unwrap(api.PyList_GetItem(w_l, 3)) == 3
+        assert api.PyObject_Compare(api.PyList_GET_ITEM(w_l, 3),
+                                    space.wrap(3)) == 0
 
     def test_sort(self, space, api):
         l = space.newlist([space.wrap(1), space.wrap(0), space.wrap(7000)])
@@ -152,29 +154,35 @@
     def test_list_macros(self):
         """The PyList_* macros cast, and calls expecting that build."""
         module = self.import_extension('foo', [
-            ("test_macro_invocations", "METH_NOARGS",
+            ("test_macro_invocations", "METH_O",
              """
              PyObject* o = PyList_New(2);
              PyListObject* l = (PyListObject*)o;
 
+             Py_INCREF(args);
+             Py_INCREF(args);
+             PyList_SET_ITEM(o, 0, args);
+             PyList_SET_ITEM(l, 1, args);
 
-             Py_INCREF(o);
-             PyList_SET_ITEM(o, 0, o);
-             Py_INCREF(o);
-             PyList_SET_ITEM(l, 1, o);
+             if(PyList_GET_ITEM(o, 0) != PyList_GET_ITEM(l, 1))
+             {
+                PyErr_SetString(PyExc_AssertionError, "PyList_GET_ITEM error");
+                return NULL;
+             }
 
-             PyList_GET_ITEM(o, 0);
-             PyList_GET_ITEM(l, 1);
-
-             PyList_GET_SIZE(o);
-             PyList_GET_SIZE(l);
+             if(PyList_GET_SIZE(o) != PyList_GET_SIZE(l))
+             {
+                PyErr_SetString(PyExc_AssertionError, "PyList_GET_SIZE error");
+                return NULL;
+             }
 
              return o;
              """
             )
         ])
-        x = module.test_macro_invocations()
-        assert x[0] is x[1] is x
+        s = 'abcdef'
+        x = module.test_macro_invocations(s)
+        assert x[0] is x[1] is s
 
     def test_get_item_macro(self):
         module = self.import_extension('foo', [
@@ -183,39 +191,96 @@
                 PyObject* o, *o2, *o3;
                 o = PyList_New(1);
 
-                o2 = PyLong_FromLong(0);
+                o2 = PyBytes_FromString("test_get_item0");
+                Py_INCREF(o2);
                 PyList_SET_ITEM(o, 0, o2);
-                o2 = NULL;
 
                 o3 = PyList_GET_ITEM(o, 0);
                 Py_INCREF(o3);
-                Py_CLEAR(o);
+                Py_DECREF(o);
+                Py_DECREF(o2);
                 return o3;
              """)])
-        assert module.test_get_item() == 0
+        assert module.test_get_item() == b'test_get_item0'
 
-    def test_set_item_macro(self):
+    def test_item_refcounts(self):
         """PyList_SET_ITEM leaks a reference to the target."""
         module = self.import_extension('foo', [
-             ("test_refcount_diff_after_setitem", "METH_NOARGS",
+             ("test_refcount_diff", "METH_VARARGS",
              """
-                PyObject* o = PyList_New(0);
-                PyObject* o2 = PyList_New(0);
-                Py_ssize_t refcount, new_refcount;
+                /* test that the refcount differences for functions
+                 * are correct. diff1 - expected refcount diff for i1,
+                 *              diff2 - expected refcount diff for i2
+                 */
+                #define CHECKCOUNT(diff1, diff2, action) \
+                    new_count1 = Py_REFCNT(i1); \
+                    new_count2 = Py_REFCNT(i2); \
+                    diff = new_count1 - old_count1; \
+                    if (diff != diff1) {\
+                        sprintf(errbuffer, action \
+                            " i1 expected diff of %ld got %ld", (long)diff1, 
(long)diff); \
+                    PyErr_SetString(PyExc_AssertionError, errbuffer); \
+                    return NULL; } \
+                    diff = new_count2 - old_count2; \
+                    if (diff != diff2) {\
+                        sprintf(errbuffer, action \
+                            " i2 expected diff of %ld got %ld", (long)diff2, 
(long)diff); \
+                    PyErr_SetString(PyExc_AssertionError, errbuffer); \
+                    return NULL; } \
+                    old_count1 = new_count1; \
+                    old_count2 = new_count2;
 
-                PyList_Append(o, o2);  // does not steal o2
+                PyObject* tmp, *o = PyList_New(0);
+                char errbuffer[1024];
+                PyObject* i1 = PyTuple_GetItem(args, 0);
+                PyObject* i2 = PyTuple_GetItem(args, 1);
+                Py_ssize_t old_count1, new_count1;
+                Py_ssize_t old_count2, new_count2;
+                Py_ssize_t diff;
+                int ret;
 
-                refcount = Py_REFCNT(o2);
+                old_count1 = Py_REFCNT(i1);
+                old_count2 = Py_REFCNT(i2);
 
-                // Steal a reference to o2, but leak the old reference to o2.
-                // The net result should be no change in refcount.
-                PyList_SET_ITEM(o, 0, o2);
+                ret = PyList_Append(o, i1);
+                if (ret != 0) 
+                    return NULL;
+                /* check the result of Append(), and also force the list
+                   to use the CPyListStrategy now */
+                if (PyList_GET_ITEM(o, 0) != i1)
+                {
+                    PyErr_SetString(PyExc_AssertionError, "Append() error?");
+                    return NULL;
+                }
+                CHECKCOUNT(1, 0, "PyList_Append");
 
-                new_refcount = Py_REFCNT(o2);
+                Py_INCREF(i2);   /* for PyList_SET_ITEM */
+                CHECKCOUNT(0, 1, "Py_INCREF");
 
-                Py_CLEAR(o);
-                Py_DECREF(o2); // append incref'd.
-                // Py_CLEAR(o2);  // naive implementation would fail here.
-                return PyLong_FromSsize_t(new_refcount - refcount);
+                PyList_SET_ITEM(o, 0, i2);
+                CHECKCOUNT(0, 0, "PyList_SET_ITEM");
+
+                tmp = PyList_GET_ITEM(o, 0);
+                if (tmp != i2)
+                {
+                    PyErr_SetString(PyExc_AssertionError, "SetItem() error?");
+                    return NULL;
+                }
+                CHECKCOUNT(0, 0, "PyList_GET_ITEM");
+
+                PyList_SetItem(o, 0, i1);
+                CHECKCOUNT(0, -1, "PyList_Set_Item");
+
+                PyList_GetItem(o, 0);
+                CHECKCOUNT(0, 0, "PyList_Get_Item");
+
+                Py_DECREF(o); 
+                #ifndef PYPY_VERSION
+                {
+                    // PyPy deletes only at teardown
+                    CHECKCOUNT(-1, 0, "Py_DECREF(o)");
+                }
+                #endif
+                return PyLong_FromSsize_t(0);
              """)])
-        assert module.test_refcount_diff_after_setitem() == 0
+        assert module.test_refcount_diff(["first"], ["second"]) == 0
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -23,7 +23,7 @@
     W_PyCMethodObject, W_PyCFunctionObject)
 from pypy.module.cpyext.modsupport import convert_method_defs
 from pypy.module.cpyext.pyobject import (
-    PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
+    PyObject, make_ref, from_ref, get_typedescr, make_typedescr,
     track_reference, Py_DecRef, as_pyobj)
 from pypy.module.cpyext.slotdefs import (
     slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function,
diff --git a/pypy/module/cpyext/unicodeobject.py 
b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -730,7 +730,7 @@
 if sys.platform == 'win32':
     make_conversion_functions('MBCS', 'mbcs')
 
-@cpython_api([rffi.CCHARP, Py_ssize_t, rffi.CCHARP, rffi.INTP], PyObject)
+@cpython_api([rffi.CCHARP, Py_ssize_t, CONST_STRING, rffi.INTP], PyObject)
 def PyUnicode_DecodeUTF16(space, s, size, llerrors, pbyteorder):
     """Decode length bytes from a UTF-16 encoded buffer string and return the
     corresponding Unicode object.  errors (if non-NULL) defines the error
diff --git a/pypy/module/test_lib_pypy/README.txt 
b/pypy/module/test_lib_pypy/README.txt
new file mode 100644
--- /dev/null
+++ b/pypy/module/test_lib_pypy/README.txt
@@ -0,0 +1,4 @@
+This directory contains app-level tests are supposed to be run *after*
+translation. So you run them by saying:
+
+pypy pytest.py <testfile.py>
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/README 
b/pypy/module/test_lib_pypy/ctypes_tests/README
new file mode 100644
--- /dev/null
+++ b/pypy/module/test_lib_pypy/ctypes_tests/README
@@ -0,0 +1,8 @@
+-------Ctypes tests------
+
+Unlike the other tests in the PyPy sources, these tests are assumed to run 
after the translation is complete.
+Therefore, using the resulting binary, you can then call, for example:
+
+/path/to/your_modified_pypy_binary pytest.py 
pypy/module/test_lib_pypy/ctypes_tests/test_libc.py
+
+This also applies to any other test in ctypes_tests.
\ No newline at end of file
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py 
b/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py
deleted file mode 100644
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_fastpath.py
+++ /dev/null
@@ -1,128 +0,0 @@
-from ctypes import CDLL, POINTER, pointer, c_byte, c_int, c_char_p, CFUNCTYPE, 
c_void_p, c_size_t
-import sys
-import py
-from support import BaseCTypesTestChecker
-
-class MyCDLL(CDLL):
-    def __getattr__(self, attr):
-        fn = self[attr] # this way it's not cached as an attribute
-        fn._slowpath_allowed = False
-        return fn
-
-def setup_module(mod):
-    import conftest
-    _ctypes_test = str(conftest.sofile)
-    mod.dll = MyCDLL(_ctypes_test)  # slowpath not allowed
-    mod.dll2 = CDLL(_ctypes_test)   # slowpath allowed
-
-
-class TestFastpath(BaseCTypesTestChecker):
-
-    def test_fastpath_forbidden(self):
-        def myfunc():
-            pass
-        #
-        tf_b = dll.tf_b
-        tf_b.restype = c_byte
-        #
-        # so far, it's still using the slowpath
-        assert not tf_b._is_fastpath
-        tf_b.callable = myfunc
-        tf_b.argtypes = (c_byte,)
-        # errcheck prevented the fastpath to kick in
-        assert not tf_b._is_fastpath
-        #
-        del tf_b.callable
-        tf_b.argtypes = (c_byte,) # try to re-enable the fastpath
-        assert tf_b._is_fastpath
-        #
-        assert not tf_b._slowpath_allowed
-        py.test.raises(AssertionError, "tf_b.callable = myfunc")
-        py.test.raises(AssertionError, "tf_b('aaa')") # force a TypeError
-
-    def test_simple_args(self):
-        tf_b = dll.tf_b
-        tf_b.restype = c_byte
-        tf_b.argtypes = (c_byte,)
-        assert tf_b(-126) == -42
-
-    def test_from_cfunctype(self):
-        from _ctypes import _memmove_addr
-        functype = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)
-        my_memmove = functype(_memmove_addr)
-        assert my_memmove._is_fastpath
-
-    def test_undeclared_restype(self):
-        # make sure we get a fresh function
-        try:
-            del dll.tf_i
-        except AttributeError:
-            pass
-        tf_i = dll.tf_i
-        assert not tf_i._is_fastpath
-        tf_i.argtypes = (c_int,)
-        assert tf_i._is_fastpath
-        assert tf_i(12) == 4
-
-    def test_pointer_args(self):
-        f = dll._testfunc_p_p
-        f.restype = POINTER(c_int)
-        f.argtypes = [POINTER(c_int)]
-        v = c_int(42)
-        result = f(pointer(v))
-        assert type(result) == POINTER(c_int)
-        assert result.contents.value == 42
-
-    def test_simple_pointer_args(self):
-        f = dll.my_strchr
-        f.argtypes = [c_char_p, c_int]
-        f.restype = c_char_p
-        mystr = c_char_p("abcd")
-        result = f(mystr, ord("b"))
-        assert result == "bcd"
-
-    def test_strings(self):
-        f = dll.my_strchr
-        f.argtypes = [c_char_p, c_int]
-        f.restype = c_char_p
-        result = f("abcd", ord("b"))
-        assert result == "bcd"
-
-    def test_errcheck(self):
-        def errcheck(result, func, args):
-            return 'hello'
-        tf_b = dll.tf_b
-        tf_b.restype = c_byte
-        tf_b.argtypes = (c_byte,)
-        tf_b.errcheck = errcheck
-        assert tf_b(-126) == 'hello'
-
-    def test_array_to_ptr(self):
-        ARRAY = c_int * 8
-        func = dll._testfunc_ai8
-        func.restype = POINTER(c_int)
-        func.argtypes = [ARRAY]
-        array = ARRAY(1, 2, 3, 4, 5, 6, 7, 8)
-        ptr = func(array)
-        assert ptr[0] == 1
-        assert ptr[7] == 8
-
-
-class TestFallbackToSlowpath(BaseCTypesTestChecker):
-
-    def test_argtypes_is_None(self):
-        tf_b = dll2.tf_b
-        tf_b.restype = c_byte
-        tf_b.argtypes = (c_char_p,)  # this is intentionally wrong
-        tf_b.argtypes = None # kill the fast path
-        assert not tf_b._is_fastpath
-        assert tf_b(-126) == -42
-
-    def test_callable_is_None(self):
-        tf_b = dll2.tf_b
-        tf_b.restype = c_byte
-        tf_b.argtypes = (c_byte,)
-        tf_b.callable = lambda x: x+1
-        assert not tf_b._is_fastpath
-        assert tf_b(-126) == -125
-        tf_b.callable = None
diff --git a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py 
b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
--- a/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
+++ b/pypy/module/test_lib_pypy/ctypes_tests/test_functions.py
@@ -478,7 +478,7 @@
         raises(ArgumentError, lambda: callback((1, 2, 3, 4), POINT()))
 
     def test_argument_conversion_and_checks(self):
-        py.test.skip("XXX currently broken on PyPy, sorry")
+        #This test is designed to check for segfaults if the wrong type of 
argument is passed as parameter
         strlen = dll.my_strchr
         strlen.argtypes = [c_char_p, c_int]
         strlen.restype = c_char_p
diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py
--- a/pypy/objspace/std/bytesobject.py
+++ b/pypy/objspace/std/bytesobject.py
@@ -580,55 +580,31 @@
         return space.newint(x)
 
     def descr_eq(self, space, w_other):
-        if space.config.objspace.std.withstrbuf:
-            from pypy.objspace.std.strbufobject import W_StringBufferObject
-            if isinstance(w_other, W_StringBufferObject):
-                return space.newbool(self._value == w_other.force())
         if not isinstance(w_other, W_BytesObject):
             return space.w_NotImplemented
         return space.newbool(self._value == w_other._value)
 
     def descr_ne(self, space, w_other):
-        if space.config.objspace.std.withstrbuf:
-            from pypy.objspace.std.strbufobject import W_StringBufferObject
-            if isinstance(w_other, W_StringBufferObject):
-                return space.newbool(self._value != w_other.force())
         if not isinstance(w_other, W_BytesObject):
             return space.w_NotImplemented
         return space.newbool(self._value != w_other._value)
 
     def descr_lt(self, space, w_other):
-        if space.config.objspace.std.withstrbuf:
-            from pypy.objspace.std.strbufobject import W_StringBufferObject
-            if isinstance(w_other, W_StringBufferObject):
-                return space.newbool(self._value < w_other.force())
         if not isinstance(w_other, W_BytesObject):
             return space.w_NotImplemented
         return space.newbool(self._value < w_other._value)
 
     def descr_le(self, space, w_other):
-        if space.config.objspace.std.withstrbuf:
-            from pypy.objspace.std.strbufobject import W_StringBufferObject
-            if isinstance(w_other, W_StringBufferObject):
-                return space.newbool(self._value <= w_other.force())
         if not isinstance(w_other, W_BytesObject):
             return space.w_NotImplemented
         return space.newbool(self._value <= w_other._value)
 
     def descr_gt(self, space, w_other):
-        if space.config.objspace.std.withstrbuf:
-            from pypy.objspace.std.strbufobject import W_StringBufferObject
-            if isinstance(w_other, W_StringBufferObject):
-                return space.newbool(self._value > w_other.force())
         if not isinstance(w_other, W_BytesObject):
             return space.w_NotImplemented
         return space.newbool(self._value > w_other._value)
 
     def descr_ge(self, space, w_other):
-        if space.config.objspace.std.withstrbuf:
-            from pypy.objspace.std.strbufobject import W_StringBufferObject
-            if isinstance(w_other, W_StringBufferObject):
-                return space.newbool(self._value >= w_other.force())
         if not isinstance(w_other, W_BytesObject):
             return space.w_NotImplemented
         return space.newbool(self._value >= w_other._value)
@@ -637,18 +613,6 @@
 
     _StringMethods_descr_add = descr_add
     def descr_add(self, space, w_other):
-        if space.config.objspace.std.withstrbuf:
-            from pypy.objspace.std.strbufobject import W_StringBufferObject
-            try:
-                other = self._op_val(space, w_other)
-            except OperationError as e:
-                if e.match(space, space.w_TypeError):
-                    return space.w_NotImplemented
-                raise
-            builder = StringBuilder()
-            builder.append(self._value)
-            builder.append(other)
-            return W_StringBufferObject(builder)
         return self._StringMethods_descr_add(space, w_other)
 
     _StringMethods_descr_join = descr_join
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -229,15 +229,13 @@
         return list(items)
 
     def switch_to_object_strategy(self):
+        object_strategy = self.space.fromcache(ObjectListStrategy)
+        if self.strategy is object_strategy:
+            return
         list_w = self.getitems()
-        object_strategy = self.space.fromcache(ObjectListStrategy)
         self.strategy = object_strategy
         object_strategy.init_from_list_w(self, list_w)
 
-    def ensure_object_strategy(self):     # for cpyext
-        if self.strategy is not self.space.fromcache(ObjectListStrategy):
-            self.switch_to_object_strategy()
-
     def _temporarily_as_objects(self):
         if self.strategy is self.space.fromcache(ObjectListStrategy):
             return self
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
@@ -18,7 +18,7 @@
 # Object imports
 from pypy.objspace.std.boolobject import W_BoolObject
 from pypy.objspace.std.bytearrayobject import W_BytearrayObject
-from pypy.objspace.std.bytesobject import W_AbstractBytesObject, W_BytesObject
+from pypy.objspace.std.bytesobject import W_BytesObject
 from pypy.objspace.std.complexobject import W_ComplexObject
 from pypy.objspace.std.dictmultiobject import W_DictMultiObject, W_DictObject
 from pypy.objspace.std.floatobject import W_FloatObject
@@ -82,9 +82,6 @@
             W_TypeObject.typedef: W_TypeObject,
             W_UnicodeObject.typedef: W_UnicodeObject,
         }
-        if self.config.objspace.std.withstrbuf:
-            builtin_type_classes[W_BytesObject.typedef] = W_AbstractBytesObject
-
         self.builtin_types = {}
         self._interplevel_classes = {}
         for typedef, cls in builtin_type_classes.items():
diff --git a/pypy/objspace/std/strbufobject.py 
b/pypy/objspace/std/strbufobject.py
deleted file mode 100644
--- a/pypy/objspace/std/strbufobject.py
+++ /dev/null
@@ -1,96 +0,0 @@
-import inspect
-
-import py
-
-from pypy.objspace.std.bytesobject import W_AbstractBytesObject, W_BytesObject
-from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.buffer import SimpleView, StringBuffer
-from pypy.interpreter.error import OperationError
-from rpython.rlib.rstring import StringBuilder
-
-
-class W_StringBufferObject(W_AbstractBytesObject):
-    w_str = None
-
-    def __init__(self, builder):
-        self.builder = builder             # StringBuilder
-        self.length = builder.getlength()
-
-    def force(self):
-        if self.w_str is None:
-            s = self.builder.build()
-            if self.length < len(s):
-                s = s[:self.length]
-            self.w_str = W_BytesObject(s)
-            return s
-        else:
-            return self.w_str._value
-
-    def __repr__(self):
-        """ representation for debugging purposes """
-        return "%s(%r[:%d])" % (
-            self.__class__.__name__, self.builder, self.length)
-
-    def unwrap(self, space):
-        return self.force()
-
-    def bytes_w(self, space):
-        return self.force()
-
-    def buffer_w(self, space, flags):
-        return SimpleView(StringBuffer(self.force()))
-
-    def descr_len(self, space):
-        return space.newint(self.length)
-
-    def descr_add(self, space, w_other):
-        try:
-            other = W_BytesObject._op_val(space, w_other)
-        except OperationError as e:
-            if e.match(space, space.w_TypeError):
-                return space.w_NotImplemented
-            raise
-        if self.builder.getlength() != self.length:
-            builder = StringBuilder()
-            builder.append(self.force())
-        else:
-            builder = self.builder
-        builder.append(other)
-        return W_StringBufferObject(builder)
-
-    def descr_str(self, space):
-        # you cannot get subclasses of W_StringBufferObject here
-        assert type(self) is W_StringBufferObject
-        return self
-
-
-delegation_dict = {}
-for key, value in W_BytesObject.typedef.rawdict.iteritems():
-    if not isinstance(value, interp2app):
-        continue
-    if key in ('__len__', '__add__', '__str__'):
-        continue
-
-    func = value._code._bltin
-    args = inspect.getargs(func.func_code)
-    if args.varargs or args.keywords:
-        raise TypeError("Varargs and keywords not supported in unwrap_spec")
-    argspec = ', '.join([arg for arg in args.args[1:]])
-    func_code = py.code.Source("""
-    def f(self, %(args)s):
-        self.force()
-        return self.w_str.%(func_name)s(%(args)s)
-    """ % {'args': argspec, 'func_name': func.func_name})
-    d = {}
-    exec func_code.compile() in d
-    f = d['f']
-    f.func_defaults = func.func_defaults
-    f.__module__ = func.__module__
-    # necessary for unique identifiers for pickling
-    f.func_name = func.func_name
-    unwrap_spec_ = getattr(func, 'unwrap_spec', None)
-    if unwrap_spec_ is not None:
-        f = unwrap_spec(**unwrap_spec_)(f)
-    setattr(W_StringBufferObject, func.func_name, f)
-
-W_StringBufferObject.typedef = W_BytesObject.typedef
diff --git a/pypy/objspace/std/test/test_stdobjspace.py 
b/pypy/objspace/std/test/test_stdobjspace.py
--- a/pypy/objspace/std/test/test_stdobjspace.py
+++ b/pypy/objspace/std/test/test_stdobjspace.py
@@ -62,13 +62,6 @@
         cls = space._get_interplevel_cls(w_sequenceiterator)
         assert cls is W_AbstractSeqIterObject
 
-    def test_withstrbuf_fastpath_isinstance(self):
-        from pypy.objspace.std.bytesobject import W_AbstractBytesObject
-
-        space = gettestobjspace(withstrbuf=True)
-        cls = space._get_interplevel_cls(space.w_bytes)
-        assert cls is W_AbstractBytesObject
-
     def test_wrap_various_unsigned_types(self):
         import sys
         from rpython.rlib.rarithmetic import r_uint
diff --git a/pypy/objspace/std/test/test_strbufobject.py 
b/pypy/objspace/std/test/test_strbufobject.py
deleted file mode 100644
--- a/pypy/objspace/std/test/test_strbufobject.py
+++ /dev/null
@@ -1,84 +0,0 @@
-import py
-
-from pypy.objspace.std.test import test_bytesobject
-
-class AppTestStringObject(test_bytesobject.AppTestBytesObject):
-    spaceconfig = {"objspace.std.withstrbuf": True}
-
-    def test_basic(self):
-        import __pypy__
-        # cannot do "Hello, " + "World!" because cpy2.5 optimises this
-        # away on AST level
-        s = b"Hello, ".__add__(b"World!")
-        assert type(s) is bytes
-        assert 'W_StringBufferObject' in __pypy__.internal_repr(s)
-
-    def test_add_twice(self):
-        x = b"a".__add__(b"b")
-        y = x + b"c"
-        c = x + b"d"
-        assert y == b"abc"
-        assert c == b"abd"
-
-    def test_add(self):
-        import __pypy__
-        all = b""
-        for i in range(20):
-            all += str(i).encode()
-        assert 'W_StringBufferObject' in __pypy__.internal_repr(all)
-        assert all == b"012345678910111213141516171819"
-
-    def test_hash(self):
-        import __pypy__
-        def join(s): return s[:len(s) // 2] + s[len(s) // 2:]
-        t = b'a' * 101
-        s = join(t)
-        assert 'W_StringBufferObject' in __pypy__.internal_repr(s)
-        assert hash(s) == hash(t)
-
-    def test_len(self):
-        s = b"a".__add__(b"b")
-        r = b"c".__add__(b"d")
-        t = s + r
-        assert len(s) == 2
-        assert len(r) == 2
-        assert len(t) == 4
-
-    def test_buffer(self):
-        s = b'a'.__add__(b'b')
-        assert memoryview(s) == b'ab'
-
-    def test_add_strbuf(self):
-        # make three strbuf objects
-        s = b'a'.__add__(b'b')
-        t = b'x'.__add__(b'c')
-        u = b'y'.__add__(b'd')
-
-        # add two different strbufs to the same string
-        v = s + t
-        w = s + u
-
-        # check that insanity hasn't resulted.
-        assert v == b"abxc"
-        assert w == b"abyd"
-
-    def test_more_adding_fun(self):
-        s = b'a'.__add__(b'b') # s is a strbuf now
-        t = s + b'c'
-        u = s + b'd'
-        v = s + b'e'
-        assert v == b'abe'
-        assert u == b'abd'
-        assert t == b'abc'
-
-    def test_buh_even_more(self):
-        a = b'a'.__add__(b'b')
-        b = a + b'c'
-        c = b'0'.__add__(b'1')
-        x = c + a
-        assert x == b'01ab'
-
-    def test_add_non_string(self):
-        a = b'a'
-        a += b'b'
-        raises(TypeError, "a += 5")
diff --git a/rpython/rlib/rposix.py b/rpython/rlib/rposix.py
--- a/rpython/rlib/rposix.py
+++ b/rpython/rlib/rposix.py
@@ -239,7 +239,7 @@
                 'signal.h', 'sys/utsname.h', _ptyh]
     if sys.platform.startswith('linux'):
         includes.append('sys/sysmacros.h')
-    if sys.platform.startswith('freebsd'):
+    if sys.platform.startswith('freebsd') or 
sys.platform.startswith('openbsd'):
         includes.append('sys/ttycom.h')
     libraries = ['util']
 eci = ExternalCompilationInfo(
diff --git a/rpython/rlib/rvmprof/src/shared/machine.c 
b/rpython/rlib/rvmprof/src/shared/machine.c
--- a/rpython/rlib/rvmprof/src/shared/machine.c
+++ b/rpython/rlib/rvmprof/src/shared/machine.c
@@ -4,6 +4,7 @@
 #include <stdio.h>
 
 #ifdef VMPROF_UNIX
+#include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
 #endif
diff --git a/rpython/rlib/streamio.py b/rpython/rlib/streamio.py
--- a/rpython/rlib/streamio.py
+++ b/rpython/rlib/streamio.py
@@ -902,18 +902,30 @@
         self.do_read = base.read
         self.do_write = base.write
         self.do_flush = base.flush_buffers
-        self.lfbuffer = ""
+        self.readahead_count = 0   # either 0 or 1
 
     def read(self, n=-1):
-        data = self.lfbuffer + self.do_read(n)
-        self.lfbuffer = ""
+        """If n >= 1, this should read between 1 and n bytes."""
+        if n <= 0:
+            if n < 0:
+                return self.readall()
+            else:
+                return ""
+
+        data = self.do_read(n - self.readahead_count)
+        if self.readahead_count > 0:
+            data = self.readahead_char + data
+            self.readahead_count = 0
+
         if data.endswith("\r"):
             c = self.do_read(1)
-            if c and c[0] == '\n':
-                data = data + '\n'
-                self.lfbuffer = c[1:]
-            else:
-                self.lfbuffer = c
+            if len(c) >= 1:
+                assert len(c) == 1
+                if c[0] == '\n':
+                    data = data + '\n'
+                else:
+                    self.readahead_char = c[0]
+                    self.readahead_count = 1
 
         result = []
         offset = 0
@@ -936,21 +948,21 @@
 
     def tell(self):
         pos = self.base.tell()
-        return pos - len(self.lfbuffer)
+        return pos - self.readahead_count
 
     def seek(self, offset, whence):
         if whence == 1:
-            offset -= len(self.lfbuffer)   # correct for already-read-ahead 
character
+            offset -= self.readahead_count   # correct for already-read-ahead 
character
         self.base.seek(offset, whence)
-        self.lfbuffer = ""
+        self.readahead_count = 0
 
     def flush_buffers(self):
-        if self.lfbuffer:
+        if self.readahead_count > 0:
             try:
-                self.base.seek(-len(self.lfbuffer), 1)
+                self.base.seek(-self.readahead_count, 1)
             except (MyNotImplementedError, OSError):
                 return
-            self.lfbuffer = ""
+            self.readahead_count = 0
         self.do_flush()
 
     def write(self, data):
diff --git a/rpython/rlib/test/test_streamio.py 
b/rpython/rlib/test/test_streamio.py
--- a/rpython/rlib/test/test_streamio.py
+++ b/rpython/rlib/test/test_streamio.py
@@ -657,6 +657,23 @@
             assert line == ''
         self.interpret(f, [])
 
+    def test_read1(self):
+        s_input = "abc\r\nabc\nd\r\nef\r\ngha\rbc\rdef\n\r\n\r"
+        s_output = "abc\nabc\nd\nef\ngha\rbc\rdef\n\n\r"
+        assert s_output == s_input.replace('\r\n', '\n')
+        packets = list(s_input)
+        expected = list(s_output)
+        crlf = streamio.TextCRLFFilter(TSource(packets))
+        def f():
+            blocks = []
+            while True:
+                block = crlf.read(1)
+                if not block:
+                    break
+                blocks.append(block)
+            assert blocks == expected
+        self.interpret(f, [])
+
 class TestTextCRLFFilterLLInterp(BaseTestTextCRLFFilter):
     pass
 
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to