Author: Manuel Jacob
Branch: refactor-str-types
Changeset: r68750:c8c7be26e72f
Date: 2014-01-17 22:47 +0100
http://bitbucket.org/pypy/pypy/changeset/c8c7be26e72f/
Log: hg merge default
diff --git a/pypy/interpreter/astcompiler/codegen.py
b/pypy/interpreter/astcompiler/codegen.py
--- a/pypy/interpreter/astcompiler/codegen.py
+++ b/pypy/interpreter/astcompiler/codegen.py
@@ -1234,6 +1234,8 @@
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:
diff --git a/pypy/interpreter/astcompiler/consts.py
b/pypy/interpreter/astcompiler/consts.py
--- a/pypy/interpreter/astcompiler/consts.py
+++ b/pypy/interpreter/astcompiler/consts.py
@@ -17,6 +17,7 @@
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
diff --git a/pypy/interpreter/astcompiler/symtable.py
b/pypy/interpreter/astcompiler/symtable.py
--- a/pypy/interpreter/astcompiler/symtable.py
+++ b/pypy/interpreter/astcompiler/symtable.py
@@ -43,6 +43,7 @@
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'."""
@@ -75,6 +76,14 @@
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,
@@ -210,6 +219,7 @@
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
@@ -220,6 +230,8 @@
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:
@@ -463,7 +475,12 @@
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
@@ -505,3 +522,16 @@
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)
diff --git a/pypy/interpreter/astcompiler/test/test_symtable.py
b/pypy/interpreter/astcompiler/test/test_symtable.py
--- a/pypy/interpreter/astcompiler/test/test_symtable.py
+++ b/pypy/interpreter/astcompiler/test/test_symtable.py
@@ -346,6 +346,25 @@
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
diff --git a/pypy/interpreter/generator.py b/pypy/interpreter/generator.py
--- a/pypy/interpreter/generator.py
+++ b/pypy/interpreter/generator.py
@@ -155,20 +155,6 @@
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.
@@ -211,3 +197,20 @@
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
diff --git a/pypy/interpreter/pycode.py b/pypy/interpreter/pycode.py
--- a/pypy/interpreter/pycode.py
+++ b/pypy/interpreter/pycode.py
@@ -12,7 +12,7 @@
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
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -167,8 +167,12 @@
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()
diff --git a/pypy/module/_pickle_support/maker.py
b/pypy/module/_pickle_support/maker.py
--- a/pypy/module/_pickle_support/maker.py
+++ b/pypy/module/_pickle_support/maker.py
@@ -5,7 +5,7 @@
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
@@ -60,7 +60,7 @@
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)
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -1337,10 +1337,9 @@
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
diff --git a/pypy/objspace/std/tupleobject.py b/pypy/objspace/std/tupleobject.py
--- a/pypy/objspace/std/tupleobject.py
+++ b/pypy/objspace/std/tupleobject.py
@@ -27,6 +27,9 @@
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__ = ()
@@ -119,13 +122,26 @@
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
diff --git a/rpython/jit/metainterp/pyjitpl.py
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -2102,11 +2102,11 @@
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
diff --git a/rpython/rlib/rbigint.py b/rpython/rlib/rbigint.py
--- a/rpython/rlib/rbigint.py
+++ b/rpython/rlib/rbigint.py
@@ -1290,26 +1290,58 @@
# 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
diff --git a/rpython/translator/driver.py b/rpython/translator/driver.py
--- a/rpython/translator/driver.py
+++ b/rpython/translator/driver.py
@@ -591,3 +591,12 @@
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
diff --git a/rpython/translator/test/test_driver.py
b/rpython/translator/test/test_driver.py
--- a/rpython/translator/test/test_driver.py
+++ b/rpython/translator/test/test_driver.py
@@ -1,6 +1,6 @@
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():
@@ -74,4 +74,9 @@
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'
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit