[pypy-commit] pypy py3.7: hg merge py3.6

rlamy pypy.commits at gmail.com
Wed Oct 16 13:01:28 EDT 2019


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: py3.7
Changeset: r97799:5b468ca97202
Date: 2019-10-16 18:00 +0100
http://bitbucket.org/pypy/pypy/changeset/5b468ca97202/

Log:	hg merge py3.6

diff too long, truncating to 2000 out of 2237 lines

diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -50,4 +50,10 @@
 de061d87e39c7df4e436974096d7982c676a859d release-pypy3.6-v7.1.0
 784b254d669919c872a505b807db8462b6140973 release-pypy3.6-v7.1.1
 8cdda8b8cdb8ff29d9e620cccd6c5edd2f2a23ec release-pypy2.7-v7.1.1
-
+85dae4fd5c234b482feff834c73e089872194541 release-pypy2.7-v7.2.0rc0
+7ffb92269488f37c707ce66076f50ffd8613f8e2 release-pypy3.6-v7.2.0rc0
+4d6761df14ffd6f38450f183ac1fad32c946c21b release-pypy3.6-v7.2.0rc1
+5da45ced70e515f94686be0df47c59abd1348ebc release-pypy3.6-v7.2.0rc2
+4a68d8d3d2fc1faec2e83bcb4d28559099092574 release-pypy2.7-v7.2.0rc2
+4a68d8d3d2fc1faec2e83bcb4d28559099092574 release-pypy2.7-v7.2.0
+5da45ced70e515f94686be0df47c59abd1348ebc release-pypy3.6-v7.2.0
diff --git a/lib_pypy/_lzma.py b/lib_pypy/_lzma.py
--- a/lib_pypy/_lzma.py
+++ b/lib_pypy/_lzma.py
@@ -583,8 +583,16 @@
                 self.clear_input_buffer()
             elif lzs.avail_in == 0:
                 # completed successfully!
-                self.needs_input = True
                 lzs.next_in = ffi.NULL
+                if lzs.avail_out == 0:
+                    # (avail_in==0 && avail_out==0)
+                    # Maybe lzs's internal state still have a few bytes can
+                    # be output, try to output them next time.
+                    self.needs_input = False
+                    assert max_length >= 0   # if < 0, lzs.avail_out always > 0
+                else:
+                    # Input buffer exhausted, output buffer has space.
+                    self.needs_input = True
                 self.clear_input_buffer()
             else:
                 self.needs_input = False
@@ -599,9 +607,6 @@
         lzs.next_in = buf
         lzs.avail_in = buf_len
 
-        if buf_len == 0:
-            return b""
-
         bufsiz = self._bufsiz
         if not (max_length < 0 or max_length > io.DEFAULT_BUFFER_SIZE):
             bufsiz = max_length
@@ -616,7 +621,8 @@
 
         try:
             while True:
-                ret = catch_lzma_error(m.lzma_code, lzs, m.LZMA_RUN)
+                ret = catch_lzma_error(m.lzma_code, lzs, m.LZMA_RUN,
+                    ignore_buf_error=(lzs.avail_in == 0 and lzs.avail_out > 0))
                 data_size = int(ffi.cast('uintptr_t', lzs.next_out)) - int(ffi.cast('uintptr_t', orig_out))
                 # data_size is the amount lzma_code has already outputted
 
@@ -626,14 +632,17 @@
                 if ret == m.LZMA_STREAM_END:
                     self.eof = True
                     break
-                elif lzs.avail_in == 0:
-                    # it ate everything
-                    break
                 elif lzs.avail_out == 0:
+                    # Need to check lzs->avail_out before lzs->avail_in.
+                    # Maybe lzs's internal state still have a few bytes
+                    # can be output, grow the output buffer and continue
+                    # if max_lengh < 0.
                     if data_size == max_length:
                         break
                     # ran out of space in the output buffer, let's grow it
                     bufsiz += (bufsiz >> 3) + 6
+                    if max_length > 0 and bufsiz > max_length:
+                        bufsiz = max_length
                     next_out = m.realloc(orig_out, bufsiz)
                     if next_out == ffi.NULL:
                         # realloc unsuccessful
@@ -645,6 +654,9 @@
 
                     lzs.next_out = orig_out + data_size
                     lzs.avail_out = bufsiz - data_size
+                elif lzs.avail_in == 0:
+                    # it ate everything
+                    break
 
             result = ffi.buffer(orig_out, data_size)[:]
         finally:
diff --git a/pypy/doc/commandline_ref.rst b/pypy/doc/commandline_ref.rst
--- a/pypy/doc/commandline_ref.rst
+++ b/pypy/doc/commandline_ref.rst
@@ -9,3 +9,4 @@
 
    man/pypy.1.rst
    man/pypy3.1.rst
+   jit_help.rst
diff --git a/pypy/doc/index-of-whatsnew.rst b/pypy/doc/index-of-whatsnew.rst
--- a/pypy/doc/index-of-whatsnew.rst
+++ b/pypy/doc/index-of-whatsnew.rst
@@ -42,7 +42,8 @@
 -------------------------------
 
 .. toctree::
-   whatsnew-pypy3-head.rst
+    whatsnew-pypy3-head.rst
+    whatsnew-pypy3-7.1.0.rst
 
 CPython 3.5 compatible versions
 -------------------------------
@@ -50,6 +51,8 @@
 .. toctree::
 
    whatsnew-pypy3-7.0.0.rst
+   whatsnew-pypy3-6.0.0.rst
+   whatsnew-pypy3-5.10.0.rst
    whatsnew-pypy3-5.9.0.rst
    whatsnew-pypy3-5.8.0.rst
    whatsnew-pypy3-5.7.0.rst
@@ -62,10 +65,4 @@
    whatsnew-pypy3-5.5.0.rst
    whatsnew-pypy3-5.1.1-alpha1.rst
 
-CPython 3.2 compatible versions
--------------------------------
 
-.. toctree::
-
-   whatsnew-pypy3-2.4.0.rst
-   whatsnew-pypy3-2.3.1.rst
diff --git a/pypy/doc/jit_help.rst b/pypy/doc/jit_help.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/jit_help.rst
@@ -0,0 +1,78 @@
+========
+JIT help
+========
+
+.. note this is from ``pypy --jit help``
+
+Advanced JIT options
+====================
+
+``<pypy> --jit`` [*options*] where *options* is a comma-separated list of
+``OPTION=VALUE``:
+
+ decay=N
+    amount to regularly decay counters by (0=none, 1000=max) (default 40)
+
+ disable_unrolling=N
+    after how many operations we should not unroll (default 200)
+
+ enable_opts=N
+    INTERNAL USE ONLY (MAY NOT WORK OR LEAD TO CRASHES): optimizations to
+    enable, or all =
+    intbounds:rewrite:virtualize:string:pure:earlyforce:heap:unroll (default
+    all)
+
+ function_threshold=N
+    number of times a function must run for it to become traced from start
+    (default 1619)
+
+ inlining=N
+    inline python functions or not (1/0) (default 1)
+
+ loop_longevity=N
+    a parameter controlling how long loops will be kept before being freed,
+    an estimate (default 1000)
+
+ max_retrace_guards=N
+    number of extra guards a retrace can cause (default 15)
+
+ max_unroll_loops=N
+    number of extra unrollings a loop can cause (default 0)
+
+ max_unroll_recursion=N
+    how many levels deep to unroll a recursive function (default 7)
+
+ retrace_limit=N
+    how many times we can try retracing before giving up (default 0)
+
+ threshold=N
+    number of times a loop has to run for it to become hot (default 1039)
+
+ trace_eagerness=N
+    number of times a guard has to fail before we start compiling a bridge
+    (default 200)
+
+ trace_limit=N
+    number of recorded operations before we abort tracing with ABORT_TOO_LONG
+    (default 6000)
+
+ vec=N
+    turn on the vectorization optimization (vecopt). Supports x86 (SSE 4.1),
+    powerpc (SVX), s390x SIMD (default 0)
+
+ vec_all=N
+    try to vectorize trace loops that occur outside of the numpypy library
+    (default 0)
+
+ vec_cost=N
+    threshold for which traces to bail. Unpacking increases the counter,
+    vector operation decrease the cost (default 0)
+
+ off
+    turn off the JIT
+ help
+    print this page
+
+The :ref:`pypyjit<jit-hooks>` module can be used to control the JIT from inside
+pypy
+
diff --git a/pypy/doc/release-v7.2.0.rst b/pypy/doc/release-v7.2.0.rst
--- a/pypy/doc/release-v7.2.0.rst
+++ b/pypy/doc/release-v7.2.0.rst
@@ -216,6 +216,7 @@
 * Add more constants to `sysconfig``. Set ``MACOSX_DEPLOYMENT_TARGET`` for
   darwin (`issue 2994`_)
 * fix ``CBuffer.buffer_attach``
+* Add ``_PyDict_GetItemWithError`` (``PyDict_GetItemWithError`` on Python3)
 
 Python 3.6 only
 ---------------
@@ -307,6 +308,7 @@
 .. _33786 : https://bugs.python.org/issue33786
 .. _32270 : https://bugs.python.org/issue32270
 .. _28691 : https://bugs.python.org/issue28691
+.. _33729 : https://bugs.python.org/issue33729
 
 .. _opencv2: https://github.com/skvark/opencv-python/
 .. _`issue 2617`: https://bitbucket.com/pypy/pypy/issues/2617
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
@@ -3,11 +3,9 @@
 ==========================
 
 .. this is a revision shortly after release-pypy-7.2.0
-.. startrev: 78cd4acbcbec 
+.. startrev: a511d86377d6 
 
+.. branch: fix-descrmismatch-crash
 
-.. branch: json-decoder-maps
+Fix segfault when calling descr-methods with no arguments
 
-Much faster and more memory-efficient JSON decoding. The resulting
-dictionaries that come out of the JSON decoder have faster lookups too.
-
diff --git a/pypy/doc/whatsnew-pypy2-7.2.0.rst b/pypy/doc/whatsnew-pypy2-7.2.0.rst
--- a/pypy/doc/whatsnew-pypy2-7.2.0.rst
+++ b/pypy/doc/whatsnew-pypy2-7.2.0.rst
@@ -17,10 +17,6 @@
 
 Add ``DateTime_FromTimestamp`` and ``Date_FromTimestamp``
 
-.. branch: issue2968
-
-Fix segfault in cpyext_tp_new_tupl
-
 .. branch: semlock-deadlock
 
 Test and reduce the probability of a deadlock when acquiring a semaphore by
@@ -79,6 +75,8 @@
 
 Update _ssl on macos to statically link to openssl-1.1.1c
 
-.. branch: more-cpyext
+.. branch: json-decoder-maps
 
-Add more datetime C functions and definitions
+Much faster and more memory-efficient JSON decoding. The resulting
+dictionaries that come out of the JSON decoder have faster lookups too.
+
diff --git a/pypy/doc/whatsnew-pypy3-2.3.1.rst b/pypy/doc/whatsnew-pypy3-2.3.1.rst
deleted file mode 100644
--- a/pypy/doc/whatsnew-pypy3-2.3.1.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-=========================
-What's new in PyPy3 2.3.1
-=========================
-
-.. this is a revision shortly after pypy3-release-2.3.x
-.. startrev: 0137d8e6657d
diff --git a/pypy/doc/whatsnew-pypy3-2.4.0.rst b/pypy/doc/whatsnew-pypy3-2.4.0.rst
deleted file mode 100644
--- a/pypy/doc/whatsnew-pypy3-2.4.0.rst
+++ /dev/null
@@ -1,6 +0,0 @@
-=========================
-What's new in PyPy3 2.4.0
-=========================
-
-.. this is a revision shortly after pypy3-release-2.4.x
-.. startrev: 12b940544622
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -394,6 +394,8 @@
 
 @specialize.memo()
 def wrappable_class_name(Class):
+    if 'exact_class_applevel_name' in Class.__dict__:
+        return Class.exact_class_applevel_name
     try:
         return Class.typedef.name
     except AttributeError:
@@ -1232,8 +1234,11 @@
         from pypy.interpreter.generator import GeneratorIterator
         return isinstance(w_obj, GeneratorIterator)
 
+    def callable_w(self, w_obj):
+        return self.lookup(w_obj, "__call__") is not None
+
     def callable(self, w_obj):
-        return self.newbool(self.lookup(w_obj, "__call__") is not None)
+        return self.newbool(self.callable_w(w_obj))
 
     def issequence_w(self, w_obj):
         flag = self.type(w_obj).flag_map_or_seq
@@ -1787,8 +1792,7 @@
     def convert_arg_to_w_unicode(self, w_obj, strict=None):
         # XXX why convert_to_w_unicode does something slightly different?
         from pypy.objspace.std.unicodeobject import W_UnicodeObject
-        # for z_translation tests
-        if hasattr(self, 'is_fake_objspace'): return self.newtext("foobar")
+        assert not hasattr(self, 'is_fake_objspace')
         return W_UnicodeObject.convert_arg_to_w_unicode(self, w_obj, strict)
 
     def utf8_len_w(self, w_obj):
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -23,8 +23,9 @@
     # XXX [fijal] but they're not. is_being_profiled is guarded a bit all
     #     over the place as well as w_tracefunc
 
-    _immutable_fields_ = ['profilefunc?', 'w_tracefunc?',
-                          'w_coroutine_wrapper_fn?']
+    _immutable_fields_ = [
+        'profilefunc?', 'w_tracefunc?', 'w_coroutine_wrapper_fn?',
+        'w_asyncgen_firstiter_fn?', 'w_asyncgen_finalizer_fn?']
 
     def __init__(self, space):
         self.space = space
@@ -41,6 +42,8 @@
         self.thread_disappeared = False   # might be set to True after os.fork()
         self.w_coroutine_wrapper_fn = None
         self.in_coroutine_wrapper = False
+        self.w_asyncgen_firstiter_fn = None
+        self.w_asyncgen_finalizer_fn = None
 
     @staticmethod
     def _mark_thread_disappeared(space):
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -755,6 +755,7 @@
                     self.func__args__ = func
                 elif unwrap_spec == [self_type, ObjSpace, Arguments]:
                     self.__class__ = BuiltinCodePassThroughArguments1
+                    self.descr_reqcls = self_type
                     miniglobals = {'func': func, 'self_type': self_type}
                     d = {}
                     source = """if 1:
@@ -800,10 +801,7 @@
         except DescrMismatch:
             if w_obj is not None:
                 args = args.prepend(w_obj)
-            return scope_w[0].descr_call_mismatch(space,
-                                                  self.descrmismatch_op,
-                                                  self.descr_reqcls,
-                                                  args)
+            return self._type_unwrap_mismatch(space, args)
         except Exception as e:
             self.handle_exception(space, e)
             w_result = None
@@ -811,6 +809,15 @@
             w_result = space.w_None
         return w_result
 
+    def _type_unwrap_mismatch(self, space, args):
+        w_obj = args.firstarg()
+        if w_obj is None:
+            raise oefmt(space.w_SystemError, "unexpected DescrMismatch error")
+        return w_obj.descr_call_mismatch(space,
+                                         self.descrmismatch_op,
+                                         self.descr_reqcls,
+                                         args)
+
     def handle_exception(self, space, e):
         try:
             if not we_are_translated():
@@ -833,10 +840,7 @@
         try:
             w_result = self.func__args__(space, args)
         except DescrMismatch:
-            return args.firstarg().descr_call_mismatch(space,
-                                                  self.descrmismatch_op,
-                                                  self.descr_reqcls,
-                                                  args)
+            return self._type_unwrap_mismatch(space, args)
         except Exception as e:
             self.handle_exception(space, e)
             w_result = None
@@ -854,10 +858,7 @@
         try:
             w_result = self.func__args__(space, w_obj, args)
         except DescrMismatch:
-            return args.firstarg().descr_call_mismatch(space,
-                                                  self.descrmismatch_op,
-                                                  self.descr_reqcls,
-                                                  args.prepend(w_obj))
+            return self._type_unwrap_mismatch(space, args.prepend(w_obj))
         except Exception as e:
             self.handle_exception(space, e)
             w_result = None
@@ -897,9 +898,7 @@
         try:
             w_result = self.fastfunc_1(space, w1)
         except DescrMismatch:
-            return w1.descr_call_mismatch(space,
-                                          self.descrmismatch_op,
-                                          self.descr_reqcls,
+            return self._type_unwrap_mismatch(space,
                                           Arguments(space, [w1]))
         except Exception as e:
             self.handle_exception(space, e)
@@ -923,9 +922,7 @@
         try:
             w_result = self.fastfunc_2(space, w1, w2)
         except DescrMismatch:
-            return w1.descr_call_mismatch(space,
-                                          self.descrmismatch_op,
-                                          self.descr_reqcls,
+            return self._type_unwrap_mismatch(space,
                                           Arguments(space, [w1, w2]))
         except Exception as e:
             self.handle_exception(space, e)
@@ -950,9 +947,7 @@
         try:
             w_result = self.fastfunc_3(space, w1, w2, w3)
         except DescrMismatch:
-            return w1.descr_call_mismatch(space,
-                                          self.descrmismatch_op,
-                                          self.descr_reqcls,
+            return self._type_unwrap_mismatch(space,
                                           Arguments(space, [w1, w2, w3]))
         except Exception as e:
             self.handle_exception(space, e)
@@ -978,9 +973,7 @@
         try:
             w_result = self.fastfunc_4(space, w1, w2, w3, w4)
         except DescrMismatch:
-            return w1.descr_call_mismatch(space,
-                                          self.descrmismatch_op,
-                                          self.descr_reqcls,
+            return self._type_unwrap_mismatch(space,
                                           Arguments(space,
                                                     [w1, w2, w3, w4]))
         except Exception as e:
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -11,8 +11,6 @@
 class GeneratorOrCoroutine(W_Root):
     _immutable_fields_ = ['pycode']
 
-    w_yielded_from = None
-
     def __init__(self, frame, name=None, qualname=None):
         self.space = frame.space
         self.frame = frame     # turned into None when frame_finished_execution
@@ -84,7 +82,7 @@
                 operr = OperationError(space.w_StopIteration, space.w_None)
             raise operr
 
-        w_result = self._invoke_execute_frame(frame, w_arg_or_err)
+        w_result = self._invoke_execute_frame(w_arg_or_err)
         assert w_result is not None
 
         # if the frame is now marked as finished, it was RETURNed from
@@ -102,8 +100,9 @@
         else:
             return w_result     # YIELDed
 
-    def _invoke_execute_frame(self, frame, w_arg_or_err):
+    def _invoke_execute_frame(self, w_arg_or_err):
         space = self.space
+        frame = self.frame
         if self.running:
             raise oefmt(space.w_ValueError, "%s already executing", self.KIND)
         ec = space.getexecutioncontext()
@@ -126,7 +125,7 @@
                             self.KIND)
         self.running = True
         try:
-            w_result = frame.execute_frame(self, w_arg_or_err)
+            w_result = frame.execute_frame(w_arg_or_err)
         except OperationError as e:
             # errors finish a frame
             try:
@@ -149,68 +148,19 @@
             ec.set_sys_exc_info(current_exc_info)
         return w_result
 
-    def resume_execute_frame(self, frame, w_arg_or_err):
-        # Called from execute_frame() just before resuming the bytecode
-        # interpretation.
-        space = self.space
-        w_yf = self.w_yielded_from
-        if w_yf is not None:
-            self.w_yielded_from = None
-            try:
-                self.next_yield_from(frame, w_yf, w_arg_or_err)
-            except OperationError as operr:
-                operr.record_context(space, space.getexecutioncontext())
-                return frame.handle_generator_error(operr)
-            # Normal case: the call above raises Yield.
-            # We reach this point if the iterable is exhausted.
-            last_instr = jit.promote(frame.last_instr)
-            assert last_instr & 1 == 0
-            assert last_instr >= 0
-            return r_uint(last_instr + 2)
+    def get_delegate(self):
+        if self.frame is None:
+            return None
+        return self.frame.w_yielding_from
 
-        if isinstance(w_arg_or_err, SApplicationException):
-            return frame.handle_generator_error(w_arg_or_err.operr)
+    def descr_delegate(self, space):
+        w_yf = self.get_delegate()
+        if w_yf is None:
+            return space.w_None
+        return w_yf
 
-        last_instr = jit.promote(frame.last_instr)
-        if last_instr != -1:
-            assert last_instr & 1 == 0
-            frame.pushvalue(w_arg_or_err)
-            return r_uint(last_instr + 2)
-        else:
-            return r_uint(0)
-
-    def next_yield_from(self, frame, w_yf, w_inputvalue_or_err):
-        """Fetch the next item of the current 'yield from', push it on
-        the frame stack, and raises Yield.  If there isn't one, push
-        w_stopiteration_value and returns.  May also just raise.
-        """
-        space = self.space
-        try:
-            if isinstance(w_yf, GeneratorOrCoroutine):
-                w_retval = w_yf.send_ex(w_inputvalue_or_err)
-            elif isinstance(w_yf, AsyncGenASend):   # performance only
-                w_retval = w_yf.do_send(w_inputvalue_or_err)
-            elif space.is_w(w_inputvalue_or_err, space.w_None):
-                w_retval = space.next(w_yf)
-            else:
-                w_retval = delegate_to_nongen(space, w_yf, w_inputvalue_or_err)
-        except OperationError as e:
-            if not e.match(space, space.w_StopIteration):
-                raise
-            frame._report_stopiteration_sometimes(w_yf, e)
-            try:
-                w_stop_value = space.getattr(e.get_w_value(space),
-                                             space.newtext("value"))
-            except OperationError as e:
-                if not e.match(space, space.w_AttributeError):
-                    raise
-                w_stop_value = space.w_None
-            frame.pushvalue(w_stop_value)
-            return
-        else:
-            frame.pushvalue(w_retval)
-            self.w_yielded_from = w_yf
-            raise Yield
+    def set_delegate(self, w_delegate):
+        self.frame.w_yielding_from = w_delegate
 
     def _leak_stopiteration(self, e):
         # Check for __future__ generator_stop and conditionally turn
@@ -259,8 +209,8 @@
         operr = OperationError(w_type, w_val, tb)
         operr.normalize_exception(space)
 
-        # note: w_yielded_from is always None if 'self.running'
-        if (self.w_yielded_from is not None and
+        # note: _w_yielded_from is always None if 'self.running'
+        if (self.get_delegate() is not None and
                     operr.match(space, space.w_GeneratorExit)):
             try:
                 self._gen_close_iter(space)
@@ -276,8 +226,8 @@
 
     def _gen_close_iter(self, space):
         assert not self.running
-        w_yf = self.w_yielded_from
-        self.w_yielded_from = None
+        w_yf = self.get_delegate()
+        self.set_delegate(None)
         self.running = True
         try:
             gen_close_iter(space, w_yf)
@@ -290,8 +240,8 @@
             return     # nothing to do in this case
         space = self.space
         operr = None
-        # note: w_yielded_from is always None if 'self.running'
-        w_yf = self.w_yielded_from
+        # note: _w_yielded_from is always None if 'self.running'
+        w_yf = self.get_delegate()
         if w_yf is not None:
             try:
                 self._gen_close_iter(space)
@@ -375,7 +325,7 @@
     # generate 2 versions of the function and 2 jit drivers.
     def _create_unpack_into():
         jitdriver = jit.JitDriver(greens=['pycode'],
-                                  reds=['self', 'frame', 'results'],
+                                  reds='auto',
                                   name='unpack_into')
 
         def unpack_into(self, results):
@@ -386,12 +336,10 @@
                 return
             pycode = self.pycode
             while True:
-                jitdriver.jit_merge_point(self=self, frame=frame,
-                                          results=results, pycode=pycode)
+                jitdriver.jit_merge_point(pycode=pycode)
                 space = self.space
                 try:
-                    w_result = self._invoke_execute_frame(
-                                            frame, space.w_None)
+                    w_result = self._invoke_execute_frame(space.w_None)
                 except OperationError as e:
                     if not e.match(space, space.w_StopIteration):
                         raise
@@ -489,27 +437,6 @@
         else:
             space.call_function(w_close)
 
-def delegate_to_nongen(space, w_yf, w_inputvalue_or_err):
-    # invoke a "send" or "throw" by method name to a non-generator w_yf
-    if isinstance(w_inputvalue_or_err, SApplicationException):
-        operr = w_inputvalue_or_err.operr
-        try:
-            w_meth = space.getattr(w_yf, space.newtext("throw"))
-        except OperationError as e:
-            if not e.match(space, space.w_AttributeError):
-                raise
-            raise operr
-        # bah, CPython calls here with the exact same arguments as
-        # originally passed to throw().  In our case it is far removed.
-        # Let's hope nobody will complain...
-        operr.normalize_exception(space)
-        w_exc = operr.w_type
-        w_val = operr.get_w_value(space)
-        w_tb  = operr.get_w_traceback(space)
-        return space.call_function(w_meth, w_exc, w_val, w_tb)
-    else:
-        return space.call_method(w_yf, "send", w_inputvalue_or_err)
-
 def gen_is_coroutine(w_obj):
     return (isinstance(w_obj, GeneratorIterator) and
             (w_obj.pycode.co_flags & consts.CO_ITERABLE_COROUTINE) != 0)
@@ -594,15 +521,15 @@
         if self.hooks_inited:
             return
         self.hooks_inited = True
-
-        self.w_finalizer = self.space.appexec([], '''():
-            import sys
-            hooks = sys.get_asyncgen_hooks()
-            return hooks.finalizer''')
+        ec = self.space.getexecutioncontext()
+        self.w_finalizer = ec.w_asyncgen_finalizer_fn
+        w_firstiter = ec.w_asyncgen_firstiter_fn
+        if w_firstiter is not None:
+            self.space.call_function(w_firstiter, self)
 
     def _finalize_(self):
         if self.frame is not None and self.frame.lastblock is not None:
-            if self.w_finalizer is not self.space.w_None:
+            if self.w_finalizer is not None:
                 # XXX: this is a hack to resurrect the weakref that was cleared
                 # before running _finalize_()
                 if self.space.config.translation.rweakref:
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -68,6 +68,7 @@
     frame_finished_execution = False
     f_generator_wref         = rweakref.dead_ref  # for generators/coroutines
     f_generator_nowref       = None               # (only one of the two attrs)
+    w_yielding_from = None
     last_instr               = -1
     f_backref                = jit.vref_None
 
@@ -319,9 +320,40 @@
                 ec.in_coroutine_wrapper = False
         return w_gen
 
-    def execute_frame(self, in_generator=None, w_arg_or_err=None):
+    def resume_execute_frame(self, w_arg_or_err):
+        # Called from execute_frame() just before resuming the bytecode
+        # interpretation.
+        from pypy.interpreter.pyopcode import SApplicationException
+        space = self.space
+        w_yf = self.w_yielding_from
+        if w_yf is not None:
+            self.w_yielding_from = None
+            try:
+                self.next_yield_from(w_yf, w_arg_or_err)
+            except OperationError as operr:
+                operr.record_context(space, space.getexecutioncontext())
+                return self.handle_generator_error(operr)
+            # Normal case: the call above raises Yield.
+            # We reach this point if the iterable is exhausted.
+            last_instr = jit.promote(self.last_instr)
+            assert last_instr & 1 == 0
+            assert last_instr >= 0
+            return r_uint(last_instr + 2)
+
+        if isinstance(w_arg_or_err, SApplicationException):
+            return self.handle_generator_error(w_arg_or_err.operr)
+
+        last_instr = jit.promote(self.last_instr)
+        if last_instr != -1:
+            assert last_instr & 1 == 0
+            self.pushvalue(w_arg_or_err)
+            return r_uint(last_instr + 2)
+        else:
+            return r_uint(0)
+
+    def execute_frame(self, w_arg_or_err=None):
         """Execute this frame.  Main entry point to the interpreter.
-        'in_generator' is non-None iff we are starting or resuming
+        'w_arg_or_err' is non-None iff we are starting or resuming
         a generator or coroutine frame; in that case, w_arg_or_err
         is the input argument -or- an SApplicationException instance.
         """
@@ -343,12 +375,11 @@
             # the YIELD_VALUE/YIELD_FROM instruction.
             try:
                 try:
-                    if in_generator is None:
+                    if w_arg_or_err is None:
                         assert self.last_instr == -1
                         next_instr = r_uint(0)
                     else:
-                        next_instr = in_generator.resume_execute_frame(
-                                                        self, w_arg_or_err)
+                        next_instr = self.resume_execute_frame(w_arg_or_err)
                 except pyopcode.Yield:
                     w_exitvalue = self.popvalue()
                 else:
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -1113,24 +1113,51 @@
             self.pushvalue(w_value)
         raise Yield
 
+    def next_yield_from(self, w_yf, w_inputvalue_or_err):
+        """Fetch the next item of the current 'yield from', push it on
+        the frame stack, and raises Yield.  If there isn't one, push
+        w_stopiteration_value and returns.  May also just raise.
+        """
+        from pypy.interpreter.generator import (
+            GeneratorOrCoroutine, AsyncGenASend)
+        space = self.space
+        try:
+            if isinstance(w_yf, GeneratorOrCoroutine):
+                w_retval = w_yf.send_ex(w_inputvalue_or_err)
+            elif isinstance(w_yf, AsyncGenASend):   # performance only
+                w_retval = w_yf.do_send(w_inputvalue_or_err)
+            elif space.is_w(w_inputvalue_or_err, space.w_None):
+                w_retval = space.next(w_yf)
+            else:
+                w_retval = delegate_to_nongen(space, w_yf, w_inputvalue_or_err)
+        except OperationError as e:
+            if not e.match(space, space.w_StopIteration):
+                raise
+            self._report_stopiteration_sometimes(w_yf, e)
+            try:
+                w_stop_value = space.getattr(e.get_w_value(space),
+                                             space.newtext("value"))
+            except OperationError as e:
+                if not e.match(space, space.w_AttributeError):
+                    raise
+                w_stop_value = space.w_None
+            self.pushvalue(w_stop_value)
+            return
+        else:
+            self.pushvalue(w_retval)
+            self.w_yielding_from = w_yf
+            raise Yield
+
     def YIELD_FROM(self, oparg, next_instr):
         # Unlike CPython, we handle this not by repeating the same
         # bytecode over and over until the inner iterator is exhausted.
-        # Instead, we directly set the generator's w_yielded_from.
-        # This asks generator.resume_execute_frame() to exhaust that
+        # Instead, we set w_yielding_from.
+        # This asks resume_execute_frame() to exhaust that
         # sub-iterable first before continuing on the next bytecode.
-        in_generator = self.get_generator()
-        if in_generator is None:
-            # Issue #2768: rare case involving __del__ methods.
-            # XXX This is a workaround, not a proper solution.
-            raise oefmt(self.space.w_RuntimeError,
-                        "PyPy limitation: cannot use 'yield from' or 'await' "
-                        "in a generator/coroutine that has been partially "
-                        "deallocated already, typically seen via __del__")
         w_inputvalue = self.popvalue()    # that's always w_None, actually
         w_gen = self.popvalue()
         #
-        in_generator.next_yield_from(self, w_gen, w_inputvalue)
+        self.next_yield_from(w_gen, w_inputvalue)
         # Common case: the call above raises Yield.
         # If instead the iterable is empty, next_yield_from() pushed the
         # final result and returns.  In that case, we can just continue
@@ -1556,7 +1583,7 @@
         w_iterable = self.popvalue()
         w_iter = get_awaitable_iter(self.space, w_iterable)
         if isinstance(w_iter, Coroutine):
-            if w_iter.w_yielded_from is not None:
+            if w_iter.get_delegate() is not None:
                 # 'w_iter' is a coroutine object that is being awaited,
                 # '.w_yielded_from' is the current awaitable being awaited on.
                 raise oefmt(self.space.w_RuntimeError,
@@ -1694,6 +1721,27 @@
         else:
             self.MISSING_OPCODE(oparg, next_instr)
 
+def delegate_to_nongen(space, w_yf, w_inputvalue_or_err):
+    # invoke a "send" or "throw" by method name to a non-generator w_yf
+    if isinstance(w_inputvalue_or_err, SApplicationException):
+        operr = w_inputvalue_or_err.operr
+        try:
+            w_meth = space.getattr(w_yf, space.newtext("throw"))
+        except OperationError as e:
+            if not e.match(space, space.w_AttributeError):
+                raise
+            raise operr
+        # bah, CPython calls here with the exact same arguments as
+        # originally passed to throw().  In our case it is far removed.
+        # Let's hope nobody will complain...
+        operr.normalize_exception(space)
+        w_exc = operr.w_type
+        w_val = operr.get_w_value(space)
+        w_tb = operr.get_w_traceback(space)
+        return space.call_function(w_meth, w_exc, w_val, w_tb)
+    else:
+        return space.call_method(w_yf, "send", w_inputvalue_or_err)
+
 
 ### ____________________________________________________________ ###
 
diff --git a/pypy/interpreter/test/apptest_coroutine.py b/pypy/interpreter/test/apptest_coroutine.py
--- a/pypy/interpreter/test/apptest_coroutine.py
+++ b/pypy/interpreter/test/apptest_coroutine.py
@@ -633,16 +633,12 @@
         a2 = g.aclose()
     sys.set_asyncgen_hooks(finalizer=_finalize)
     assert state == 0
-    try:
+    with pytest.raises(StopIteration):
         a.send(None)
-    except StopIteration:
-        pass
     assert a2.send(None) == 'coro'
     assert state == 1
-    try:
+    with pytest.raises(StopIteration):
         a2.send(None)
-    except StopIteration:
-        pass
     assert state == 2
     sys.set_asyncgen_hooks(None, None)
 
diff --git a/pypy/interpreter/test/test_gateway.py b/pypy/interpreter/test/test_gateway.py
--- a/pypy/interpreter/test/test_gateway.py
+++ b/pypy/interpreter/test/test_gateway.py
@@ -1095,6 +1095,29 @@
         # white-box check for opt
         assert called[0] is args
 
+    def test_base_regular_descr_mismatch(self):
+        space = self.space
+
+        def f():
+            raise gateway.DescrMismatch
+
+        w_f = space.wrap(gateway.interp2app_temp(f,
+                         unwrap_spec=[]))
+        args = argument.Arguments(space, [])
+        space.raises_w(space.w_SystemError, space.call_args, w_f, args)
+
+    def test_pass_trough_arguments0_descr_mismatch(self):
+        space = self.space
+
+        def f(space, __args__):
+            raise gateway.DescrMismatch
+
+        w_f = space.wrap(gateway.interp2app_temp(f,
+                         unwrap_spec=[gateway.ObjSpace,
+                                      gateway.Arguments]))
+        args = argument.Arguments(space, [])
+        space.raises_w(space.w_SystemError, space.call_args, w_f, args)
+
 
 class AppTestKeywordsToBuiltinSanity(object):
     def test_type(self):
@@ -1134,3 +1157,26 @@
 
         d.update(**{clash: 33})
         dict.update(d, **{clash: 33})
+
+
+
+class AppTestFastPathCrash(object):
+    def setup_class(cls):
+        cls.w_runappdirect = cls.space.wrap(cls.runappdirect)
+
+    def test_fast_path_crash(self):
+        # issue bb-3091 crash in BuiltinCodePassThroughArguments0.funcrun
+        for obj in (dict, set):
+            with raises(TypeError) as excinfo:
+                if self.runappdirect:
+                    import platform
+                    if platform.python_implementation() == 'PyPy':
+                        msg_fmt = "%s instance as first argument (got %s"
+                    else:
+                        msg_fmt = "'%s' object but received a '%s'"
+                    obj.__init__(0)
+                else:
+                    msg_fmt = "'%s' object expected, got '%s'"
+                    obj.__init__.im_func(0)
+            msg = msg_fmt %(obj.__name__, 'int')
+            assert msg in str(excinfo.value)
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -838,7 +838,7 @@
     gi_running = interp_attrproperty('running', cls=GeneratorIterator, wrapfn="newbool"),
     gi_frame   = GetSetProperty(GeneratorIterator.descr_gicr_frame),
     gi_code    = interp_attrproperty_w('pycode', cls=GeneratorIterator),
-    gi_yieldfrom=interp_attrproperty_w('w_yielded_from', cls=GeneratorIterator),
+    gi_yieldfrom=GetSetProperty(GeneratorIterator.descr_delegate),
     __name__   = GetSetProperty(GeneratorIterator.descr__name__,
                                 GeneratorIterator.descr_set__name__),
     __qualname__ = GetSetProperty(GeneratorIterator.descr__qualname__,
@@ -862,7 +862,7 @@
     cr_running = interp_attrproperty('running', cls=Coroutine, wrapfn="newbool"),
     cr_frame   = GetSetProperty(Coroutine.descr_gicr_frame),
     cr_code    = interp_attrproperty_w('pycode', cls=Coroutine),
-    cr_await   = interp_attrproperty_w('w_yielded_from', cls=Coroutine),
+    cr_await=GetSetProperty(Coroutine.descr_delegate),
     __name__   = GetSetProperty(Coroutine.descr__name__,
                                 Coroutine.descr_set__name__,
                                 doc="name of the coroutine"),
@@ -890,7 +890,7 @@
     ag_running = interp_attrproperty('running', cls=AsyncGenerator, wrapfn="newbool"),
     ag_frame   = GetSetProperty(AsyncGenerator.descr_gicr_frame),
     ag_code    = interp_attrproperty_w('pycode', cls=AsyncGenerator),
-    ag_await   = interp_attrproperty_w('w_yielded_from', cls=AsyncGenerator),
+    ag_await=GetSetProperty(AsyncGenerator.descr_delegate),
     __name__   = GetSetProperty(AsyncGenerator.descr__name__,
                                 AsyncGenerator.descr_set__name__,
                                 doc="name of the async generator"),
diff --git a/pypy/interpreter/unicodehelper.py b/pypy/interpreter/unicodehelper.py
--- a/pypy/interpreter/unicodehelper.py
+++ b/pypy/interpreter/unicodehelper.py
@@ -375,6 +375,14 @@
         return res_utf8, len(res), size
 
 def str_decode_utf8(s, errors, final, errorhandler, allow_surrogates=False):
+    try:
+        # fast version first
+        return s, rutf8.check_utf8(s, allow_surrogates=allow_surrogates), len(s)
+    except rutf8.CheckError:
+        return _str_decode_utf8_slowpath(
+            s, errors, final, errorhandler, allow_surrogates=allow_surrogates)
+
+def _str_decode_utf8_slowpath(s, errors, final, errorhandler, allow_surrogates):
     """ Same as checking for the valid utf8, but we know the utf8 is not
     valid so we're trying to either raise or pack stuff with error handler.
     The key difference is that this is call_may_force
diff --git a/pypy/module/_codecs/interp_codecs.py b/pypy/module/_codecs/interp_codecs.py
--- a/pypy/module/_codecs/interp_codecs.py
+++ b/pypy/module/_codecs/interp_codecs.py
@@ -737,17 +737,10 @@
         errors = 'strict'
     final = space.is_true(w_final)
     state = space.fromcache(CodecState)
-    # call the fast version for checking
-    try:
-        lgt = rutf8.check_utf8(string, allow_surrogates=False)
-    except rutf8.CheckError:
-        res, lgt, pos = unicodehelper.str_decode_utf8(string,
-            errors, final, state.decode_error_handler)
-        return space.newtuple([space.newutf8(res, lgt),
-                               space.newint(pos)])
-    else:
-        return space.newtuple([space.newutf8(string, lgt),
-                               space.newint(len(string))])
+    res, lgt, pos = unicodehelper.str_decode_utf8(string,
+        errors, final, state.decode_error_handler)
+    return space.newtuple([space.newutf8(res, lgt),
+                           space.newint(pos)])
 
 @unwrap_spec(data='bufferstr', errors='text_or_none', byteorder=int,
              w_final=WrappedDefault(False))
diff --git a/pypy/module/_csv/interp_csv.py b/pypy/module/_csv/interp_csv.py
--- a/pypy/module/_csv/interp_csv.py
+++ b/pypy/module/_csv/interp_csv.py
@@ -1,3 +1,4 @@
+from rpython.rlib import rutf8
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.typedef import TypeDef, interp_attrproperty
@@ -47,24 +48,26 @@
     if w_src is None:
         return default
     try:
-        return space.realunicode_w(w_src)
+        return space.text_w(w_src)
     except OperationError as e:
         if e.match(space, space.w_TypeError):
             raise oefmt(space.w_TypeError, '"%s" must be a string', attrname)
         raise
 
-def _get_char(space, w_src, default, name):
+def _get_codepoint(space, w_src, default, name):
     if w_src is None:
         return default
     if space.is_w(w_src, space.w_None):
-        return u'\0'
+        return 0
     if not space.isinstance_w(w_src, space.w_unicode):
         raise oefmt(space.w_TypeError, '"%s" must be string, not %T', name, w_src)
-    src = space.realunicode_w(w_src)
-    if len(src) == 1:
-        return src[0]
+    src, length = space.utf8_len_w(w_src)
+    if length == 1:
+        res = rutf8.codepoint_at_pos(src, 0)
+        assert res >= 0
+        return res
     if len(src) == 0:
-        return u'\0'
+        return 0
     raise oefmt(space.w_TypeError, '"%s" must be a 1-character string', name)
 
 def _build_dialect(space, w_dialect, w_delimiter, w_doublequote,
@@ -104,11 +107,11 @@
             w_strict = _fetch(space, w_dialect, 'strict')
 
     dialect = W_Dialect()
-    dialect.delimiter = _get_char(space, w_delimiter, u',', 'delimiter')
+    dialect.delimiter = _get_codepoint(space, w_delimiter, ord(u','), 'delimiter')
     dialect.doublequote = _get_bool(space, w_doublequote, True)
-    dialect.escapechar = _get_char(space, w_escapechar, u'\0', 'escapechar')
-    dialect.lineterminator = _get_str(space, w_lineterminator, u'\r\n', 'lineterminator')
-    dialect.quotechar = _get_char(space, w_quotechar, u'"', 'quotechar')
+    dialect.escapechar = _get_codepoint(space, w_escapechar, ord(u'\0'), 'escapechar')
+    dialect.lineterminator = _get_str(space, w_lineterminator, '\r\n', 'lineterminator')
+    dialect.quotechar = _get_codepoint(space, w_quotechar, ord(u'"'), 'quotechar')
     tmp_quoting = _get_int(space, w_quoting, QUOTE_MINIMAL, 'quoting')
     dialect.skipinitialspace = _get_bool(space, w_skipinitialspace, False)
     dialect.strict = _get_bool(space, w_strict, False)
@@ -117,13 +120,13 @@
     if not (0 <= tmp_quoting < 4):
         raise oefmt(space.w_TypeError, 'bad "quoting" value')
 
-    if dialect.delimiter == u'\0':
+    if dialect.delimiter == 0:
         raise oefmt(space.w_TypeError,
                     '"delimiter" must be a 1-character string')
 
     if space.is_w(w_quotechar, space.w_None) and w_quoting is None:
         tmp_quoting = QUOTE_NONE
-    if tmp_quoting != QUOTE_NONE and dialect.quotechar == u'\0':
+    if tmp_quoting != QUOTE_NONE and dialect.quotechar == 0:
         raise oefmt(space.w_TypeError,
                     "quotechar must be set if quoting enabled")
     dialect.quoting = tmp_quoting
@@ -158,14 +161,20 @@
 
 
 def _get_escapechar(space, dialect):
-    if dialect.escapechar == u'\0':
+    if dialect.escapechar == 0:
         return space.w_None
-    return space.newtext(dialect.escapechar)
+    s = rutf8.unichr_as_utf8(dialect.escapechar)
+    return space.newutf8(s, 1)
 
 def _get_quotechar(space, dialect):
-    if dialect.quotechar == u'\0':
+    if dialect.quotechar == 0:
         return space.w_None
-    return space.newtext(dialect.quotechar)
+    s = rutf8.unichr_as_utf8(dialect.quotechar)
+    return space.newutf8(s, 1)
+
+def _get_delimiter(space, dialect):
+    s = rutf8.unichr_as_utf8(dialect.delimiter)
+    return space.newutf8(s, 1)
 
 
 W_Dialect.typedef = TypeDef(
@@ -173,8 +182,7 @@
         __new__ = interp2app(W_Dialect___new__),
         __reduce_ex__ = interp2app(W_Dialect.reduce_ex_w),
 
-        delimiter        = interp_attrproperty('delimiter', W_Dialect,
-            wrapfn='newtext'),
+        delimiter        = GetSetProperty(_get_delimiter, cls=W_Dialect),
         doublequote      = interp_attrproperty('doublequote', W_Dialect,
             wrapfn='newbool'),
         escapechar       = GetSetProperty(_get_escapechar, cls=W_Dialect),
diff --git a/pypy/module/_csv/interp_reader.py b/pypy/module/_csv/interp_reader.py
--- a/pypy/module/_csv/interp_reader.py
+++ b/pypy/module/_csv/interp_reader.py
@@ -1,5 +1,4 @@
-from rpython.rlib.rstring import UnicodeBuilder
-from rpython.rlib.rutf8 import Utf8StringIterator
+from rpython.rlib.rutf8 import Utf8StringIterator, Utf8StringBuilder
 from rpython.rlib import objectmodel
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError
@@ -22,6 +21,7 @@
         self.dialect = dialect
         self.w_iter = w_iter
         self.line_num = 0
+        self.sizehint = 1  # just used for first line
 
     def iter_w(self):
         return self
@@ -38,22 +38,21 @@
         assert field_builder is not None
         if field_builder.getlength() >= field_limit.limit:
             raise self.error(u"field larger than field limit")
-        field_builder.append(c)
+        field_builder.append_code(c)
 
     def save_field(self, field_builder):
         space = self.space
         field = field_builder.build()
+        w_obj = space.newutf8(field, field_builder.getlength())
         if self.numeric_field:
             self.numeric_field = False
-            w_obj = space.call_function(space.w_float, space.newtext(field))
-        else:
-            w_obj = space.newtext(field)
+            w_obj = space.call_function(space.w_float, w_obj)
         self.fields_w.append(w_obj)
 
     def next_w(self):
         space = self.space
         dialect = self.dialect
-        self.fields_w = []
+        self.fields_w = objectmodel.newlist_hint(self.sizehint)
         self.numeric_field = False
         field_builder = None  # valid iff state not in [START_RECORD, EAT_CRNL]
         state = START_RECORD
@@ -79,13 +78,11 @@
                                  u"(did you open the file in text mode?")
             line = space.utf8_w(w_line)
             for c in Utf8StringIterator(line):
-                # XXX rewrite this to use c (as int) not unichr(c)
-                c = unichr(c)
-                if c == '\0':
+                if c == 0:
                     raise self.error(u"line contains NULL byte")
 
                 if state == START_RECORD:
-                    if c == b'\n' or c == b'\r':
+                    if c == ord(u'\n') or c == ord(u'\r'):
                         state = EAT_CRNL
                         continue
                     # normal character - handle as START_FIELD
@@ -93,9 +90,9 @@
                     # fall-through to the next case
 
                 if state == START_FIELD:
-                    field_builder = UnicodeBuilder(64)
+                    field_builder = Utf8StringBuilder(64)
                     # expecting field
-                    if c == u'\n' or c == u'\r':
+                    if c == ord(u'\n') or c == ord(u'\r'):
                         # save empty field
                         self.save_field(field_builder)
                         state = EAT_CRNL
@@ -106,7 +103,7 @@
                     elif c == dialect.escapechar:
                         # possible escaped character
                         state = ESCAPED_CHAR
-                    elif c == u' ' and dialect.skipinitialspace:
+                    elif c == ord(u' ') and dialect.skipinitialspace:
                         # ignore space at start of field
                         pass
                     elif c == dialect.delimiter:
@@ -120,7 +117,7 @@
                         state = IN_FIELD
 
                 elif state == ESCAPED_CHAR:
-                    if c in '\n\r':
+                    if c == ord(u'\n') or c == ord(u'\r'):
                         self.add_char(field_builder, c)
                         state = AFTER_ESCAPED_CRNL
                     else:
@@ -129,7 +126,7 @@
 
                 elif state == IN_FIELD or state == AFTER_ESCAPED_CRNL:
                     # in unquoted field
-                    if c == u'\n' or c == u'\r':
+                    if c == ord(u'\n') or c == ord(u'\r'):
                         # end of line
                         self.save_field(field_builder)
                         state = EAT_CRNL
@@ -176,7 +173,7 @@
                         # save field - wait for new field
                         self.save_field(field_builder)
                         state = START_FIELD
-                    elif c == u'\n' or c == u'\r':
+                    elif c == ord(u'\n') or c == ord(u'\r'):
                         # end of line
                         self.save_field(field_builder)
                         state = EAT_CRNL
@@ -186,10 +183,10 @@
                     else:
                         # illegal
                         raise self.error(u"'%s' expected after '%s'" % (
-                            dialect.delimiter, dialect.quotechar))
+                            unichr(dialect.delimiter), unichr(dialect.quotechar)))
 
                 elif state == EAT_CRNL:
-                    if not (c == u'\n' or c == u'\r'):
+                    if not (c == ord(u'\n') or c == ord(u'\r')):
                         raise self.error(u"new-line character seen in unquoted "
                                          u"field - do you need to open the file "
                                          u"in universal-newline mode?")
@@ -198,16 +195,16 @@
                 self.save_field(field_builder)
                 break
             elif state == ESCAPED_CHAR:
-                self.add_char(field_builder, u'\n')
+                self.add_char(field_builder, ord(u'\n'))
                 state = IN_FIELD
             elif state == IN_QUOTED_FIELD:
                 pass
             elif state == ESCAPE_IN_QUOTED_FIELD:
-                self.add_char(field_builder, u'\n')
+                self.add_char(field_builder, ord(u'\n'))
                 state = IN_QUOTED_FIELD
             elif state == START_FIELD:
                 # save empty field
-                field_builder = UnicodeBuilder(1)
+                field_builder = Utf8StringBuilder()
                 self.save_field(field_builder)
                 break
             elif state == AFTER_ESCAPED_CRNL:
@@ -216,6 +213,8 @@
                 break
         #
         w_result = space.newlist(self.fields_w)
+        # assume all lines have the same number of fields
+        self.sizehint = len(self.fields_w)
         self.fields_w = None
         return w_result
 
diff --git a/pypy/module/_csv/interp_writer.py b/pypy/module/_csv/interp_writer.py
--- a/pypy/module/_csv/interp_writer.py
+++ b/pypy/module/_csv/interp_writer.py
@@ -1,4 +1,4 @@
-from rpython.rlib.rstring import UnicodeBuilder
+from rpython.rlib.rutf8 import Utf8StringIterator, Utf8StringBuilder
 from rpython.rlib import objectmodel
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError
@@ -15,11 +15,13 @@
         self.dialect = dialect
         self.w_filewrite = space.getattr(w_fileobj, space.newtext('write'))
         # precompute this
-        special = dialect.delimiter + dialect.lineterminator
-        if dialect.escapechar != '\0':
-            special += dialect.escapechar
-        if dialect.quotechar != '\0':
-            special += dialect.quotechar
+        special = [dialect.delimiter]
+        for c in Utf8StringIterator(dialect.lineterminator):
+            special.append(c)
+        if dialect.escapechar != 0:
+            special.append(dialect.escapechar)
+        if dialect.quotechar != 0:
+            special.append(dialect.quotechar)
         self.special_characters = special
 
     @objectmodel.dont_inline
@@ -35,16 +37,17 @@
         space = self.space
         fields_w = space.listview(w_fields)
         dialect = self.dialect
-        rec = UnicodeBuilder(80)
+        rec = Utf8StringBuilder(80)
         #
         for field_index in range(len(fields_w)):
             w_field = fields_w[field_index]
             if space.is_w(w_field, space.w_None):
-                field = u""
+                field = ""
+                length = 0
             elif space.isinstance_w(w_field, space.w_float):
-                field = space.realunicode_w(space.repr(w_field))
+                field, length = space.utf8_len_w(space.repr(w_field))
             else:
-                field = space.realunicode_w(space.str(w_field))
+                field, length = space.utf8_len_w(space.str(w_field))
             #
             if dialect.quoting == QUOTE_NONNUMERIC:
                 try:
@@ -57,9 +60,9 @@
             elif dialect.quoting == QUOTE_ALL:
                 quoted = True
             elif dialect.quoting == QUOTE_MINIMAL:
-                # Find out if we really quoting
+                # Find out if we really need quoting.
                 special_characters = self.special_characters
-                for c in field:
+                for c in Utf8StringIterator(field):
                     if c in special_characters:
                         if c != dialect.quotechar or dialect.doublequote:
                             quoted = True
@@ -78,15 +81,15 @@
 
             # If this is not the first field we need a field separator
             if field_index > 0:
-                rec.append(dialect.delimiter)
+                rec.append_code(dialect.delimiter)
 
             # Handle preceding quote
             if quoted:
-                rec.append(dialect.quotechar)
+                rec.append_code(dialect.quotechar)
 
             # Copy field data
             special_characters = self.special_characters
-            for c in field:
+            for c in Utf8StringIterator(field):
                 if c in special_characters:
                     if dialect.quoting == QUOTE_NONE:
                         want_escape = True
@@ -94,28 +97,28 @@
                         want_escape = False
                         if c == dialect.quotechar:
                             if dialect.doublequote:
-                                rec.append(dialect.quotechar)
+                                rec.append_code(dialect.quotechar)
                             else:
                                 want_escape = True
                     if want_escape:
-                        if dialect.escapechar == u'\0':
+                        if dialect.escapechar == 0:
                             raise self.error("need to escape, "
                                              "but no escapechar set")
-                        rec.append(dialect.escapechar)
+                        rec.append_code(dialect.escapechar)
                     else:
                         assert quoted
                 # Copy field character into record buffer
-                rec.append(c)
+                rec.append_code(c)
 
             # Handle final quote
             if quoted:
-                rec.append(dialect.quotechar)
+                rec.append_code(dialect.quotechar)
 
         # Add line terminator
         rec.append(dialect.lineterminator)
 
         line = rec.build()
-        return space.call_function(self.w_filewrite, space.newtext(line))
+        return space.call_function(self.w_filewrite, space.newutf8(line, rec.getlength()))
 
     def writerows(self, w_seqseq):
         """Construct and write a series of sequences to a csv file.
diff --git a/pypy/module/_multibytecodec/src/cjkcodecs/_codecs_cn.c b/pypy/module/_multibytecodec/src/cjkcodecs/_codecs_cn.c
--- a/pypy/module/_multibytecodec/src/cjkcodecs/_codecs_cn.c
+++ b/pypy/module/_multibytecodec/src/cjkcodecs/_codecs_cn.c
@@ -266,7 +266,9 @@
             REQUIRE_INBUF(4)
             c3 = IN3;
             c4 = IN4;
-            if (c < 0x81 || c3 < 0x81 || c4 < 0x30 || c4 > 0x39)
+            if (c  < 0x81 || c  > 0xFE ||
+                c3 < 0x81 || c3 > 0xFE ||
+                c4 < 0x30 || c4 > 0x39)
                 return 1;
             c -= 0x81;  c2 -= 0x30;
             c3 -= 0x81; c4 -= 0x30;
@@ -333,14 +335,16 @@
         DBCHAR code;
 
         if (c < 0x80) {
-            if (state->i == 0) {
-                WRITE1((unsigned char)c)
-                NEXT(1, 1)
+            if (state->i) {
+                WRITE2('~', '}');
+                NEXT_OUT(2);
+                state->i = 0;
             }
-            else {
-                WRITE3('~', '}', (unsigned char)c)
-                NEXT(1, 3)
-                state->i = 0;
+            WRITE1((unsigned char)c);
+            NEXT(1, 1);
+            if (c == '~') {
+                WRITE1('~');
+                NEXT_OUT(1);
             }
             continue;
         }
@@ -388,17 +392,15 @@
             unsigned char c2 = IN2;
 
             REQUIRE_INBUF(2)
-            if (c2 == '~') {
+            if (c2 == '~' && state->i == 0) {
                 WRITE1('~')
-                NEXT(2, 1)
-                continue;
             }
             else if (c2 == '{' && state->i == 0)
                 state->i = 1; /* set GB */
+            else if (c2 == '\n' && state->i == 0)
+                ; /* line-continuation */
             else if (c2 == '}' && state->i == 1)
                 state->i = 0; /* set ASCII */
-            else if (c2 == '\n')
-                ; /* line-continuation */
             else
                 return 1;
             NEXT(2, 0);
diff --git a/pypy/module/_multibytecodec/test/test_c_codecs.py b/pypy/module/_multibytecodec/test/test_c_codecs.py
--- a/pypy/module/_multibytecodec/test/test_c_codecs.py
+++ b/pypy/module/_multibytecodec/test/test_c_codecs.py
@@ -1,4 +1,5 @@
 import py
+import pytest
 from pypy.module._multibytecodec.c_codecs import getcodec, codecs
 from pypy.module._multibytecodec.c_codecs import decode, encode
 from pypy.module._multibytecodec.c_codecs import EncodeDecodeError
@@ -18,6 +19,15 @@
     u = decode(c, "foobar")
     assert u == "foobar"
 
+ at pytest.mark.parametrize('undecodable', [
+    b"abc\x80\x80\xc1\xc4",
+    b"\xff\x30\x81\x30", b"\x81\x30\xff\x30",  # bpo-29990
+])
+def test_decode_gb18030_error(undecodable):
+    c = getcodec("gb18030")
+    with pytest.raises(EncodeDecodeError):
+        decode(c, undecodable)
+
 def test_decode_hz():
     # stateful
     c = getcodec("hz")
@@ -99,6 +109,9 @@
     assert s == 'foobar' and type(s) is str
     s = encode(c, u'\u5f95\u6cef'.encode('utf8'), 2)
     assert s == '~{abc}~}'
+    # bpo-30003
+    s = encode(c, 'ab~cd', 5)
+    assert s == 'ab~~cd'
 
 def test_encode_hz_error():
     # error
diff --git a/pypy/module/_pypyjson/interp_decoder.py b/pypy/module/_pypyjson/interp_decoder.py
--- a/pypy/module/_pypyjson/interp_decoder.py
+++ b/pypy/module/_pypyjson/interp_decoder.py
@@ -73,6 +73,9 @@
     # hit in the cache
     STRING_CACHE_USEFULNESS_FACTOR = 4
 
+    # don't make arbitrarily huge maps
+    MAX_MAP_SIZE = 100
+
 
     def __init__(self, space, s):
         self.space = space
@@ -369,7 +372,7 @@
                 return w_res
             elif ch == ',':
                 i = self.skip_whitespace(i)
-                if currmap.is_state_blocked():
+                if currmap.is_state_blocked() or nextindex > self.MAX_MAP_SIZE:
                     self.scratch.append(values_w)  # can reuse next time
                     dict_w = self._switch_to_dict(currmap, values_w, nextindex)
                     return self.decode_object_dict(i, start, dict_w)
diff --git a/pypy/module/_pypyjson/simd.py b/pypy/module/_pypyjson/simd.py
--- a/pypy/module/_pypyjson/simd.py
+++ b/pypy/module/_pypyjson/simd.py
@@ -1,7 +1,7 @@
 from rpython.rtyper.lltypesystem import lltype, rffi
 from rpython.rlib import objectmodel, unroll
 from rpython.rlib.rarithmetic import r_uint, intmask, LONG_BIT
-from rpython.jit.backend.detect_cpu import autodetect
+from rpython.jit.backend.detect_cpu import autodetect, ProcessorAutodetectError
 
 # accelerators for string operations using simd on regular word sizes (*not*
 # SSE instructions). this style is sometimes called SWAR (SIMD Within A
@@ -15,8 +15,11 @@
     WORD_SIZE = 8
     EVERY_BYTE_ONE = 0x0101010101010101
     EVERY_BYTE_HIGHEST_BIT = 0x8080808080808080
-    if autodetect() == "x86-64":
-        USE_SIMD = True
+    try:
+        if autodetect() == "x86-64":
+            USE_SIMD = True
+    except ProcessorAutodetectError:
+        pass
 else:
     WORD_SIZE = 4
     EVERY_BYTE_ONE = 0x01010101
diff --git a/pypy/module/_pypyjson/test/test__pypyjson.py b/pypy/module/_pypyjson/test/test__pypyjson.py
--- a/pypy/module/_pypyjson/test/test__pypyjson.py
+++ b/pypy/module/_pypyjson/test/test__pypyjson.py
@@ -467,6 +467,14 @@
         res = _pypyjson.loads(json)
         assert res == [{u'a': 1}, {u'a': 2}]
 
+    def test_huge_map(self):
+        import _pypyjson
+        import __pypy__
+        s = '{' + ",".join('"%s": %s' % (i, i) for i in range(200)) + '}'
+        res = _pypyjson.loads(s)
+        assert len(res) == 200
+        assert __pypy__.strategy(res) == "UnicodeDictStrategy"
+
     def test_tab_in_string_should_fail(self):
         import _pypyjson
         # http://json.org/JSON_checker/test/fail25.json
diff --git a/pypy/module/_vmprof/interp_vmprof.py b/pypy/module/_vmprof/interp_vmprof.py
--- a/pypy/module/_vmprof/interp_vmprof.py
+++ b/pypy/module/_vmprof/interp_vmprof.py
@@ -9,15 +9,15 @@
 # ____________________________________________________________
 
 
-_get_code = lambda frame, w_inputvalue, operr: frame.pycode
+_get_code = lambda frame, w_arg_or_err: frame.pycode
 _decorator = rvmprof.vmprof_execute_code("pypy", _get_code, W_Root)
 my_execute_frame = _decorator(PyFrame.execute_frame)
 
 
 class __extend__(PyFrame):
-    def execute_frame(self, in_generator=None, w_arg_or_err=None):
+    def execute_frame(self, w_arg_or_err=None):
         # indirection for the optional arguments
-        return my_execute_frame(self, in_generator, w_arg_or_err)
+        return my_execute_frame(self, w_arg_or_err)
 
 
 def _safe(s):
diff --git a/pypy/module/_weakref/interp__weakref.py b/pypy/module/_weakref/interp__weakref.py
--- a/pypy/module/_weakref/interp__weakref.py
+++ b/pypy/module/_weakref/interp__weakref.py
@@ -157,6 +157,8 @@
 
 
 class W_WeakrefBase(W_Root):
+    exact_class_applevel_name = 'weakref-or-proxy'
+
     def __init__(self, space, w_obj, w_callable):
         assert w_callable is not space.w_None    # should be really None
         self.space = space
diff --git a/pypy/module/_weakref/test/test_weakref.py b/pypy/module/_weakref/test/test_weakref.py
--- a/pypy/module/_weakref/test/test_weakref.py
+++ b/pypy/module/_weakref/test/test_weakref.py
@@ -545,3 +545,12 @@
         p1[42] = p2
         assert a1.setkey == 42
         assert a1.setvalue is p2
+
+    def test_error_message_wrong_self(self):
+        import _weakref
+        unboundmeth = _weakref.ref.__repr__
+        e = raises(TypeError, unboundmeth, 42)
+        assert "weakref" in str(e.value)
+        if hasattr(unboundmeth, 'im_func'):
+            e = raises(TypeError, unboundmeth.im_func, 42)
+            assert "'weakref-or-proxy'" in str(e.value)
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
@@ -80,6 +80,16 @@
     # XXX this is wrong with IntMutableCell.  Hope it works...
     return w_dict.getitem(w_key)
 
+ at cpython_api([PyObject, PyObject], PyObject, result_borrowed=True)
+def PyDict_GetItemWithError(space, w_dict, w_key):
+    """Variant of PyDict_GetItem() that does not suppress
+    exceptions. Return NULL with an exception set if an exception
+    occurred.  Return NULL without an exception set if the key
+    wasn't present."""
+    if not isinstance(w_dict, W_DictMultiObject):
+        PyErr_BadInternalCall(space)
+    return w_dict.getitem(w_key)
+
 @cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1)
 def PyDict_SetItem(space, w_dict, w_key, w_obj):
     if not isinstance(w_dict, W_DictMultiObject):
@@ -298,3 +308,5 @@
             return 0
     return 1
 
+#def PyObject_GenericGetDict(space, w_obj, context):
+#    unlike CPython, you'll find this one in object.py together with ..SetDict
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -444,3 +444,16 @@
             del d[w_obj]
         except KeyError:
             pass
+
+ at cpython_api([PyObject, rffi.VOIDP], PyObject)
+def PyObject_GenericGetDict(space, w_obj, context):
+    from pypy.interpreter.typedef import descr_get_dict
+    return descr_get_dict(space, w_obj)
+
+ at cpython_api([PyObject, PyObject, rffi.VOIDP], rffi.INT_real, error=-1)
+def PyObject_GenericSetDict(space, w_obj, w_value, context):
+    from pypy.interpreter.typedef import descr_set_dict
+    if w_value is None:
+        raise oefmt(space.w_TypeError, "cannot delete __dict__")
+    descr_set_dict(space, w_obj, w_value)
+    return 0
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
@@ -243,14 +243,6 @@
 def PyWrapper_New(space, w_d, w_self):
     raise NotImplementedError
 
- at cpython_api([PyObject, PyObject], PyObject)
-def PyDict_GetItemWithError(space, p, key):
-    """Variant of PyDict_GetItem() that does not suppress
-    exceptions. Return NULL with an exception set if an exception
-    occurred.  Return NULL without an exception set if the key
-    wasn't present."""
-    raise NotImplementedError
-
 @cpython_api([PyObject, PyObject, rffi.INT_real], rffi.INT_real, error=-1)
 def PyDict_MergeFromSeq2(space, a, seq2, override):
     """Update or merge into dictionary a, from the key-value pairs in seq2.
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
@@ -175,6 +175,26 @@
             ])
         assert module.dict_proxy({'a': 1, 'b': 2}) == 2
 
+    def test_getitemwitherror(self):
+        module = self.import_extension('foo', [
+            ("dict_getitem", "METH_VARARGS",
+             """
+             PyObject *d, *key, *result;
+             if (!PyArg_ParseTuple(args, "OO", &d, &key)) {
+                return NULL;
+             }
+             result = PyDict_GetItemWithError(d, key);
+             if (result == NULL && !PyErr_Occurred())
+                Py_RETURN_NONE;
+             Py_XINCREF(result);
+             return result;
+             """)])
+        d = {'foo': 'bar'}
+        assert module.dict_getitem(d, 'foo') == 'bar'
+        assert module.dict_getitem(d, 'missing') is None
+        with raises(TypeError):
+            module.dict_getitem(d, [])
+
     def test_setdefault(self):
         module = self.import_extension('foo', [
             ("setdefault", "METH_VARARGS",
diff --git a/pypy/module/cpyext/test/test_object.py b/pypy/module/cpyext/test/test_object.py
--- a/pypy/module/cpyext/test/test_object.py
+++ b/pypy/module/cpyext/test/test_object.py
@@ -451,6 +451,31 @@
         assert n == 1
         module.leave(obj2)
 
+    def test_GenericGetSetDict(self):
+        module = self.import_extension('test_GenericGetSetDict', [
+            ('test1', 'METH_VARARGS',
+             """
+                 PyObject *obj = PyTuple_GET_ITEM(args, 0);
+                 PyObject *newdict = PyTuple_GET_ITEM(args, 1);
+
+                 PyObject *olddict = PyObject_GenericGetDict(obj, NULL);
+                 if (olddict == NULL)
+                    return NULL;
+                 int res = PyObject_GenericSetDict(obj, newdict, NULL);
+                 if (res != 0)
+                     return NULL;
+                 return olddict;
+             """)])
+        class A:
+            pass
+        a = A()
+        a.x = 42
+        nd = {'y': 43}
+        d = module.test1(a, nd)
+        assert d == {'x': 42}
+        assert a.y == 43
+        assert a.__dict__ is nd
+
 
 class AppTestPyBuffer_FillInfo(AppTestCpythonExtensionBase):
     """
diff --git a/pypy/module/sys/app.py b/pypy/module/sys/app.py
--- a/pypy/module/sys/app.py
+++ b/pypy/module/sys/app.py
@@ -134,7 +134,6 @@
 
 # This is tested in test_app_main.py
 class sysflags(metaclass=structseqtype):
-
     name = "sys.flags"
 
     debug = structseqfield(0)
@@ -157,29 +156,6 @@
 null__xoptions = {}
 
 
-class asyncgen_hooks(metaclass=structseqtype):
-    name = "asyncgen_hooks"
-
-    firstiter = structseqfield(0)
-    finalizer = structseqfield(1)
-
-# FIXME: make this thread-local
-_current_asyncgen_hooks = asyncgen_hooks((None, None))
-
-def get_asyncgen_hooks():
-    return _current_asyncgen_hooks
-
-_default_arg = object()
-
-def set_asyncgen_hooks(firstiter=_default_arg, finalizer=_default_arg):
-    global _current_asyncgen_hooks
-    if firstiter is _default_arg:
-        firstiter = _current_asyncgen_hooks.firstiter
-    if finalizer is _default_arg:
-        finalizer = _current_asyncgen_hooks.finalizer
-    _current_asyncgen_hooks = asyncgen_hooks((firstiter, finalizer))
-
-
 implementation = SimpleNamespace(
     name='pypy',
     version=sys.version_info,
diff --git a/pypy/module/sys/moduledef.py b/pypy/module/sys/moduledef.py
--- a/pypy/module/sys/moduledef.py
+++ b/pypy/module/sys/moduledef.py
@@ -95,6 +95,8 @@
 
         'get_coroutine_wrapper' : 'vm.get_coroutine_wrapper',
         'set_coroutine_wrapper' : 'vm.set_coroutine_wrapper',
+        'get_asyncgen_hooks'    : 'vm.get_asyncgen_hooks',
+        'set_asyncgen_hooks'    : 'vm.set_asyncgen_hooks',
 
         'is_finalizing'         : 'vm.is_finalizing',
         }
@@ -117,8 +119,6 @@
         'flags'                 : 'app.null_sysflags',
         '_xoptions'             : 'app.null__xoptions',
         'implementation'        : 'app.implementation',
-        'get_asyncgen_hooks'    : 'app.get_asyncgen_hooks',
-        'set_asyncgen_hooks'    : 'app.set_asyncgen_hooks',
 
         # these six attributes are here only during tests;
         # they are removed before translation
@@ -186,7 +186,7 @@
                     if w_file is w_stdout:
                         e.write_unraisable(space, '', w_file)
                     ret = -1
-        return ret 
+        return ret
 
     def _file_is_closed(self, space, w_file):
         try:
diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py
--- a/pypy/module/sys/vm.py
+++ b/pypy/module/sys/vm.py
@@ -7,7 +7,7 @@
 
 from pypy.interpreter import gateway
 from pypy.interpreter.error import oefmt
-from pypy.interpreter.gateway import unwrap_spec
+from pypy.interpreter.gateway import unwrap_spec, WrappedDefault
 
 
 # ____________________________________________________________
@@ -240,6 +240,14 @@
     suite_mask = structseqfield(12, "Bit mask identifying available product suites")
     product_type = structseqfield(13, "System product type")
     platform_version = structseqfield(14, "Diagnostic version number")
+
+
+class asyncgen_hooks(metaclass=structseqtype):
+    name = "asyncgen_hooks"
+
+    firstiter = structseqfield(0)
+    finalizer = structseqfield(1)
+
 ''')
 
 
@@ -286,7 +294,7 @@
 
 getsizeof_missing = """getsizeof(...)
     getsizeof(object, default) -> int
-    
+
     Return the size of object in bytes.
 
 sys.getsizeof(object, default) will always return default on PyPy, and
@@ -351,5 +359,45 @@
     else:
         raise oefmt(space.w_TypeError, "callable expected, got %T", w_wrapper)
 
+def get_asyncgen_hooks(space):
+    """get_asyncgen_hooks()
+
+Return a namedtuple of installed asynchronous generators hooks (firstiter, finalizer)."""
+    ec = space.getexecutioncontext()
+    w_firstiter = ec.w_asyncgen_firstiter_fn
+    if w_firstiter is None:
+        w_firstiter = space.w_None
+    w_finalizer = ec.w_asyncgen_finalizer_fn
+    if w_finalizer is None:
+        w_finalizer = space.w_None
+    w_asyncgen_hooks = app.wget(space, "asyncgen_hooks")
+    return space.call_function(
+        w_asyncgen_hooks,
+        space.newtuple([w_firstiter, w_finalizer]))
+
+# Note: the docstring is wrong on CPython
+def set_asyncgen_hooks(space, w_firstiter=None, w_finalizer=None):
+    """set_asyncgen_hooks(firstiter=None, finalizer=None)
+
+Set a finalizer for async generators objects."""
+    ec = space.getexecutioncontext()
+    if space.is_w(w_finalizer, space.w_None):
+        ec.w_asyncgen_finalizer_fn = None
+    elif w_finalizer is not None:
+        if space.callable_w(w_finalizer):
+            ec.w_asyncgen_finalizer_fn = w_finalizer
+        else:
+            raise oefmt(space.w_TypeError,
+                "callable finalizer expected, got %T", w_finalizer)
+    if space.is_w(w_firstiter, space.w_None):
+        ec.w_asyncgen_firstiter_fn = None
+    elif w_firstiter is not None:
+        if space.callable_w(w_firstiter):
+            ec.w_asyncgen_firstiter_fn = w_firstiter
+        else:
+            raise oefmt(space.w_TypeError,
+                "callable firstiter expected, got %T", w_firstiter)
+
+
 def is_finalizing(space):
     return space.newbool(space.sys.finalizing)
diff --git a/pypy/objspace/fake/objspace.py b/pypy/objspace/fake/objspace.py
--- a/pypy/objspace/fake/objspace.py
+++ b/pypy/objspace/fake/objspace.py
@@ -164,6 +164,9 @@
         is_root(w_obj)
         return NonConstant(False)
 
+    def utf8_len_w(self, space):
+        return NonConstant((NonConstant("utf8len_foobar"), NonConstant(14)))
+
     @not_rpython
     def unwrap(self, w_obj):
         raise NotImplementedError
diff --git a/pypy/objspace/fake/test/test_objspace.py b/pypy/objspace/fake/test/test_objspace.py
--- a/pypy/objspace/fake/test/test_objspace.py
+++ b/pypy/objspace/fake/test/test_objspace.py
@@ -1,4 +1,5 @@
-import py
+import pytest
+from rpython.rlib.nonconst import NonConstant
 from pypy.objspace.fake.objspace import FakeObjSpace, W_Root
 from pypy.interpreter.argument import Arguments
 from pypy.interpreter.typedef import TypeDef
@@ -63,8 +64,8 @@
     def test_is_true(self):
         space = self.space
         space.translates(lambda: space.is_true(W_Root()))
-        py.test.raises(AssertionError,
-                       space.translates, lambda: space.is_true(42))
+        with pytest.raises(AssertionError):
+            space.translates(lambda: space.is_true(42))
 
     def test_unpackiterable(self):
         space = self.space
@@ -79,3 +80,23 @@
         space = self.space
         space.translates(lambda: (space.get(W_Root(), W_Root()),
                                   space.get(W_Root(), W_Root(), W_Root())))
+
+    def test_bug_utf8_len_w(self):
+        space = self.space
+
+        class A(object):
+            pass
+
+        def f():
+            s = NonConstant('a')
+            w_s = space.newutf8(s, 1)
+            t, l = space.utf8_len_w(w_s)
+            a = A()
+            if l == 1:
+                a.x = 1
+            else:
+                raise Exception
+            return a.x
+        space.translates(f)
+
+
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
@@ -19,6 +19,7 @@
 
 class W_AbstractBytesObject(W_Root):
     __slots__ = ()
+    exact_class_applevel_name = 'bytes'
 
     def is_w(self, space, w_other):
         if not isinstance(w_other, W_AbstractBytesObject):
diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py
--- a/pypy/objspace/std/setobject.py
+++ b/pypy/objspace/std/setobject.py
@@ -20,6 +20,7 @@
 
 class W_BaseSetObject(W_Root):
     typedef = None
+    exact_class_applevel_name = 'set-or-frozenset'
 
     def __init__(self, space, w_iterable=None):
         """Initialize the set by taking ownership of 'setdata'."""
@@ -489,6 +490,12 @@
 
 
 class W_SetObject(W_BaseSetObject):
+
+    #overridden here so the error is reported correctly
+    def __init__(self, space, w_iterable=None):
+        """Initialize the set by taking ownership of 'setdata'."""
+        W_BaseSetObject.__init__(self, space, w_iterable)
+
     def _newobj(self, space, w_iterable):
         """Make a new set by taking ownership of 'w_iterable'."""
         return W_SetObject(space, w_iterable)
@@ -504,7 +511,7 @@
 
 Build an unordered collection.""",
     __new__ = gateway.interp2app(W_SetObject.descr_new),
-    __init__ = gateway.interp2app(W_BaseSetObject.descr_init),
+    __init__ = gateway.interp2app(W_SetObject.descr_init),
     __repr__ = gateway.interp2app(W_BaseSetObject.descr_repr),
     __hash__ = None,
 
diff --git a/pypy/objspace/std/test/test_bytesobject.py b/pypy/objspace/std/test/test_bytesobject.py
--- a/pypy/objspace/std/test/test_bytesobject.py
+++ b/pypy/objspace/std/test/test_bytesobject.py
@@ -1050,3 +1050,10 @@
         id_a = id(a)
         assert a is not str(a, 'latin1')
         assert id_a != id_b
+
+    def test_error_message_wrong_self(self):
+        e = raises(TypeError, bytes.upper, 42)
+        assert "bytes" in str(e.value)
+        if hasattr(bytes.upper, 'im_func'):
+            e = raises(TypeError, bytes.upper.im_func, 42)
+            assert "'bytes'" in str(e.value)


More information about the pypy-commit mailing list