Author: Amaury Forgeot d'Arc <amaur...@gmail.com>
Branch: py3k
Changeset: r54868:c2293a4badc4
Date: 2012-05-02 01:02 +0200
http://bitbucket.org/pypy/pypy/changeset/c2293a4badc4/

Log:    hg merge default

diff --git a/pypy/doc/cppyy.rst b/pypy/doc/cppyy.rst
--- a/pypy/doc/cppyy.rst
+++ b/pypy/doc/cppyy.rst
@@ -21,6 +21,26 @@
 .. _`llvm`: http://llvm.org/
 
 
+Motivation
+==========
+
+The cppyy module offers two unique features, which result in great
+performance as well as better functionality and cross-language integration
+than would otherwise be possible.
+First, cppyy is written in RPython and therefore open to optimizations by the
+JIT up until the actual point of call into C++.
+This means that there are no conversions necessary between a garbage collected
+and a reference counted environment, as is needed for the use of existing
+extension modules written or generated for CPython.
+It also means that if variables are already unboxed by the JIT, they can be
+passed through directly to C++.
+Second, Reflex (and cling far more so) adds dynamic features to C++, thus
+greatly reducing impedance mismatches between the two languages.
+In fact, Reflex is dynamic enough that you could write the runtime bindings
+generation in python (as opposed to RPython) and this is used to create very
+natural "pythonizations" of the bound code.
+
+
 Installation
 ============
 
@@ -195,10 +215,12 @@
     >>>> d = cppyy.gbl.BaseFactory("name", 42, 3.14)
     >>>> type(d)
     <class '__main__.Derived'>
-    >>>> d.m_i
-    42
-    >>>> d.m_d
-    3.14
+    >>>> isinstance(d, cppyy.gbl.Base1)
+    True
+    >>>> isinstance(d, cppyy.gbl.Base2)
+    True
+    >>>> d.m_i, d.m_d
+    (42, 3.14)
     >>>> d.m_name == "name"
     True
     >>>>
@@ -295,6 +317,9 @@
   To select a specific virtual method, do like with normal python classes
   that override methods: select it from the class that you need, rather than
   calling the method on the instance.
+  To select a specific overload, use the __dispatch__ special function, which
+  takes the name of the desired method and its signature (which can be
+  obtained from the doc string) as arguments.
 
 * **namespaces**: Are represented as python classes.
   Namespaces are more open-ended than classes, so sometimes initial access may
diff --git a/pypy/doc/extending.rst b/pypy/doc/extending.rst
--- a/pypy/doc/extending.rst
+++ b/pypy/doc/extending.rst
@@ -116,13 +116,21 @@
 Reflex
 ======
 
-This method is only experimental for now, and is being exercised on a branch,
-`reflex-support`_, so you will have to build PyPy yourself.
+This method is still experimental and is being exercised on a branch,
+`reflex-support`_, which adds the `cppyy`_ module.
 The method works by using the `Reflex package`_ to provide reflection
 information of the C++ code, which is then used to automatically generate
-bindings at runtime, which can then be used from python.
+bindings at runtime.
+From a python standpoint, there is no difference between generating bindings
+at runtime, or having them "statically" generated and available in scripts
+or compiled into extension modules: python classes and functions are always
+runtime structures, created when a script or module loads.
+However, if the backend itself is capable of dynamic behavior, it is a much
+better functional match to python, allowing tighter integration and more
+natural language mappings.
 Full details are `available here`_.
 
+.. _`cppyy`: cppyy.html
 .. _`reflex-support`: cppyy.html
 .. _`Reflex package`: http://root.cern.ch/drupal/content/reflex
 .. _`available here`: cppyy.html
@@ -130,16 +138,33 @@
 Pros
 ----
 
-If it works, it is mostly automatic, and hence easy in use.
-The bindings can make use of direct pointers, in which case the calls are
-very fast.
+The cppyy module is written in RPython, which makes it possible to keep the
+code execution visible to the JIT all the way to the actual point of call into
+C++, thus allowing for a very fast interface.
+Reflex is currently in use in large software environments in High Energy
+Physics (HEP), across many different projects and packages, and its use can be
+virtually completely automated in a production environment.
+One of its uses in HEP is in providing language bindings for CPython.
+Thus, it is possible to use Reflex to have bound code work on both CPython and
+on PyPy.
+In the medium-term, Reflex will be replaced by `cling`_, which is based on
+`llvm`_.
+This will affect the backend only; the python-side interface is expected to
+remain the same, except that cling adds a lot of dynamic behavior to C++,
+enabling further language integration.
+
+.. _`cling`: http://root.cern.ch/drupal/content/cling
+.. _`llvm`: http://llvm.org/
 
 Cons
 ----
 
-C++ is a large language, and these bindings are not yet feature-complete.
-Although missing features should do no harm if you don't use them, if you do
-need a particular feature, it may be necessary to work around it in python
-or with a C++ helper function.
+C++ is a large language, and cppyy is not yet feature-complete.
+Still, the experience gained in developing the equivalent bindings for CPython
+means that adding missing features is a simple matter of engineering, not a
+question of research.
+The module is written so that currently missing features should do no harm if
+you don't use them, if you do need a particular feature, it may be necessary
+to work around it in python or with a C++ helper function.
 Although Reflex works on various platforms, the bindings with PyPy have only
 been tested on Linux.
diff --git a/pypy/jit/backend/llsupport/test/test_asmmemmgr.py 
b/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
--- a/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
+++ b/pypy/jit/backend/llsupport/test/test_asmmemmgr.py
@@ -217,7 +217,8 @@
     encoded = ''.join(writtencode).encode('hex').upper()
     ataddr = '@%x' % addr
     assert log == [('test-logname-section',
-                    [('debug_print', 'CODE_DUMP', ataddr, '+0 ', encoded)])]
+                    [('debug_print', 'SYS_EXECUTABLE', '??'),
+                     ('debug_print', 'CODE_DUMP', ataddr, '+0 ', encoded)])]
     
     lltype.free(p, flavor='raw')
 
diff --git a/pypy/jit/metainterp/jitexc.py b/pypy/jit/metainterp/jitexc.py
--- a/pypy/jit/metainterp/jitexc.py
+++ b/pypy/jit/metainterp/jitexc.py
@@ -12,7 +12,6 @@
     """
     _go_through_llinterp_uncaught_ = True     # ugh
 
-
 def _get_standard_error(rtyper, Class):
     exdata = rtyper.getexceptiondata()
     clsdef = rtyper.annotator.bookkeeper.getuniqueclassdef(Class)
diff --git a/pypy/jit/metainterp/optimize.py b/pypy/jit/metainterp/optimize.py
--- a/pypy/jit/metainterp/optimize.py
+++ b/pypy/jit/metainterp/optimize.py
@@ -5,3 +5,9 @@
     """Raised when the optimize*.py detect that the loop that
     we are trying to build cannot possibly make sense as a
     long-running loop (e.g. it cannot run 2 complete iterations)."""
+
+    def __init__(self, msg='?'):
+        debug_start("jit-abort")
+        debug_print(msg)
+        debug_stop("jit-abort")
+        self.msg = msg
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
@@ -49,8 +49,9 @@
                 optimizations.append(OptFfiCall())
 
     if ('rewrite' not in enable_opts or 'virtualize' not in enable_opts
-        or 'heap' not in enable_opts or 'unroll' not in enable_opts):
-        optimizations.append(OptSimplify())
+        or 'heap' not in enable_opts or 'unroll' not in enable_opts
+        or 'pure' not in enable_opts):
+        optimizations.append(OptSimplify(unroll))
 
     return optimizations, unroll
 
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
@@ -257,8 +257,8 @@
             opnum == rop.COPYSTRCONTENT or       # no effect on GC struct/array
             opnum == rop.COPYUNICODECONTENT):    # no effect on GC struct/array
             return
-        assert opnum != rop.CALL_PURE
         if (opnum == rop.CALL or
+            opnum == rop.CALL_PURE or
             opnum == rop.CALL_MAY_FORCE or
             opnum == rop.CALL_RELEASE_GIL or
             opnum == rop.CALL_ASSEMBLER):
@@ -481,7 +481,7 @@
         # already between the tracing and now.  In this case, we are
         # simply ignoring the QUASIIMMUT_FIELD hint and compiling it
         # as a regular getfield.
-        if not qmutdescr.is_still_valid():
+        if not qmutdescr.is_still_valid_for(structvalue.get_key_box()):
             self._remove_guard_not_invalidated = True
             return
         # record as an out-of-line guard
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
@@ -191,10 +191,13 @@
         # GUARD_OVERFLOW, then the loop is invalid.
         lastop = self.last_emitted_operation
         if lastop is None:
-            raise InvalidLoop
+            raise InvalidLoop('An INT_xxx_OVF was proven not to overflow but' +
+                              'guarded with GUARD_OVERFLOW')
         opnum = lastop.getopnum()
         if opnum not in (rop.INT_ADD_OVF, rop.INT_SUB_OVF, rop.INT_MUL_OVF):
-            raise InvalidLoop
+            raise InvalidLoop('An INT_xxx_OVF was proven not to overflow but' +
+                              'guarded with GUARD_OVERFLOW')
+                             
         self.emit_operation(op)
 
     def optimize_INT_ADD_OVF(self, op):
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
@@ -525,6 +525,7 @@
 
     @specialize.argtype(0)
     def _emit_operation(self, op):
+        assert op.getopnum() != rop.CALL_PURE
         for i in range(op.numargs()):
             arg = op.getarg(i)
             try:
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
@@ -208,7 +208,8 @@
             box = value.box
             assert isinstance(box, Const)
             if not box.same_constant(constbox):
-                raise InvalidLoop
+                raise InvalidLoop('A GURAD_{VALUE,TRUE,FALSE} was proven to' +
+                                  'always fail')
             return
         if emit_operation:
             self.emit_operation(op)
@@ -220,7 +221,7 @@
         if value.is_null():
             return
         elif value.is_nonnull():
-            raise InvalidLoop
+            raise InvalidLoop('A GUARD_ISNULL was proven to always fail')
         self.emit_operation(op)
         value.make_constant(self.optimizer.cpu.ts.CONST_NULL)
 
@@ -229,7 +230,7 @@
         if value.is_nonnull():
             return
         elif value.is_null():
-            raise InvalidLoop
+            raise InvalidLoop('A GUARD_NONNULL was proven to always fail')
         self.emit_operation(op)
         value.make_nonnull(op)
 
@@ -278,7 +279,7 @@
         if realclassbox is not None:
             if realclassbox.same_constant(expectedclassbox):
                 return
-            raise InvalidLoop
+            raise InvalidLoop('A GUARD_CLASS was proven to always fail')
         if value.last_guard:
             # there already has been a guard_nonnull or guard_class or
             # guard_nonnull_class on this value.
@@ -301,7 +302,8 @@
     def optimize_GUARD_NONNULL_CLASS(self, op):
         value = self.getvalue(op.getarg(0))
         if value.is_null():
-            raise InvalidLoop
+            raise InvalidLoop('A GUARD_NONNULL_CLASS was proven to always ' +
+                              'fail')
         self.optimize_GUARD_CLASS(op)
 
     def optimize_CALL_LOOPINVARIANT(self, op):
diff --git a/pypy/jit/metainterp/optimizeopt/simplify.py 
b/pypy/jit/metainterp/optimizeopt/simplify.py
--- a/pypy/jit/metainterp/optimizeopt/simplify.py
+++ b/pypy/jit/metainterp/optimizeopt/simplify.py
@@ -4,8 +4,9 @@
 from pypy.jit.metainterp.history import TargetToken, JitCellToken
 
 class OptSimplify(Optimization):
-    def __init__(self):
+    def __init__(self, unroll):
         self.last_label_descr = None
+        self.unroll = unroll
         
     def optimize_CALL_PURE(self, op):
         args = op.getarglist()
@@ -35,24 +36,26 @@
         pass
 
     def optimize_LABEL(self, op):
-        descr = op.getdescr()
-        if isinstance(descr, JitCellToken):
-            return self.optimize_JUMP(op.copy_and_change(rop.JUMP))
-        self.last_label_descr = op.getdescr()
+        if not self.unroll:
+            descr = op.getdescr()
+            if isinstance(descr, JitCellToken):
+                return self.optimize_JUMP(op.copy_and_change(rop.JUMP))
+            self.last_label_descr = op.getdescr()
         self.emit_operation(op)
         
     def optimize_JUMP(self, op):
-        descr = op.getdescr()
-        assert isinstance(descr, JitCellToken)
-        if not descr.target_tokens:
-            assert self.last_label_descr is not None
-            target_token = self.last_label_descr
-            assert isinstance(target_token, TargetToken)
-            assert target_token.targeting_jitcell_token is descr
-            op.setdescr(self.last_label_descr)
-        else:
-            assert len(descr.target_tokens) == 1
-            op.setdescr(descr.target_tokens[0])
+        if not self.unroll:
+            descr = op.getdescr()
+            assert isinstance(descr, JitCellToken)
+            if not descr.target_tokens:
+                assert self.last_label_descr is not None
+                target_token = self.last_label_descr
+                assert isinstance(target_token, TargetToken)
+                assert target_token.targeting_jitcell_token is descr
+                op.setdescr(self.last_label_descr)
+            else:
+                assert len(descr.target_tokens) == 1
+                op.setdescr(descr.target_tokens[0])
         self.emit_operation(op)
 
 dispatch_opt = make_dispatcher_method(OptSimplify, 'optimize_',
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_disable_optimizations.py 
b/pypy/jit/metainterp/optimizeopt/test/test_disable_optimizations.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/optimizeopt/test/test_disable_optimizations.py
@@ -0,0 +1,46 @@
+from pypy.jit.metainterp.optimizeopt.test.test_optimizeopt import 
OptimizeOptTest
+from pypy.jit.metainterp.optimizeopt.test.test_util import LLtypeMixin
+from pypy.jit.metainterp.resoperation import rop
+
+
+allopts = OptimizeOptTest.enable_opts.split(':')
+for optnum in range(len(allopts)):
+    myopts = allopts[:]
+    del myopts[optnum]
+
+    class TestLLtype(OptimizeOptTest, LLtypeMixin):
+        enable_opts = ':'.join(myopts)
+
+        def optimize_loop(self, ops, expected, expected_preamble=None,
+                          call_pure_results=None, expected_short=None):
+            loop = self.parse(ops)
+            if expected != "crash!":
+                expected = self.parse(expected)
+            if expected_preamble:
+                expected_preamble = self.parse(expected_preamble)
+            if expected_short:
+                expected_short = self.parse(expected_short)
+
+            preamble = self.unroll_and_optimize(loop, call_pure_results)
+
+            for op in preamble.operations + loop.operations:
+                assert op.getopnum() not in (rop.CALL_PURE,
+                                             rop.CALL_LOOPINVARIANT,
+                                             rop.VIRTUAL_REF_FINISH,
+                                             rop.VIRTUAL_REF,
+                                             rop.QUASIIMMUT_FIELD,
+                                             rop.MARK_OPAQUE_PTR,
+                                             rop.RECORD_KNOWN_CLASS)
+
+        def raises(self, e, fn, *args):
+            try:
+                fn(*args)
+            except e:
+                pass
+
+    opt = allopts[optnum]
+    exec "TestNo%sLLtype = TestLLtype" % (opt[0].upper() + opt[1:])
+
+del TestLLtype # No need to run the last set twice
+del TestNoUnrollLLtype # This case is take care of by test_optimizebasic
+        
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
@@ -5090,7 +5090,6 @@
 class TestLLtype(BaseTestOptimizeBasic, LLtypeMixin):
     pass
 
-
 ##class TestOOtype(BaseTestOptimizeBasic, OOtypeMixin):
 
 ##    def test_instanceof(self):
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
@@ -105,6 +105,9 @@
 
         return loop
 
+    def raises(self, e, fn, *args):
+        py.test.raises(e, fn, *args)
+
 class OptimizeOptTest(BaseTestWithUnroll):
 
     def setup_method(self, meth=None):
@@ -2639,7 +2642,7 @@
         p2 = new_with_vtable(ConstClass(node_vtable))
         jump(p2)
         """
-        py.test.raises(InvalidLoop, self.optimize_loop,
+        self.raises(InvalidLoop, self.optimize_loop,
                        ops, ops)
 
     def test_invalid_loop_2(self):
@@ -2651,7 +2654,7 @@
         escape(p2)      # prevent it from staying Virtual
         jump(p2)
         """
-        py.test.raises(InvalidLoop, self.optimize_loop,
+        self.raises(InvalidLoop, self.optimize_loop,
                        ops, ops)
 
     def test_invalid_loop_3(self):
@@ -2665,7 +2668,7 @@
         setfield_gc(p3, p4, descr=nextdescr)
         jump(p3)
         """
-        py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
+        self.raises(InvalidLoop, self.optimize_loop, ops, ops)
 
 
     def test_merge_guard_class_guard_value(self):
@@ -4411,7 +4414,7 @@
         setfield_gc(p1, p3, descr=nextdescr)
         jump(p3)
         """
-        py.test.raises(BogusPureField, self.optimize_loop, ops, "crash!")
+        self.raises(BogusPureField, self.optimize_loop, ops, "crash!")
 
     def test_dont_complains_different_field(self):
         ops = """
@@ -5024,7 +5027,7 @@
         i2 = int_add(i0, 3)
         jump(i2)
         """
-        py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
+        self.raises(InvalidLoop, self.optimize_loop, ops, ops)
 
     def test_bound_ne_const_not(self):
         ops = """
@@ -5074,7 +5077,7 @@
         i3 = int_add(i0, 3)
         jump(i3)
         """
-        py.test.raises(InvalidLoop, self.optimize_loop, ops, ops)
+        self.raises(InvalidLoop, self.optimize_loop, ops, ops)
 
     def test_bound_lshift(self):
         ops = """
@@ -6533,9 +6536,9 @@
     def test_quasi_immut_2(self):
         ops = """
         []
-        quasiimmut_field(ConstPtr(myptr), descr=quasiimmutdescr)
+        quasiimmut_field(ConstPtr(quasiptr), descr=quasiimmutdescr)
         guard_not_invalidated() []
-        i1 = getfield_gc(ConstPtr(myptr), descr=quasifielddescr)
+        i1 = getfield_gc(ConstPtr(quasiptr), descr=quasifielddescr)
         escape(i1)
         jump()
         """
@@ -6585,13 +6588,13 @@
     def test_call_may_force_invalidated_guards_reload(self):
         ops = """
         [i0a, i0b]
-        quasiimmut_field(ConstPtr(myptr), descr=quasiimmutdescr)
+        quasiimmut_field(ConstPtr(quasiptr), descr=quasiimmutdescr)
         guard_not_invalidated() []
-        i1 = getfield_gc(ConstPtr(myptr), descr=quasifielddescr)
+        i1 = getfield_gc(ConstPtr(quasiptr), descr=quasifielddescr)
         call_may_force(i0b, descr=mayforcevirtdescr)
-        quasiimmut_field(ConstPtr(myptr), descr=quasiimmutdescr)
+        quasiimmut_field(ConstPtr(quasiptr), descr=quasiimmutdescr)
         guard_not_invalidated() []
-        i2 = getfield_gc(ConstPtr(myptr), descr=quasifielddescr)
+        i2 = getfield_gc(ConstPtr(quasiptr), descr=quasifielddescr)
         i3 = escape(i1)
         i4 = escape(i2)
         jump(i3, i4)
@@ -7813,6 +7816,52 @@
         """
         self.optimize_loop(ops, expected)
 
+    def test_issue1080_infinitie_loop_virtual(self):
+        ops = """
+        [p10]
+        p52 = getfield_gc(p10, descr=nextdescr) # inst_storage
+        p54 = getarrayitem_gc(p52, 0, descr=arraydescr)
+        p69 = getfield_gc_pure(p54, descr=otherdescr) # inst_w_function
+
+        quasiimmut_field(p69, descr=quasiimmutdescr)
+        guard_not_invalidated() []
+        p71 = getfield_gc(p69, descr=quasifielddescr) # inst_code
+        guard_value(p71, -4247) []
+
+        p106 = new_with_vtable(ConstClass(node_vtable))
+        p108 = new_array(3, descr=arraydescr)
+        p110 = new_with_vtable(ConstClass(node_vtable))
+        setfield_gc(p110, ConstPtr(myptr2), descr=otherdescr) # inst_w_function
+        setarrayitem_gc(p108, 0, p110, descr=arraydescr)
+        setfield_gc(p106, p108, descr=nextdescr) # inst_storage
+        jump(p106)
+        """
+        expected = """
+        []
+        p72 = getfield_gc(ConstPtr(myptr2), descr=quasifielddescr)
+        guard_value(p72, -4247) []
+        jump()
+        """
+        self.optimize_loop(ops, expected)
+        
+
+    def test_issue1080_infinitie_loop_simple(self):
+        ops = """
+        [p69]
+        quasiimmut_field(p69, descr=quasiimmutdescr)
+        guard_not_invalidated() []
+        p71 = getfield_gc(p69, descr=quasifielddescr) # inst_code
+        guard_value(p71, -4247) []
+        jump(ConstPtr(myptr))
+        """
+        expected = """
+        []
+        p72 = getfield_gc(ConstPtr(myptr), descr=quasifielddescr)
+        guard_value(p72, -4247) []
+        jump()
+        """
+        self.optimize_loop(ops, expected)
+
 class TestLLtype(OptimizeOptTest, LLtypeMixin):
     pass
 
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py 
b/pypy/jit/metainterp/optimizeopt/test/test_util.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_util.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py
@@ -122,6 +122,7 @@
     quasi.inst_field = -4247
     quasifielddescr = cpu.fielddescrof(QUASI, 'inst_field')
     quasibox = BoxPtr(lltype.cast_opaque_ptr(llmemory.GCREF, quasi))
+    quasiptr = quasibox.value
     quasiimmutdescr = QuasiImmutDescr(cpu, quasibox,
                                       quasifielddescr,
                                       cpu.fielddescrof(QUASI, 'mutate_field'))
diff --git a/pypy/jit/metainterp/optimizeopt/unroll.py 
b/pypy/jit/metainterp/optimizeopt/unroll.py
--- a/pypy/jit/metainterp/optimizeopt/unroll.py
+++ b/pypy/jit/metainterp/optimizeopt/unroll.py
@@ -315,7 +315,10 @@
         try:
             jumpargs = virtual_state.make_inputargs(values, self.optimizer)
         except BadVirtualState:
-            raise InvalidLoop
+            raise InvalidLoop('The state of the optimizer at the end of ' +
+                              'peeled loop is inconsistent with the ' +
+                              'VirtualState at the begining of the peeled ' +
+                              'loop')
         jumpop.initarglist(jumpargs)
 
         # Inline the short preamble at the end of the loop
@@ -325,7 +328,11 @@
         for i in range(len(short_inputargs)):
             if short_inputargs[i] in args:
                 if args[short_inputargs[i]] != jmp_to_short_args[i]:
-                    raise InvalidLoop
+                    raise InvalidLoop('The short preamble wants the ' +
+                                      'same box passed to multiple of its ' +
+                                      'inputargs, but the jump at the ' +
+                                      'end of this bridge does not do that.')
+                                      
             args[short_inputargs[i]] = jmp_to_short_args[i]
         self.short_inliner = Inliner(short_inputargs, jmp_to_short_args)
         for op in self.short[1:]:
@@ -378,7 +385,10 @@
             #final_virtual_state.debug_print("Bad virtual state at end of 
loop, ",
             #                                bad)
             #debug_stop('jit-log-virtualstate')
-            raise InvalidLoop
+            raise InvalidLoop('The virtual state at the end of the peeled ' +
+                              'loop is not compatible with the virtual ' +
+                              'state at the start of the loop which makes ' +
+                              'it impossible to close the loop')
             
         #debug_stop('jit-log-virtualstate')
 
@@ -526,8 +536,8 @@
         args = jumpop.getarglist()
         modifier = VirtualStateAdder(self.optimizer)
         virtual_state = modifier.get_virtual_state(args)
-        #debug_start('jit-log-virtualstate')
-        #virtual_state.debug_print("Looking for ")
+        debug_start('jit-log-virtualstate')
+        virtual_state.debug_print("Looking for ")
 
         for target in cell_token.target_tokens:
             if not target.virtual_state:
@@ -536,10 +546,10 @@
             extra_guards = []
 
             bad = {}
-            #debugmsg = 'Did not match '
+            debugmsg = 'Did not match '
             if target.virtual_state.generalization_of(virtual_state, bad):
                 ok = True
-                #debugmsg = 'Matched '
+                debugmsg = 'Matched '
             else:
                 try:
                     cpu = self.optimizer.cpu
@@ -548,13 +558,13 @@
                                                          extra_guards)
 
                     ok = True
-                    #debugmsg = 'Guarded to match '
+                    debugmsg = 'Guarded to match '
                 except InvalidLoop:
                     pass
-            #target.virtual_state.debug_print(debugmsg, bad)
+            target.virtual_state.debug_print(debugmsg, bad)
 
             if ok:
-                #debug_stop('jit-log-virtualstate')
+                debug_stop('jit-log-virtualstate')
 
                 values = [self.getvalue(arg)
                           for arg in jumpop.getarglist()]
@@ -581,7 +591,7 @@
                     jumpop.setdescr(cell_token.target_tokens[0])
                     self.optimizer.send_extra_operation(jumpop)
                 return True
-        #debug_stop('jit-log-virtualstate')
+        debug_stop('jit-log-virtualstate')
         return False
 
 class ValueImporter(object):
diff --git a/pypy/jit/metainterp/optimizeopt/virtualstate.py 
b/pypy/jit/metainterp/optimizeopt/virtualstate.py
--- a/pypy/jit/metainterp/optimizeopt/virtualstate.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualstate.py
@@ -27,11 +27,15 @@
         if self.generalization_of(other, renum, {}):
             return
         if renum[self.position] != other.position:
-            raise InvalidLoop
+            raise InvalidLoop('The numbering of the virtual states does not ' +
+                              'match. This means that two virtual fields ' +
+                              'have been set to the same Box in one of the ' +
+                              'virtual states but not in the other.')
         self._generate_guards(other, box, cpu, extra_guards)
 
     def _generate_guards(self, other, box, cpu, extra_guards):
-        raise InvalidLoop
+        raise InvalidLoop('Generating guards for making the VirtualStates ' +
+                          'at hand match have not been implemented')
 
     def enum_forced_boxes(self, boxes, value, optimizer):
         raise NotImplementedError
@@ -346,10 +350,12 @@
 
     def _generate_guards(self, other, box, cpu, extra_guards):
         if not isinstance(other, NotVirtualStateInfo):
-            raise InvalidLoop
+            raise InvalidLoop('The VirtualStates does not match as a ' +
+                              'virtual appears where a pointer is needed ' +
+                              'and it is too late to force it.')
 
         if self.lenbound or other.lenbound:
-            raise InvalidLoop
+            raise InvalidLoop('The array length bounds does not match.')
 
         if self.level == LEVEL_KNOWNCLASS and \
            box.nonnull() and \
@@ -400,7 +406,8 @@
             return
 
         # Remaining cases are probably not interesting
-        raise InvalidLoop
+        raise InvalidLoop('Generating guards for making the VirtualStates ' +
+                          'at hand match have not been implemented')
         if self.level == LEVEL_CONSTANT:
             import pdb; pdb.set_trace()
             raise NotImplementedError
diff --git a/pypy/jit/metainterp/quasiimmut.py 
b/pypy/jit/metainterp/quasiimmut.py
--- a/pypy/jit/metainterp/quasiimmut.py
+++ b/pypy/jit/metainterp/quasiimmut.py
@@ -120,8 +120,10 @@
                                     self.fielddescr, self.structbox)
         return fieldbox.constbox()
 
-    def is_still_valid(self):
+    def is_still_valid_for(self, structconst):
         assert self.structbox is not None
+        if not self.structbox.constbox().same_constant(structconst):
+            return False
         cpu = self.cpu
         gcref = self.structbox.getref_base()
         qmut = get_current_qmut_instance(cpu, gcref, self.mutatefielddescr)
diff --git a/pypy/jit/metainterp/test/test_quasiimmut.py 
b/pypy/jit/metainterp/test/test_quasiimmut.py
--- a/pypy/jit/metainterp/test/test_quasiimmut.py
+++ b/pypy/jit/metainterp/test/test_quasiimmut.py
@@ -8,7 +8,7 @@
 from pypy.jit.metainterp.quasiimmut import get_current_qmut_instance
 from pypy.jit.metainterp.test.support import LLJitMixin
 from pypy.jit.codewriter.policy import StopAtXPolicy
-from pypy.rlib.jit import JitDriver, dont_look_inside, unroll_safe
+from pypy.rlib.jit import JitDriver, dont_look_inside, unroll_safe, promote
 
 
 def test_get_current_qmut_instance():
@@ -506,6 +506,27 @@
             "guard_not_invalidated": 2
         })
 
+    def test_issue1080(self):
+        myjitdriver = JitDriver(greens=[], reds=["n", "sa", "a"])
+        class Foo(object):
+            _immutable_fields_ = ["x?"]
+            def __init__(self, x):
+                self.x = x
+        one, two = Foo(1), Foo(2)
+        def main(n):
+            sa = 0
+            a = one
+            while n:
+                myjitdriver.jit_merge_point(n=n, sa=sa, a=a)
+                sa += a.x
+                if a.x == 1:
+                    a = two
+                elif a.x == 2:
+                    a = one                    
+                n -= 1
+            return sa
+        res = self.meta_interp(main, [10])
+        assert res == main(10)
 
 class TestLLtypeGreenFieldsTests(QuasiImmutTests, LLJitMixin):
     pass
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
@@ -420,7 +420,8 @@
     NULL, the return value might be a shared object. Therefore, modification of
     the resulting Unicode object is only allowed when u is NULL."""
     if s:
-        return make_ref(space, PyUnicode_DecodeUTF8(space, s, size, None))
+        return make_ref(space, PyUnicode_DecodeUTF8(
+            space, s, size, lltype.nullptr(rffi.CCHARP.TO)))
     else:
         return rffi.cast(PyObject, new_empty_unicode(space, size))
 
diff --git a/pypy/module/rctime/test/test_rctime.py 
b/pypy/module/rctime/test/test_rctime.py
--- a/pypy/module/rctime/test/test_rctime.py
+++ b/pypy/module/rctime/test/test_rctime.py
@@ -64,6 +64,7 @@
 
     def test_localtime(self):
         import time as rctime
+        import os
         raises(TypeError, rctime.localtime, "foo")
         rctime.localtime()
         rctime.localtime(None)
@@ -75,6 +76,10 @@
         assert 0 <= (t1 - t0) < 1.2
         t = rctime.time()
         assert rctime.localtime(t) == rctime.localtime(t)
+        if os.name == 'nt':
+            raises(ValueError, rctime.localtime, -1)
+        else:
+            rctime.localtime(-1)
 
     def test_mktime(self):
         import time as rctime
@@ -108,8 +113,8 @@
         assert int(rctime.mktime(rctime.gmtime(t))) - rctime.timezone == int(t)
         ltime = rctime.localtime()
         assert rctime.mktime(tuple(ltime)) == rctime.mktime(ltime)
-
-        assert rctime.mktime(rctime.localtime(-1)) == -1
+        if os.name != 'nt':
+            assert rctime.mktime(rctime.localtime(-1)) == -1
 
     def test_asctime(self):
         import time as rctime
diff --git a/pypy/module/select/__init__.py b/pypy/module/select/__init__.py
--- a/pypy/module/select/__init__.py
+++ b/pypy/module/select/__init__.py
@@ -2,6 +2,7 @@
 from pypy.interpreter.mixedmodule import MixedModule
 
 import sys
+import os
 
 
 class Module(MixedModule):
@@ -9,11 +10,13 @@
     }
 
     interpleveldefs = {
-        'poll'  : 'interp_select.poll',
         'select': 'interp_select.select',
         'error' : 'space.fromcache(interp_select.Cache).w_error'
     }
 
+    if os.name =='posix':
+        interpleveldefs['poll'] = 'interp_select.poll'
+
     if sys.platform.startswith('linux'):
         interpleveldefs['epoll'] = 'interp_epoll.W_Epoll'
         from pypy.module.select.interp_epoll import cconfig, public_symbols
diff --git a/pypy/module/select/test/test_select.py 
b/pypy/module/select/test/test_select.py
--- a/pypy/module/select/test/test_select.py
+++ b/pypy/module/select/test/test_select.py
@@ -214,6 +214,8 @@
 
     def test_poll(self):
         import select
+        if not hasattr(select, 'poll'):
+            skip("no select.poll() on this platform")
         readend, writeend = self.getpair()
         try:
             class A(object):
diff --git a/pypy/rlib/debug.py b/pypy/rlib/debug.py
--- a/pypy/rlib/debug.py
+++ b/pypy/rlib/debug.py
@@ -1,10 +1,12 @@
 import sys, time
 from pypy.rpython.extregistry import ExtRegistryEntry
+from pypy.rlib.objectmodel import we_are_translated
 from pypy.rlib.rarithmetic import is_valid_int
 
 
 def ll_assert(x, msg):
     """After translation to C, this becomes an RPyAssert."""
+    assert type(x) is bool, "bad type! got %r" % (type(x),)
     assert x, msg
 
 class Entry(ExtRegistryEntry):
@@ -21,8 +23,13 @@
         hop.exception_cannot_occur()
         hop.genop('debug_assert', vlist)
 
+class FatalError(Exception):
+    pass
+
 def fatalerror(msg):
     # print the RPython traceback and abort with a fatal error
+    if not we_are_translated():
+        raise FatalError(msg)
     from pypy.rpython.lltypesystem import lltype
     from pypy.rpython.lltypesystem.lloperation import llop
     llop.debug_print_traceback(lltype.Void)
@@ -33,6 +40,8 @@
 
 def fatalerror_notb(msg):
     # a variant of fatalerror() that doesn't print the RPython traceback
+    if not we_are_translated():
+        raise FatalError(msg)
     from pypy.rpython.lltypesystem import lltype
     from pypy.rpython.lltypesystem.lloperation import llop
     llop.debug_fatalerror(lltype.Void, msg)
diff --git a/pypy/rpython/memory/gc/minimark.py 
b/pypy/rpython/memory/gc/minimark.py
--- a/pypy/rpython/memory/gc/minimark.py
+++ b/pypy/rpython/memory/gc/minimark.py
@@ -916,7 +916,7 @@
         ll_assert(not self.is_in_nursery(obj),
                   "object in nursery after collection")
         # similarily, all objects should have this flag:
-        ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS,
+        ll_assert(self.header(obj).tid & GCFLAG_TRACK_YOUNG_PTRS != 0,
                   "missing GCFLAG_TRACK_YOUNG_PTRS")
         # the GCFLAG_VISITED should not be set between collections
         ll_assert(self.header(obj).tid & GCFLAG_VISITED == 0,
diff --git a/pypy/rpython/memory/gc/semispace.py 
b/pypy/rpython/memory/gc/semispace.py
--- a/pypy/rpython/memory/gc/semispace.py
+++ b/pypy/rpython/memory/gc/semispace.py
@@ -640,7 +640,7 @@
         between collections."""
         tid = self.header(obj).tid
         if tid & GCFLAG_EXTERNAL:
-            ll_assert(tid & GCFLAG_FORWARDED, "bug: external+!forwarded")
+            ll_assert(tid & GCFLAG_FORWARDED != 0, "bug: external+!forwarded")
             ll_assert(not (self.tospace <= obj < self.free),
                       "external flag but object inside the semispaces")
         else:
diff --git a/pypy/rpython/memory/gctransform/framework.py 
b/pypy/rpython/memory/gctransform/framework.py
--- a/pypy/rpython/memory/gctransform/framework.py
+++ b/pypy/rpython/memory/gctransform/framework.py
@@ -8,7 +8,6 @@
 from pypy.rpython.memory.gcheader import GCHeaderBuilder
 from pypy.rlib.rarithmetic import ovfcheck
 from pypy.rlib import rgc
-from pypy.rlib.debug import ll_assert
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.translator.backendopt import graphanalyze
 from pypy.translator.backendopt.support import var_needsgc
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to