Author: Philip Jenvey <pjen...@underboss.org> Branch: py3k Changeset: r68867:6ebf49c04a51 Date: 2014-01-21 11:42 -0800 http://bitbucket.org/pypy/pypy/changeset/6ebf49c04a51/
Log: merge default (6cbefcec4ceb) diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst --- a/pypy/doc/project-ideas.rst +++ b/pypy/doc/project-ideas.rst @@ -74,6 +74,10 @@ The actual details would be rather differen in PyPy, but we would like to have the same optimization implemented. +Or maybe not. We can also play around with the idea of using a single +representation: as a byte string in utf-8. (This idea needs some extra logic +for efficient indexing, like a cache.) + .. _`optimized unicode representation`: http://www.python.org/dev/peps/pep-0393/ Translation Toolchain diff --git a/pypy/goal/getnightly.py b/pypy/goal/getnightly.py --- a/pypy/goal/getnightly.py +++ b/pypy/goal/getnightly.py @@ -26,7 +26,12 @@ if branch == 'default': branch = 'trunk' -filename = 'pypy-c-jit-latest-%s.tar.bz2' % arch +if '--nojit' in sys.argv: + kind = 'nojit' +else: + kind = 'jit' + +filename = 'pypy-c-%s-latest-%s.tar.bz2' % (kind, arch) url = 'http://buildbot.pypy.org/nightly/%s/%s' % (branch, filename) tmp = py.path.local.mkdtemp() mydir = tmp.chdir() 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 @@ -1243,6 +1243,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 @@ -18,6 +18,7 @@ CO_FUTURE_BARRY_AS_BDFL = 0x40000 #pypy specific: CO_KILL_DOCSTRING = 0x100000 +CO_YIELD_INSIDE_TRY = 0x200000 PyCF_MASK = (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION | 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, @@ -223,6 +232,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 @@ -238,6 +248,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: @@ -489,7 +501,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 @@ -535,3 +552,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 @@ -365,6 +365,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 @@ -160,20 +160,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. @@ -216,3 +202,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, we_are_translated diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py --- a/pypy/interpreter/pyframe.py +++ b/pypy/interpreter/pyframe.py @@ -170,8 +170,12 @@ def run(self): """Start this frame's execution.""" if self.is_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) def rangeiter_new(space, w_start, w_step, w_len, w_index): 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 @@ -1316,10 +1316,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__ = () @@ -121,13 +124,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/config/translationoption.py b/rpython/config/translationoption.py --- a/rpython/config/translationoption.py +++ b/rpython/config/translationoption.py @@ -177,6 +177,9 @@ BoolOption("lldebug", "If true, makes an lldebug build", default=False, cmdline="--lldebug"), + BoolOption("lldebug0", + "If true, makes an lldebug0 build", default=False, + cmdline="--lldebug0"), OptionDescription("backendopt", "Backend Optimization Options", [ # control inlining 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 @@ -1287,26 +1287,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/c/genc.py b/rpython/translator/c/genc.py --- a/rpython/translator/c/genc.py +++ b/rpython/translator/c/genc.py @@ -364,6 +364,8 @@ extra_opts += ['-j', str(self.config.translation.make_jobs)] if self.config.translation.lldebug: extra_opts += ["lldebug"] + elif self.config.translation.lldebug0: + extra_opts += ["lldebug0"] self.translator.platform.execute_makefile(self.targetdir, extra_opts) if shared: @@ -398,6 +400,7 @@ ('linuxmemchk', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DPPY_USE_LINUXMEMCHK" debug_target'), ('llsafer', '', '$(MAKE) CFLAGS="-O2 -DRPY_LL_ASSERT" $(TARGET)'), ('lldebug', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DRPY_LL_ASSERT" debug_target'), + ('lldebug0','', '$(MAKE) CFLAGS="-O0 $(DEBUGFLAGS) -DRPY_ASSERT -DRPY_LL_ASSERT" debug_target'), ('profile', '', '$(MAKE) CFLAGS="-g -O1 -pg $(CFLAGS) -fno-omit-frame-pointer" LDFLAGS="-pg $(LDFLAGS)" $(TARGET)'), ] if self.has_profopt(): 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 pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit