Commits

Manuel Jacob committed c8c7be2 Merge

hg merge default

  • Participants
  • Parent commits 705202f, 6cbefce
  • Branches refactor-str-types

Comments (0)

Files changed (14)

pypy/interpreter/astcompiler/codegen.py

             flags |= consts.CO_NESTED
         if scope.is_generator:
             flags |= consts.CO_GENERATOR
+        if scope.has_yield_inside_try:
+            flags |= consts.CO_YIELD_INSIDE_TRY
         if scope.has_variable_arg:
             flags |= consts.CO_VARARGS
         if scope.has_keywords_arg:

pypy/interpreter/astcompiler/consts.py

 CO_FUTURE_UNICODE_LITERALS = 0x20000
 #pypy specific:
 CO_KILL_DOCSTRING = 0x100000
+CO_YIELD_INSIDE_TRY = 0x200000
 
 PyCF_SOURCE_IS_UTF8 = 0x0100
 PyCF_DONT_IMPLY_DEDENT = 0x0200

pypy/interpreter/astcompiler/symtable.py

         self.child_has_free = False
         self.nested = False
         self.doc_removable = False
+        self._in_try_body_depth = 0
 
     def lookup(self, name):
         """Find the scope of identifier 'name'."""
             self.varnames.append(mangled)
         return mangled
 
+    def note_try_start(self, try_node):
+        """Called when a try is found, before visiting the body."""
+        self._in_try_body_depth += 1
+
+    def note_try_end(self, try_node):
+        """Called after visiting a try body."""
+        self._in_try_body_depth -= 1
+
     def note_yield(self, yield_node):
         """Called when a yield is found."""
         raise SyntaxError("'yield' outside function", yield_node.lineno,
         self.has_variable_arg = False
         self.has_keywords_arg = False
         self.is_generator = False
+        self.has_yield_inside_try = False
         self.optimized = True
         self.return_with_value = False
         self.import_star = None
             raise SyntaxError("'return' with argument inside generator",
                               self.ret.lineno, self.ret.col_offset)
         self.is_generator = True
+        if self._in_try_body_depth > 0:
+            self.has_yield_inside_try = True
 
     def note_return(self, ret):
         if ret.value:
         self.scope.new_temporary_name()
         if wih.optional_vars:
             self.scope.new_temporary_name()
-        ast.GenericASTVisitor.visit_With(self, wih)
+        wih.context_expr.walkabout(self)
+        if wih.optional_vars:
+            wih.optional_vars.walkabout(self)
+        self.scope.note_try_start(wih)
+        self.visit_sequence(wih.body)
+        self.scope.note_try_end(wih)
 
     def visit_arguments(self, arguments):
         scope = self.scope
         else:
             role = SYM_ASSIGNED
         self.note_symbol(name.id, role)
+
+    def visit_TryExcept(self, node):
+        self.scope.note_try_start(node)
+        self.visit_sequence(node.body)
+        self.scope.note_try_end(node)
+        self.visit_sequence(node.handlers)
+        self.visit_sequence(node.orelse)
+
+    def visit_TryFinally(self, node):
+        self.scope.note_try_start(node)
+        self.visit_sequence(node.body)
+        self.scope.note_try_end(node)
+        self.visit_sequence(node.finalbody)

pypy/interpreter/astcompiler/test/test_symtable.py

             assert exc.msg == "'return' with argument inside generator"
         scp = self.func_scope("def f():\n    return\n    yield x")
 
+    def test_yield_inside_try(self):
+        scp = self.func_scope("def f(): yield x")
+        assert not scp.has_yield_inside_try
+        scp = self.func_scope("def f():\n  try:\n    yield x\n  except: pass")
+        assert scp.has_yield_inside_try
+        scp = self.func_scope("def f():\n  try:\n    yield x\n  finally: pass")
+        assert scp.has_yield_inside_try
+        scp = self.func_scope("def f():\n    with x: yield y")
+        assert scp.has_yield_inside_try
+
+    def test_yield_outside_try(self):
+        for input in ("try: pass\n    except: pass",
+                      "try: pass\n    except: yield y",
+                      "try: pass\n    finally: pass",
+                      "try: pass\n    finally: yield y",
+                      "with x: pass"):
+            input = "def f():\n    yield y\n    %s\n    yield y" % (input,)
+            assert not self.func_scope(input).has_yield_inside_try
+
     def test_return(self):
         for input in ("class x: return", "return"):
             exc = py.test.raises(SyntaxError, self.func_scope, input).value

pypy/interpreter/generator.py

         code_name = self.pycode.co_name
         return space.wrap(code_name)
 
-    def __del__(self):
-        # Only bother enqueuing self to raise an exception if the frame is
-        # still not finished and finally or except blocks are present.
-        self.clear_all_weakrefs()
-        if self.frame is not None:
-            block = self.frame.lastblock
-            while block is not None:
-                if not isinstance(block, LoopBlock):
-                    self.enqueue_for_destruction(self.space,
-                                                 GeneratorIterator.descr_close,
-                                                 "interrupting generator of ")
-                    break
-                block = block.previous
-
     # Results can be either an RPython list of W_Root, or it can be an
     # app-level W_ListObject, which also has an append() method, that's why we
     # generate 2 versions of the function and 2 jit drivers.
         return unpack_into
     unpack_into = _create_unpack_into()
     unpack_into_w = _create_unpack_into()
+
+
+class GeneratorIteratorWithDel(GeneratorIterator):
+
+    def __del__(self):
+        # Only bother enqueuing self to raise an exception if the frame is
+        # still not finished and finally or except blocks are present.
+        self.clear_all_weakrefs()
+        if self.frame is not None:
+            block = self.frame.lastblock
+            while block is not None:
+                if not isinstance(block, LoopBlock):
+                    self.enqueue_for_destruction(self.space,
+                                                 GeneratorIterator.descr_close,
+                                                 "interrupting generator of ")
+                    break
+                block = block.previous

pypy/interpreter/pycode.py

 from pypy.interpreter.gateway import unwrap_spec
 from pypy.interpreter.astcompiler.consts import (
     CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS, CO_NESTED,
-    CO_GENERATOR, CO_KILL_DOCSTRING)
+    CO_GENERATOR, CO_KILL_DOCSTRING, CO_YIELD_INSIDE_TRY)
 from pypy.tool.stdlib_opcode import opcodedesc, HAVE_ARGUMENT
 from rpython.rlib.rarithmetic import intmask
 from rpython.rlib.objectmodel import compute_hash

pypy/interpreter/pyframe.py

     def run(self):
         """Start this frame's execution."""
         if self.getcode().co_flags & pycode.CO_GENERATOR:
-            from pypy.interpreter.generator import GeneratorIterator
-            return self.space.wrap(GeneratorIterator(self))
+            if pycode.CO_YIELD_INSIDE_TRY:
+                from pypy.interpreter.generator import GeneratorIteratorWithDel
+                return self.space.wrap(GeneratorIteratorWithDel(self))
+            else:
+                from pypy.interpreter.generator import GeneratorIterator
+                return self.space.wrap(GeneratorIterator(self))
         else:
             return self.execute_frame()
 

pypy/module/_pickle_support/maker.py

 from pypy.interpreter.module import Module
 from pypy.interpreter.pyframe import PyFrame
 from pypy.interpreter.pytraceback import PyTraceback
-from pypy.interpreter.generator import GeneratorIterator
+from pypy.interpreter.generator import GeneratorIteratorWithDel
 from rpython.rlib.objectmodel import instantiate
 from pypy.interpreter.gateway import unwrap_spec
 from pypy.objspace.std.iterobject import W_SeqIterObject, W_ReverseSeqIterObject
     return space.wrap(tb)
 
 def generator_new(space):
-    new_generator = instantiate(GeneratorIterator)
+    new_generator = instantiate(GeneratorIteratorWithDel)
     return space.wrap(new_generator)
 
 @unwrap_spec(current=int, remaining=int, step=int)

pypy/objspace/std/listobject.py

                 l[index] = self.unwrap(w_item)
             except IndexError:
                 raise
-            return
-
-        w_list.switch_to_object_strategy()
-        w_list.setitem(index, w_item)
+        else:
+            w_list.switch_to_object_strategy()
+            w_list.setitem(index, w_item)
 
     def setslice(self, w_list, start, step, slicelength, w_other):
         assert slicelength >= 0

pypy/objspace/std/tupleobject.py

             jit.loop_unrolling_heuristic(other, other.length(), UNROLL_CUTOFF))
 
 
+contains_jmp = jit.JitDriver(greens = [], reds = 'auto',
+                             name = 'tuple.contains')
+
 class W_AbstractTupleObject(W_Root):
     __slots__ = ()
 
     descr_gt = _make_tuple_comparison('gt')
     descr_ge = _make_tuple_comparison('ge')
 
-    @jit.look_inside_iff(lambda self, _1, _2: _unroll_condition(self))
     def descr_contains(self, space, w_obj):
+        if _unroll_condition(self):
+            return self._descr_contains_unroll_safe(space, w_obj)
+        else:
+            return self._descr_contains_jmp(space, w_obj)
+
+    @jit.unroll_safe
+    def _descr_contains_unroll_safe(self, space, w_obj):
         for w_item in self.tolist():
             if space.eq_w(w_item, w_obj):
                 return space.w_True
         return space.w_False
 
+    def _descr_contains_jmp(self, space, w_obj):
+        for w_item in self.tolist():
+            contains_jmp.jit_merge_point()
+            if space.eq_w(w_item, w_obj):
+                return space.w_True
+        return space.w_False
+
     def descr_add(self, space, w_other):
         if not isinstance(w_other, W_AbstractTupleObject):
             return space.w_NotImplemented

rpython/jit/metainterp/pyjitpl.py

                 if not box1.same_constant(box2):
                     break
             else:
-                # Found!  Compile it as a loop.
-                # raises in case it works -- which is the common case
                 if self.partial_trace:
                     if  start != self.retracing_from:
                         raise SwitchToBlackhole(Counters.ABORT_BAD_LOOP) # For now
+                # Found!  Compile it as a loop.
+                # raises in case it works -- which is the common case
                 self.compile_loop(original_boxes, live_arg_boxes, start, resumedescr)
                 # creation of the loop was cancelled!
                 self.cancel_count += 1

rpython/rlib/rbigint.py

         # Even if it's not power of two it can still be useful.
         return _muladd1(b, digit)
 
+    # a is not b
+    # use the following identity to reduce the number of operations
+    # a * b = a_0*b_0 + sum_{i=1}^n(a_0*b_i + a_1*b_{i-1}) + a_1*b_n
     z = rbigint([NULLDIGIT] * (size_a + size_b), 1)
-    # gradeschool long mult
     i = UDIGIT_TYPE(0)
-    while i < size_a:
-        carry = 0
-        f = a.widedigit(i)
+    size_a1 = UDIGIT_TYPE(size_a - 1)
+    size_b1 = UDIGIT_TYPE(size_b - 1)
+    while i < size_a1:
+        f0 = a.widedigit(i)
+        f1 = a.widedigit(i + 1)
         pz = i
+        carry = z.widedigit(pz) + b.widedigit(0) * f0
+        z.setdigit(pz, carry)
+        pz += 1
+        carry >>= SHIFT
+        j = UDIGIT_TYPE(0)
+        while j < size_b1:
+            # this operation does not overflow using 
+            # SHIFT = (LONG_BIT // 2) - 1 = B - 1; in fact before it
+            # carry and z.widedigit(pz) are less than 2**(B - 1);
+            # b.widedigit(j + 1) * f0 < (2**(B-1) - 1)**2; so
+            # carry + z.widedigit(pz) + b.widedigit(j + 1) * f0 +
+            # b.widedigit(j) * f1 < 2**(2*B - 1) - 2**B < 2**LONG)BIT - 1
+            carry += z.widedigit(pz) + b.widedigit(j + 1) * f0 + \
+                     b.widedigit(j) * f1
+            z.setdigit(pz, carry)
+            pz += 1
+            carry >>= SHIFT
+            j += 1
+        # carry < 2**(B + 1) - 2
+        carry += z.widedigit(pz) + b.widedigit(size_b1) * f1
+        z.setdigit(pz, carry)
+        pz += 1
+        carry >>= SHIFT
+        # carry < 4
+        if carry:
+            z.setdigit(pz, carry)
+        assert (carry >> SHIFT) == 0
+        i += 2
+    if size_a & 1:
+        pz = size_a1
+        f = a.widedigit(pz)
         pb = 0
+        carry = _widen_digit(0)
         while pb < size_b:
             carry += z.widedigit(pz) + b.widedigit(pb) * f
             pb += 1
             z.setdigit(pz, carry)
             pz += 1
             carry >>= SHIFT
-            assert carry <= MASK
         if carry:
-            assert pz >= 0
             z.setdigit(pz, z.widedigit(pz) + carry)
-        assert (carry >> SHIFT) == 0
-        i += 1
     z._normalize()
     return z
 

rpython/translator/driver.py

     if sys.platform == 'win32':
         name = name.new(ext='exe')
     return name
+
+if os.name == 'posix':
+    def shutil_copy(src, dst):
+        # this version handles the case where 'dst' is an executable
+        # currently being executed
+        shutil.copy(src, dst + '~')
+        os.rename(dst + '~', dst)
+else:
+    shutil_copy = shutil.copy

rpython/translator/test/test_driver.py

 import py
 import os
-from rpython.translator.driver import TranslationDriver
+from rpython.translator.driver import TranslationDriver, shutil_copy
 from rpython.tool.udir import udir 
 
 def test_ctr():
     assert dst_name.new(ext='dll').read() == 'dll'
     assert dst_name.new(purebasename='python27',ext='lib').read() == 'lib'
 
-
+def test_shutil_copy():
+    a = udir.join('file_a')
+    b = udir.join('file_a')
+    a.write('hello')
+    shutil_copy(str(a), str(b))
+    assert b.read() == 'hello'