[pypy-commit] pypy jit-targets: hg merge default

hakanardo noreply at buildbot.pypy.org
Mon Nov 7 16:49:45 CET 2011


Author: Hakan Ardo <hakan at debian.org>
Branch: jit-targets
Changeset: r48870:fd948f0bae66
Date: 2011-11-07 16:49 +0100
http://bitbucket.org/pypy/pypy/changeset/fd948f0bae66/

Log:	hg merge default

diff --git a/lib-python/conftest.py b/lib-python/conftest.py
--- a/lib-python/conftest.py
+++ b/lib-python/conftest.py
@@ -201,7 +201,7 @@
     RegrTest('test_difflib.py'),
     RegrTest('test_dircache.py', core=True),
     RegrTest('test_dis.py'),
-    RegrTest('test_distutils.py'),
+    RegrTest('test_distutils.py', skip=True),
     RegrTest('test_dl.py', skip=True),
     RegrTest('test_doctest.py', usemodules="thread"),
     RegrTest('test_doctest2.py'),
diff --git a/lib-python/modified-2.7/ctypes/test/test_simplesubclasses.py b/lib-python/modified-2.7/ctypes/test/test_simplesubclasses.py
--- a/lib-python/modified-2.7/ctypes/test/test_simplesubclasses.py
+++ b/lib-python/modified-2.7/ctypes/test/test_simplesubclasses.py
@@ -1,6 +1,5 @@
 import unittest
 from ctypes import *
-from ctypes.test import xfail
 
 class MyInt(c_int):
     def __cmp__(self, other):
@@ -27,7 +26,6 @@
         self.assertEqual(None, cb())
 
 
-    @xfail
     def test_int_callback(self):
         args = []
         def func(arg):
diff --git a/lib_pypy/_ctypes/structure.py b/lib_pypy/_ctypes/structure.py
--- a/lib_pypy/_ctypes/structure.py
+++ b/lib_pypy/_ctypes/structure.py
@@ -17,7 +17,7 @@
         if len(f) == 3:
             if (not hasattr(tp, '_type_')
                 or not isinstance(tp._type_, str)
-                or tp._type_ not in "iIhHbBlL"):
+                or tp._type_ not in "iIhHbBlLqQ"):
                 #XXX: are those all types?
                 #     we just dont get the type name
                 #     in the interp levle thrown TypeError
diff --git a/pypy/jit/metainterp/optimizeopt/__init__.py b/pypy/jit/metainterp/optimizeopt/__init__.py
--- a/pypy/jit/metainterp/optimizeopt/__init__.py
+++ b/pypy/jit/metainterp/optimizeopt/__init__.py
@@ -55,7 +55,7 @@
 
 
 def optimize_loop_1(metainterp_sd, loop, enable_opts,
-                    inline_short_preamble=True, retraced=False, bridge=False):
+                    inline_short_preamble=True, retraced=False):
     """Optimize loop.operations to remove internal overheadish operations.
     """
 
@@ -64,7 +64,7 @@
     if unroll:
         optimize_unroll(metainterp_sd, loop, optimizations)
     else:
-        optimizer = Optimizer(metainterp_sd, loop, optimizations, bridge)
+        optimizer = Optimizer(metainterp_sd, loop, optimizations)
         optimizer.propagate_all_forward()
 
 def optimize_bridge_1(metainterp_sd, bridge, enable_opts,
@@ -76,7 +76,7 @@
     except KeyError:
         pass
     optimize_loop_1(metainterp_sd, bridge, enable_opts,
-                    inline_short_preamble, retraced, bridge=True)
+                    inline_short_preamble, retraced)
 
 if __name__ == '__main__':
     print ALL_OPTS_NAMES
diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -234,7 +234,7 @@
             or op.is_ovf()):
             self.posponedop = op
         else:
-            self.next_optimization.propagate_forward(op)
+            Optimization.emit_operation(self, op)
 
     def emitting_operation(self, op):
         if op.has_no_side_effect():
diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py
--- a/pypy/jit/metainterp/optimizeopt/intbounds.py
+++ b/pypy/jit/metainterp/optimizeopt/intbounds.py
@@ -6,6 +6,7 @@
     IntUpperBound)
 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
 from pypy.jit.metainterp.resoperation import rop
+from pypy.jit.metainterp.optimize import InvalidLoop
 from pypy.rlib.rarithmetic import LONG_BIT
 
 
@@ -13,30 +14,10 @@
     """Keeps track of the bounds placed on integers by guards and remove
        redundant guards"""
 
-    def setup(self):
-        self.posponedop = None
-        self.nextop = None
-
     def new(self):
-        assert self.posponedop is None
         return OptIntBounds()
-        
-    def flush(self):
-        assert self.posponedop is None
-
-    def setup(self):
-        self.posponedop = None
-        self.nextop = None
 
     def propagate_forward(self, op):
-        if op.is_ovf():
-            self.posponedop = op
-            return
-        if self.posponedop:
-            self.nextop = op
-            op = self.posponedop
-            self.posponedop = None
-
         dispatch_opt(self, op)
 
     def opt_default(self, op):
@@ -179,68 +160,75 @@
             r = self.getvalue(op.result)
             r.intbound.intersect(b)
 
+    def optimize_GUARD_NO_OVERFLOW(self, op):
+        lastop = self.last_emitted_operation
+        if lastop is not None:
+            opnum = lastop.getopnum()
+            args = lastop.getarglist()
+            result = lastop.result
+            # If the INT_xxx_OVF was replaced with INT_xxx, then we can kill
+            # the GUARD_NO_OVERFLOW.
+            if (opnum == rop.INT_ADD or
+                opnum == rop.INT_SUB or
+                opnum == rop.INT_MUL):
+                return
+            # Else, synthesize the non overflowing op for optimize_default to
+            # reuse, as well as the reverse op
+            elif opnum == rop.INT_ADD_OVF:
+                self.pure(rop.INT_ADD, args[:], result)
+                self.pure(rop.INT_SUB, [result, args[1]], args[0])
+                self.pure(rop.INT_SUB, [result, args[0]], args[1])
+            elif opnum == rop.INT_SUB_OVF:
+                self.pure(rop.INT_SUB, args[:], result)
+                self.pure(rop.INT_ADD, [result, args[1]], args[0])
+                self.pure(rop.INT_SUB, [args[0], result], args[1])
+            elif opnum == rop.INT_MUL_OVF:
+                self.pure(rop.INT_MUL, args[:], result)
+        self.emit_operation(op)
+
+    def optimize_GUARD_OVERFLOW(self, op):
+        # If INT_xxx_OVF was replaced by INT_xxx, *but* we still see
+        # GUARD_OVERFLOW, then the loop is invalid.
+        lastop = self.last_emitted_operation
+        if lastop is None:
+            raise InvalidLoop
+        opnum = lastop.getopnum()
+        if opnum not in (rop.INT_ADD_OVF, rop.INT_SUB_OVF, rop.INT_MUL_OVF):
+            raise InvalidLoop
+        self.emit_operation(op)
+
     def optimize_INT_ADD_OVF(self, op):
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))
         resbound = v1.intbound.add_bound(v2.intbound)
-        if resbound.has_lower and resbound.has_upper and \
-           self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
-            # Transform into INT_ADD and remove guard
+        if resbound.bounded():
+            # Transform into INT_ADD.  The following guard will be killed
+            # by optimize_GUARD_NO_OVERFLOW; if we see instead an
+            # optimize_GUARD_OVERFLOW, then InvalidLoop.
             op = op.copy_and_change(rop.INT_ADD)
-            self.optimize_INT_ADD(op) # emit the op
-        else:
-            self.emit_operation(op)
-            r = self.getvalue(op.result)
-            r.intbound.intersect(resbound)
-            self.emit_operation(self.nextop)
-            if self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
-                # Synthesize the non overflowing op for optimize_default to reuse
-                self.pure(rop.INT_ADD, op.getarglist()[:], op.result)
-                # Synthesize the reverse op for optimize_default to reuse
-                self.pure(rop.INT_SUB, [op.result, op.getarg(1)], op.getarg(0))
-                self.pure(rop.INT_SUB, [op.result, op.getarg(0)], op.getarg(1))
-
+        self.emit_operation(op) # emit the op
+        r = self.getvalue(op.result)
+        r.intbound.intersect(resbound)
 
     def optimize_INT_SUB_OVF(self, op):
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))
         resbound = v1.intbound.sub_bound(v2.intbound)
-        if resbound.has_lower and resbound.has_upper and \
-               self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
-            # Transform into INT_SUB and remove guard
+        if resbound.bounded():
             op = op.copy_and_change(rop.INT_SUB)
-            self.optimize_INT_SUB(op) # emit the op
-        else:
-            self.emit_operation(op)
-            r = self.getvalue(op.result)
-            r.intbound.intersect(resbound)
-            self.emit_operation(self.nextop)
-            if self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
-                # Synthesize the non overflowing op for optimize_default to reuse
-                self.pure(rop.INT_SUB, op.getarglist()[:], op.result)
-                # Synthesize the reverse ops for optimize_default to reuse
-                self.pure(rop.INT_ADD, [op.result, op.getarg(1)], op.getarg(0))
-                self.pure(rop.INT_SUB, [op.getarg(0), op.result], op.getarg(1))
-
+        self.emit_operation(op) # emit the op
+        r = self.getvalue(op.result)
+        r.intbound.intersect(resbound)
 
     def optimize_INT_MUL_OVF(self, op):
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))
         resbound = v1.intbound.mul_bound(v2.intbound)
-        if resbound.has_lower and resbound.has_upper and \
-               self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
-            # Transform into INT_MUL and remove guard
+        if resbound.bounded():
             op = op.copy_and_change(rop.INT_MUL)
-            self.optimize_INT_MUL(op) # emit the op
-        else:
-            self.emit_operation(op)
-            r = self.getvalue(op.result)
-            r.intbound.intersect(resbound)
-            self.emit_operation(self.nextop)
-            if self.nextop.getopnum() == rop.GUARD_NO_OVERFLOW:
-                # Synthesize the non overflowing op for optimize_default to reuse
-                self.pure(rop.INT_MUL, op.getarglist()[:], op.result)
-
+        self.emit_operation(op)
+        r = self.getvalue(op.result)
+        r.intbound.intersect(resbound)
 
     def optimize_INT_LT(self, op):
         v1 = self.getvalue(op.getarg(0))
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -6,7 +6,7 @@
                                                      IntLowerBound, MININT, MAXINT
 from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
     args_dict)
-from pypy.jit.metainterp.resoperation import rop, ResOperation
+from pypy.jit.metainterp.resoperation import rop, ResOperation, AbstractResOp
 from pypy.jit.metainterp.typesystem import llhelper, oohelper
 from pypy.tool.pairtype import extendabletype
 from pypy.rlib.debug import debug_start, debug_stop, debug_print
@@ -249,6 +249,8 @@
 CVAL_ZERO_FLOAT = ConstantValue(Const._new(0.0))
 llhelper.CVAL_NULLREF = ConstantValue(llhelper.CONST_NULL)
 oohelper.CVAL_NULLREF = ConstantValue(oohelper.CONST_NULL)
+REMOVED = AbstractResOp(None)
+
 
 class Optimization(object):
     next_optimization = None
@@ -260,6 +262,7 @@
         raise NotImplementedError
 
     def emit_operation(self, op):
+        self.last_emitted_operation = op
         self.next_optimization.propagate_forward(op)
 
     # FIXME: Move some of these here?
@@ -327,6 +330,7 @@
     def forget_numberings(self, box):
         self.optimizer.forget_numberings(box)
 
+
 class Optimizer(Optimization):
 
     def __init__(self, metainterp_sd, loop, optimizations=None):
@@ -340,7 +344,6 @@
         self.bool_boxes = {}
         self.producer = {}
         self.pendingfields = []
-        self.exception_might_have_happened = False
         self.quasi_immutable_deps = None
         self.opaque_pointers = {}
         self.replaces_guard = {}
@@ -362,6 +365,7 @@
             optimizations[-1].next_optimization = self
             for o in optimizations:
                 o.optimizer = self
+                o.last_emitted_operation = None
                 o.setup()
         else:
             optimizations = []
@@ -496,7 +500,6 @@
             return CVAL_ZERO
 
     def propagate_all_forward(self, clear=True):
-        self.exception_might_have_happened = True
         if clear:
             self.clear_newoperations()
         for op in self.loop.operations:
diff --git a/pypy/jit/metainterp/optimizeopt/pure.py b/pypy/jit/metainterp/optimizeopt/pure.py
--- a/pypy/jit/metainterp/optimizeopt/pure.py
+++ b/pypy/jit/metainterp/optimizeopt/pure.py
@@ -1,4 +1,4 @@
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
+from pypy.jit.metainterp.optimizeopt.optimizer import Optimization, REMOVED
 from pypy.jit.metainterp.resoperation import rop, ResOperation
 from pypy.jit.metainterp.optimizeopt.util import (make_dispatcher_method,
     args_dict)
@@ -61,7 +61,10 @@
         oldop = self.pure_operations.get(args, None)
         if oldop is not None and oldop.getdescr() is op.getdescr():
             assert oldop.getopnum() == op.getopnum()
+            # this removes a CALL_PURE that has the same (non-constant)
+            # arguments as a previous CALL_PURE.
             self.make_equal_to(op.result, self.getvalue(oldop.result))
+            self.last_emitted_operation = REMOVED
             return
         else:
             self.pure_operations[args] = op
@@ -72,6 +75,13 @@
         self.emit_operation(ResOperation(rop.CALL, args, op.result,
                                          op.getdescr()))
 
+    def optimize_GUARD_NO_EXCEPTION(self, op):
+        if self.last_emitted_operation is REMOVED:
+            # it was a CALL_PURE that was killed; so we also kill the
+            # following GUARD_NO_EXCEPTION
+            return
+        self.emit_operation(op)
+
     def flush(self):
         assert self.posponedop is None
 
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -294,12 +294,6 @@
             raise InvalidLoop
         self.optimize_GUARD_CLASS(op)
 
-    def optimize_GUARD_NO_EXCEPTION(self, op):
-        if not self.optimizer.exception_might_have_happened:
-            return
-        self.emit_operation(op)
-        self.optimizer.exception_might_have_happened = False
-
     def optimize_CALL_LOOPINVARIANT(self, op):
         arg = op.getarg(0)
         # 'arg' must be a Const, because residual_call in codewriter
@@ -310,6 +304,7 @@
         resvalue = self.loop_invariant_results.get(key, None)
         if resvalue is not None:
             self.make_equal_to(op.result, resvalue)
+            self.last_emitted_operation = REMOVED
             return
         # change the op to be a normal call, from the backend's point of view
         # there is no reason to have a separate operation for this
@@ -444,10 +439,19 @@
             except KeyError:
                 pass
             else:
+                # this removes a CALL_PURE with all constant arguments.
                 self.make_constant(op.result, result)
+                self.last_emitted_operation = REMOVED
                 return
         self.emit_operation(op)
 
+    def optimize_GUARD_NO_EXCEPTION(self, op):
+        if self.last_emitted_operation is REMOVED:
+            # it was a CALL_PURE or a CALL_LOOPINVARIANT that was killed;
+            # so we also kill the following GUARD_NO_EXCEPTION
+            return
+        self.emit_operation(op)
+
     def optimize_INT_FLOORDIV(self, op):
         v1 = self.getvalue(op.getarg(0))
         v2 = self.getvalue(op.getarg(1))
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -685,25 +685,60 @@
 
     # ----------
 
-    def test_fold_guard_no_exception(self):
-        ops = """
-        [i]
-        guard_no_exception() []
-        i1 = int_add(i, 3)
-        guard_no_exception() []
+    def test_keep_guard_no_exception(self):
+        ops = """
+        [i1]
         i2 = call(i1, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
-        guard_no_exception() []
-        i3 = call(i2, descr=nonwritedescr)
-        jump(i1)       # the exception is considered lost when we loop back
-        """
-        expected = """
-        [i]
-        i1 = int_add(i, 3)
-        i2 = call(i1, descr=nonwritedescr)
+        jump(i2)
+        """
+        self.optimize_loop(ops, ops)
+
+    def test_keep_guard_no_exception_with_call_pure_that_is_not_folded(self):
+        ops = """
+        [i1]
+        i2 = call_pure(123456, i1, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
-        i3 = call(i2, descr=nonwritedescr)
-        jump(i1)
+        jump(i2)
+        """
+        expected = """
+        [i1]
+        i2 = call(123456, i1, descr=nonwritedescr)
+        guard_no_exception() [i1, i2]
+        jump(i2)
+        """
+        self.optimize_loop(ops, expected)
+
+    def test_remove_guard_no_exception_with_call_pure_on_constant_args(self):
+        arg_consts = [ConstInt(i) for i in (123456, 81)]
+        call_pure_results = {tuple(arg_consts): ConstInt(5)}
+        ops = """
+        [i1]
+        i3 = same_as(81)
+        i2 = call_pure(123456, i3, descr=nonwritedescr)
+        guard_no_exception() [i1, i2]
+        jump(i2)
+        """
+        expected = """
+        [i1]
+        jump(5)
+        """
+        self.optimize_loop(ops, expected, call_pure_results)
+
+    def test_remove_guard_no_exception_with_duplicated_call_pure(self):
+        ops = """
+        [i1]
+        i2 = call_pure(123456, i1, descr=nonwritedescr)
+        guard_no_exception() [i1, i2]
+        i3 = call_pure(123456, i1, descr=nonwritedescr)
+        guard_no_exception() [i1, i2, i3]
+        jump(i3)
+        """
+        expected = """
+        [i1]
+        i2 = call(123456, i1, descr=nonwritedescr)
+        guard_no_exception() [i1, i2]
+        jump(i2)
         """
         self.optimize_loop(ops, expected)
 
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -975,17 +975,14 @@
         [i]
         guard_no_exception() []
         i1 = int_add(i, 3)
-        guard_no_exception() []
         i2 = call(i1, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
-        guard_no_exception() []
         i3 = call(i2, descr=nonwritedescr)
         jump(i1)       # the exception is considered lost when we loop back
         """
-        # note that 'guard_no_exception' at the very start is kept around
-        # for bridges, but not for loops
         preamble = """
         [i]
+        guard_no_exception() []    # occurs at the start of bridges, so keep it
         i1 = int_add(i, 3)
         i2 = call(i1, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
@@ -994,6 +991,7 @@
         """
         expected = """
         [i]
+        guard_no_exception() []    # occurs at the start of bridges, so keep it
         i1 = int_add(i, 3)
         i2 = call(i1, descr=nonwritedescr)
         guard_no_exception() [i1, i2]
@@ -1002,6 +1000,23 @@
         """
         self.optimize_loop(ops, expected, preamble)
 
+    def test_bug_guard_no_exception(self):
+        ops = """
+        []
+        i0 = call(123, descr=nonwritedescr)
+        p0 = call(0, "xy", descr=s2u_descr)      # string -> unicode
+        guard_no_exception() []
+        escape(p0)
+        jump()
+        """
+        expected = """
+        []
+        i0 = call(123, descr=nonwritedescr)
+        escape(u"xy")
+        jump()
+        """
+        self.optimize_loop(ops, expected)
+
     # ----------
 
     def test_call_loopinvariant(self):
@@ -6360,12 +6375,15 @@
     def test_str2unicode_constant(self):
         ops = """
         []
+        escape(1213)
         p0 = call(0, "xy", descr=s2u_descr)      # string -> unicode
+        guard_no_exception() []
         escape(p0)
         jump()
         """
         expected = """
         []
+        escape(1213)
         escape(u"xy")
         jump()
         """
@@ -6375,6 +6393,7 @@
         ops = """
         [p0]
         p1 = call(0, p0, descr=s2u_descr)      # string -> unicode
+        guard_no_exception() []
         escape(p1)
         jump(p1)
         """
diff --git a/pypy/jit/metainterp/optimizeopt/vstring.py b/pypy/jit/metainterp/optimizeopt/vstring.py
--- a/pypy/jit/metainterp/optimizeopt/vstring.py
+++ b/pypy/jit/metainterp/optimizeopt/vstring.py
@@ -2,7 +2,8 @@
 from pypy.jit.metainterp.history import (BoxInt, Const, ConstInt, ConstPtr,
     get_const_ptr_for_string, get_const_ptr_for_unicode, BoxPtr, REF, INT)
 from pypy.jit.metainterp.optimizeopt import optimizer, virtualize
-from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1, llhelper
+from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1
+from pypy.jit.metainterp.optimizeopt.optimizer import llhelper, REMOVED
 from pypy.jit.metainterp.optimizeopt.util import make_dispatcher_method
 from pypy.jit.metainterp.resoperation import rop, ResOperation
 from pypy.rlib.objectmodel import specialize, we_are_translated
@@ -529,6 +530,11 @@
 
     optimize_CALL_PURE = optimize_CALL
 
+    def optimize_GUARD_NO_EXCEPTION(self, op):
+        if self.last_emitted_operation is REMOVED:
+            return
+        self.emit_operation(op)
+
     def opt_call_str_STR2UNICODE(self, op):
         # Constant-fold unicode("constant string").
         # More generally, supporting non-constant but virtual cases is
@@ -543,6 +549,7 @@
         except UnicodeDecodeError:
             return False
         self.make_constant(op.result, get_const_ptr_for_unicode(u))
+        self.last_emitted_operation = REMOVED
         return True
 
     def opt_call_stroruni_STR_CONCAT(self, op, mode):
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -90,7 +90,10 @@
         return op
 
     def __repr__(self):
-        return self.repr()
+        try:
+            return self.repr()
+        except NotImplementedError:
+            return object.__repr__(self)
 
     def repr(self, graytext=False):
         # RPython-friendly version
diff --git a/pypy/jit/metainterp/test/test_resume.py b/pypy/jit/metainterp/test/test_resume.py
--- a/pypy/jit/metainterp/test/test_resume.py
+++ b/pypy/jit/metainterp/test/test_resume.py
@@ -1135,16 +1135,11 @@
     assert ptr2.parent.next == ptr
 
 class CompareableConsts(object):
-    def __init__(self):
-        self.oldeq = None
-        
     def __enter__(self):
-        assert self.oldeq is None
-        self.oldeq = Const.__eq__
         Const.__eq__ = Const.same_box
-        
+
     def __exit__(self, type, value, traceback):
-        Const.__eq__ = self.oldeq
+        del Const.__eq__
 
 def test_virtual_adder_make_varray():
     b2s, b4s = [BoxPtr(), BoxInt(4)]
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -392,6 +392,7 @@
         'Slice': 'space.gettypeobject(W_SliceObject.typedef)',
         'StaticMethod': 'space.gettypeobject(StaticMethod.typedef)',
         'CFunction': 'space.gettypeobject(cpyext.methodobject.W_PyCFunctionObject.typedef)',
+        'WrapperDescr': 'space.gettypeobject(cpyext.methodobject.W_PyCMethodObject.typedef)'
         }.items():
         GLOBALS['Py%s_Type#' % (cpyname, )] = ('PyTypeObject*', pypyexpr)
 
diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -240,6 +240,7 @@
 def PyStaticMethod_New(space, w_func):
     return space.wrap(StaticMethod(w_func))
 
+ at cpython_api([PyObject, lltype.Ptr(PyMethodDef)], PyObject)
 def PyDescr_NewMethod(space, w_type, method):
     return space.wrap(W_PyCMethodObject(space, method, w_type))
 
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -586,10 +586,6 @@
 def PyDescr_NewMember(space, type, meth):
     raise NotImplementedError
 
- at cpython_api([PyTypeObjectPtr, PyMethodDef], PyObject)
-def PyDescr_NewMethod(space, type, meth):
-    raise NotImplementedError
-
 @cpython_api([PyTypeObjectPtr, wrapperbase, rffi.VOIDP], PyObject)
 def PyDescr_NewWrapper(space, type, wrapper, wrapped):
     raise NotImplementedError
@@ -610,14 +606,6 @@
 def PyWrapper_New(space, w_d, w_self):
     raise NotImplementedError
 
- at cpython_api([PyObject], PyObject)
-def PyDictProxy_New(space, dict):
-    """Return a proxy object for a mapping which enforces read-only behavior.
-    This is normally used to create a proxy to prevent modification of the
-    dictionary for non-dynamic class types.
-    """
-    raise NotImplementedError
-
 @cpython_api([PyObject, PyObject, rffi.INT_real], rffi.INT_real, error=-1)
 def PyDict_Merge(space, a, b, override):
     """Iterate over mapping object b adding key-value pairs to dictionary a.
@@ -2293,15 +2281,6 @@
     changes in your code for properly supporting 64-bit systems."""
     raise NotImplementedError
 
- at cpython_api([rffi.CWCHARP, Py_ssize_t, rffi.CCHARP], PyObject)
-def PyUnicode_EncodeUTF8(space, s, size, errors):
-    """Encode the Py_UNICODE buffer of the given size using UTF-8 and return a
-    Python string object.  Return NULL if an exception was raised by the codec.
-
-    This function used an int type for size. This might require
-    changes in your code for properly supporting 64-bit systems."""
-    raise NotImplementedError
-
 @cpython_api([rffi.CCHARP, Py_ssize_t, rffi.CCHARP, rffi.INTP], PyObject)
 def PyUnicode_DecodeUTF32(space, s, size, errors, byteorder):
     """Decode length bytes from a UTF-32 encoded buffer string and return the
@@ -2481,31 +2460,6 @@
     was raised by the codec."""
     raise NotImplementedError
 
- at cpython_api([rffi.CCHARP, Py_ssize_t, rffi.CCHARP], PyObject)
-def PyUnicode_DecodeLatin1(space, s, size, errors):
-    """Create a Unicode object by decoding size bytes of the Latin-1 encoded string
-    s.  Return NULL if an exception was raised by the codec.
-
-    This function used an int type for size. This might require
-    changes in your code for properly supporting 64-bit systems."""
-    raise NotImplementedError
-
- at cpython_api([rffi.CWCHARP, Py_ssize_t, rffi.CCHARP], PyObject)
-def PyUnicode_EncodeLatin1(space, s, size, errors):
-    """Encode the Py_UNICODE buffer of the given size using Latin-1 and return
-    a Python string object.  Return NULL if an exception was raised by the codec.
-
-    This function used an int type for size. This might require
-    changes in your code for properly supporting 64-bit systems."""
-    raise NotImplementedError
-
- at cpython_api([PyObject], PyObject)
-def PyUnicode_AsLatin1String(space, unicode):
-    """Encode a Unicode object using Latin-1 and return the result as Python string
-    object.  Error handling is "strict".  Return NULL if an exception was raised
-    by the codec."""
-    raise NotImplementedError
-
 @cpython_api([rffi.CCHARP, Py_ssize_t, PyObject, rffi.CCHARP], PyObject)
 def PyUnicode_DecodeCharmap(space, s, size, mapping, errors):
     """Create a Unicode object by decoding size bytes of the encoded string s using
@@ -2564,13 +2518,6 @@
     """
     raise NotImplementedError
 
- at cpython_api([PyObject], PyObject)
-def PyUnicode_AsMBCSString(space, unicode):
-    """Encode a Unicode object using MBCS and return the result as Python string
-    object.  Error handling is "strict".  Return NULL if an exception was raised
-    by the codec."""
-    raise NotImplementedError
-
 @cpython_api([PyObject, PyObject], PyObject)
 def PyUnicode_Concat(space, left, right):
     """Concat two strings giving a new Unicode string."""
@@ -2912,16 +2859,3 @@
     """Return true if ob is a proxy object.
     """
     raise NotImplementedError
-
- at cpython_api([PyObject, PyObject], PyObject)
-def PyWeakref_NewProxy(space, ob, callback):
-    """Return a weak reference proxy object for the object ob.  This will always
-    return a new reference, but is not guaranteed to create a new object; an
-    existing proxy object may be returned.  The second parameter, callback, can
-    be a callable object that receives notification when ob is garbage
-    collected; it should accept a single parameter, which will be the weak
-    reference object itself. callback may also be None or NULL.  If ob
-    is not a weakly-referencable object, or if callback is not callable,
-    None, or NULL, this will return NULL and raise TypeError.
-    """
-    raise NotImplementedError
diff --git a/pypy/module/cpyext/test/test_methodobject.py b/pypy/module/cpyext/test/test_methodobject.py
--- a/pypy/module/cpyext/test/test_methodobject.py
+++ b/pypy/module/cpyext/test/test_methodobject.py
@@ -79,7 +79,7 @@
         raises(TypeError, mod.isSameFunction, 1)
 
 class TestPyCMethodObject(BaseApiTest):
-    def test_repr(self, space):
+    def test_repr(self, space, api):
         """
         W_PyCMethodObject has a repr string which describes it as a method
         and gives its name and the name of its class.
@@ -94,7 +94,7 @@
         ml.c_ml_meth = rffi.cast(PyCFunction_typedef,
                                  c_func.get_llhelper(space))
 
-        method = PyDescr_NewMethod(space, space.w_str, ml)
+        method = api.PyDescr_NewMethod(space.w_str, ml)
         assert repr(method).startswith(
             "<built-in method 'func' of 'str' object ")
 
diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py
--- a/pypy/module/cpyext/test/test_unicodeobject.py
+++ b/pypy/module/cpyext/test/test_unicodeobject.py
@@ -188,6 +188,12 @@
         assert space.unwrap(w_u) == 'sp'
         rffi.free_charp(u)
 
+    def test_encode_utf8(self, space, api):
+        u = rffi.unicode2wcharp(u'sp&#65533;m')
+        w_s = api.PyUnicode_EncodeUTF8(u, 4, None)
+        assert space.unwrap(w_s) == u'sp&#65533;m'.encode('utf-8')
+        rffi.free_wcharp(u)
+
     def test_IS(self, space, api):
         for char in [0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x1c, 0x1d, 0x1e, 0x1f,
                      0x20, 0x85, 0xa0, 0x1680, 0x2000, 0x2001, 0x2002,
@@ -385,6 +391,24 @@
                     data, len(u), lltype.nullptr(rffi.CCHARP.TO))
         rffi.free_wcharp(data)
 
+    def test_latin1(self, space, api):
+        s = 'abcdefg'
+        data = rffi.str2charp(s)
+        w_u = api.PyUnicode_DecodeLatin1(data, len(s), lltype.nullptr(rffi.CCHARP.TO))
+        assert space.eq_w(w_u, space.wrap(u"abcdefg"))
+        rffi.free_charp(data)
+
+        uni = u'abcdefg'
+        data = rffi.unicode2wcharp(uni)
+        w_s = api.PyUnicode_EncodeLatin1(data, len(uni), lltype.nullptr(rffi.CCHARP.TO))
+        assert space.eq_w(space.wrap("abcdefg"), w_s)
+        rffi.free_wcharp(data)
+
+        ustr = "abcdef"
+        w_ustr = space.wrap(ustr.decode("ascii"))
+        result = api.PyUnicode_AsLatin1String(w_ustr)
+        assert space.eq_w(space.wrap(ustr), result)
+
     def test_format(self, space, api):
         w_format = space.wrap(u'hi %s')
         w_args = space.wrap((u'test',))
diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py
--- a/pypy/module/cpyext/test/test_weakref.py
+++ b/pypy/module/cpyext/test/test_weakref.py
@@ -15,6 +15,12 @@
         assert api.PyErr_Occurred() is space.w_TypeError
         api.PyErr_Clear()
 
+    def test_proxy(self, space, api):
+        w_obj = space.w_Warning # some weakrefable object
+        w_proxy = api.PyWeakref_NewProxy(w_obj, None)
+        assert space.unwrap(space.str(w_proxy)) == "<type 'exceptions.Warning'>"
+        assert space.unwrap(space.repr(w_proxy)).startswith('<weak')
+
     def test_weakref_lockobject(self, space, api):
         # some new weakrefable object
         w_obj = space.call_function(space.w_type, space.wrap("newtype"),
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -14,6 +14,7 @@
 from pypy.module.sys.interp_encoding import setdefaultencoding
 from pypy.objspace.std import unicodeobject, unicodetype
 from pypy.rlib import runicode
+from pypy.tool.sourcetools import func_renamer
 import sys
 
 ## See comment in stringobject.py.
@@ -417,26 +418,49 @@
     ref[0] = rffi.cast(PyObject, py_newuni)
     return 0
 
- at cpython_api([PyObject], PyObject)
-def PyUnicode_AsUTF8String(space, w_unicode):
-    """Encode a Unicode object using UTF-8 and return the result as Python string
-    object.  Error handling is "strict".  Return NULL if an exception was raised
-    by the codec."""
-    if not PyUnicode_Check(space, w_unicode):
-        PyErr_BadArgument(space)
-    return unicodetype.encode_object(space, w_unicode, "utf-8", "strict")
+def make_conversion_functions(suffix, encoding):
+    @cpython_api([PyObject], PyObject)
+    @func_renamer('PyUnicode_As%sString' % suffix)
+    def PyUnicode_AsXXXString(space, w_unicode):
+        """Encode a Unicode object and return the result as Python
+        string object.  Error handling is "strict".  Return NULL if an
+        exception was raised by the codec."""
+        if not PyUnicode_Check(space, w_unicode):
+            PyErr_BadArgument(space)
+        return unicodetype.encode_object(space, w_unicode, encoding, "strict")
 
- at cpython_api([CONST_STRING, Py_ssize_t, CONST_STRING], PyObject)
-def PyUnicode_DecodeUTF8(space, s, size, errors):
-    """Create a Unicode object by decoding size bytes of the UTF-8 encoded string
-    s. Return NULL if an exception was raised by the codec.
-    """
-    w_str = space.wrap(rffi.charpsize2str(s, size))
-    if errors:
-        w_errors = space.wrap(rffi.charp2str(errors))
-    else:
-        w_errors = space.w_None
-    return space.call_method(w_str, 'decode', space.wrap("utf-8"), w_errors)
+    @cpython_api([CONST_STRING, Py_ssize_t, CONST_STRING], PyObject)
+    @func_renamer('PyUnicode_Decode%s' % suffix)
+    def PyUnicode_DecodeXXX(space, s, size, errors):
+        """Create a Unicode object by decoding size bytes of the
+        encoded string s. Return NULL if an exception was raised by
+        the codec.
+        """
+        w_s = space.wrap(rffi.charpsize2str(s, size))
+        if errors:
+            w_errors = space.wrap(rffi.charp2str(errors))
+        else:
+            w_errors = space.w_None
+        return space.call_method(w_s, 'decode', space.wrap(encoding), w_errors)
+
+    @cpython_api([CONST_WSTRING, Py_ssize_t, CONST_STRING], PyObject)
+    @func_renamer('PyUnicode_Encode%s' % suffix)
+    def PyUnicode_EncodeXXX(space, s, size, errors):
+        """Encode the Py_UNICODE buffer of the given size and return a
+        Python string object.  Return NULL if an exception was raised
+        by the codec."""
+        w_u = space.wrap(rffi.wcharpsize2unicode(s, size))
+        if errors:
+            w_errors = space.wrap(rffi.charp2str(errors))
+        else:
+            w_errors = space.w_None
+        return space.call_method(w_u, 'encode', space.wrap(encoding), w_errors)
+
+make_conversion_functions('UTF8', 'utf-8')
+make_conversion_functions('ASCII', 'ascii')
+make_conversion_functions('Latin1', 'latin-1')
+if sys.platform == 'win32':
+    make_conversion_functions('MBCS', 'mbcs')
 
 @cpython_api([rffi.CCHARP, Py_ssize_t, rffi.CCHARP, rffi.INTP], PyObject)
 def PyUnicode_DecodeUTF16(space, s, size, llerrors, pbyteorder):
@@ -493,56 +517,6 @@
 
     return space.wrap(result)
 
- at cpython_api([PyObject], PyObject)
-def PyUnicode_AsASCIIString(space, w_unicode):
-    """Encode a Unicode object using ASCII and return the result as Python string
-    object.  Error handling is "strict".  Return NULL if an exception was raised
-    by the codec."""
-    return space.call_method(w_unicode, 'encode', space.wrap('ascii')) #space.w_None for errors?
-
- at cpython_api([rffi.CCHARP, Py_ssize_t, rffi.CCHARP], PyObject)
-def PyUnicode_DecodeASCII(space, s, size, errors):
-    """Create a Unicode object by decoding size bytes of the ASCII encoded string
-    s.  Return NULL if an exception was raised by the codec."""
-    w_s = space.wrap(rffi.charpsize2str(s, size))
-    return space.call_method(w_s, 'decode', space.wrap('ascii'))
-
- at cpython_api([rffi.CWCHARP, Py_ssize_t, rffi.CCHARP], PyObject)
-def PyUnicode_EncodeASCII(space, s, size, errors):
-    """Encode the Py_UNICODE buffer of the given size using ASCII and return a
-    Python string object.  Return NULL if an exception was raised by the codec.
-    """
-
-    w_s = space.wrap(rffi.wcharpsize2unicode(s, size))
-    return space.call_method(w_s, 'encode', space.wrap('ascii'))
-
-if sys.platform == 'win32':
-    @cpython_api([CONST_WSTRING, Py_ssize_t, CONST_STRING], PyObject)
-    def PyUnicode_EncodeMBCS(space, wchar_p, length, errors):
-        """Encode the Py_UNICODE buffer of the given size using MBCS and return a
-        Python string object.  Return NULL if an exception was raised by the codec.
-        """
-        w_unicode = space.wrap(rffi.wcharpsize2unicode(wchar_p, length))
-        if errors:
-            w_errors = space.wrap(rffi.charp2str(errors))
-        else:
-            w_errors = space.w_None
-        return space.call_method(w_unicode, "encode",
-                                 space.wrap("mbcs"), w_errors)
-
-    @cpython_api([CONST_STRING, Py_ssize_t, CONST_STRING], PyObject)
-    def PyUnicode_DecodeMBCS(space, s, size, errors):
-        """Create a Unicode object by decoding size bytes of the MBCS encoded string s.
-        Return NULL if an exception was raised by the codec.
-        """
-        w_str = space.wrap(rffi.charpsize2str(s, size))
-        w_encoding = space.wrap("mbcs")
-        if errors:
-            w_errors = space.wrap(rffi.charp2str(errors))
-        else:
-            w_errors = space.w_None
-        return space.call_method(w_str, 'decode', w_encoding, w_errors)
-
 @cpython_api([PyObject, PyObject], rffi.INT_real, error=-2)
 def PyUnicode_Compare(space, w_left, w_right):
     """Compare two strings and return -1, 0, 1 for less than, equal, and greater
diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py
--- a/pypy/module/cpyext/weakrefobject.py
+++ b/pypy/module/cpyext/weakrefobject.py
@@ -1,6 +1,6 @@
 from pypy.module.cpyext.api import cpython_api
 from pypy.module.cpyext.pyobject import PyObject, borrow_from
-from pypy.module._weakref.interp__weakref import W_Weakref
+from pypy.module._weakref.interp__weakref import W_Weakref, proxy
 
 @cpython_api([PyObject, PyObject], PyObject)
 def PyWeakref_NewRef(space, w_obj, w_callback):
@@ -16,6 +16,20 @@
     w_weakref = space.gettypeobject(W_Weakref.typedef)
     return space.call_function(w_weakref, w_obj, w_callback)
 
+ at cpython_api([PyObject, PyObject], PyObject)
+def PyWeakref_NewProxy(space, w_obj, w_callback):
+    """Return a weak reference proxy object for the object *ob*.  This will
+    alwas return a new reference, but is not guaranteed to create a new
+    object; an existing proxy object may be returned.  The second parameter,
+    *callback*, can be a callable object that receives notification when *ob*
+    is garbage collected; it should accept a single parameter, which will be
+    the weak reference object itself. *callback* may also be ``None`` or
+    *NULL*.  If *ob* is not a weakly-referencable object, or if *callback* is
+    not callable, ``None``, or *NULL*, this will return *NULL* and raise
+    :exc:`TypeError`.
+    """
+    return proxy(space, w_obj, w_callback)
+
 @cpython_api([PyObject], PyObject)
 def PyWeakref_GetObject(space, w_ref):
     """Return the referenced object from a weak reference.  If the referent is
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -201,6 +201,9 @@
     def descr_get_shape(self, space):
         return space.newtuple([self.descr_len(space)])
 
+    def descr_get_size(self, space):
+        return space.wrap(self.find_size())
+
     def descr_copy(self, space):
         return space.call_function(space.gettypefor(BaseArray), self, self.find_dtype())
 
@@ -607,6 +610,7 @@
 
     dtype = GetSetProperty(BaseArray.descr_get_dtype),
     shape = GetSetProperty(BaseArray.descr_get_shape),
+    size = GetSetProperty(BaseArray.descr_get_size),
 
     mean = interp2app(BaseArray.descr_mean),
     sum = interp2app(BaseArray.descr_sum),
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -17,6 +17,14 @@
         a[13] = 5.3
         assert a[13] == 5.3
 
+    def test_size(self):
+        from numpy import array
+        # XXX fixed on multidim branch
+        #assert array(3).size == 1
+        a = array([1, 2, 3])
+        assert a.size == 3
+        assert (a + a).size == 3
+
     def test_empty(self):
         """
         Test that empty() works.


More information about the pypy-commit mailing list