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