Author: Wim Lavrijsen <wlavrij...@lbl.gov> Branch: reflex-support Changeset: r54878:3f1d1ccdb3f5 Date: 2012-05-01 11:13 -0700 http://bitbucket.org/pypy/pypy/changeset/3f1d1ccdb3f5/
Log: merge default into branch diff --git a/lib-python/modified-2.7/test/test_peepholer.py b/lib-python/modified-2.7/test/test_peepholer.py --- a/lib-python/modified-2.7/test/test_peepholer.py +++ b/lib-python/modified-2.7/test/test_peepholer.py @@ -145,12 +145,15 @@ def test_binary_subscr_on_unicode(self): # valid code get optimized - asm = dis_single('u"foo"[0]') - self.assertIn("(u'f')", asm) - self.assertNotIn('BINARY_SUBSCR', asm) - asm = dis_single('u"\u0061\uffff"[1]') - self.assertIn("(u'\\uffff')", asm) - self.assertNotIn('BINARY_SUBSCR', asm) + # XXX for now we always disable this optimization + # XXX see CPython's issue5057 + if 0: + asm = dis_single('u"foo"[0]') + self.assertIn("(u'f')", asm) + self.assertNotIn('BINARY_SUBSCR', asm) + asm = dis_single('u"\u0061\uffff"[1]') + self.assertIn("(u'\\uffff')", asm) + self.assertNotIn('BINARY_SUBSCR', asm) # invalid code doesn't get optimized # out of range 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/interpreter/astcompiler/optimize.py b/pypy/interpreter/astcompiler/optimize.py --- a/pypy/interpreter/astcompiler/optimize.py +++ b/pypy/interpreter/astcompiler/optimize.py @@ -304,14 +304,19 @@ # produce compatible pycs. if (self.space.isinstance_w(w_obj, self.space.w_unicode) and self.space.isinstance_w(w_const, self.space.w_unicode)): - unistr = self.space.unicode_w(w_const) - if len(unistr) == 1: - ch = ord(unistr[0]) - else: - ch = 0 - if (ch > 0xFFFF or - (MAXUNICODE == 0xFFFF and 0xD800 <= ch <= 0xDFFF)): - return subs + #unistr = self.space.unicode_w(w_const) + #if len(unistr) == 1: + # ch = ord(unistr[0]) + #else: + # ch = 0 + #if (ch > 0xFFFF or + # (MAXUNICODE == 0xFFFF and 0xD800 <= ch <= 0xDFFF)): + # --XXX-- for now we always disable optimization of + # u'...'[constant] because the tests above are not + # enough to fix issue5057 (CPython has the same + # problem as of April 24, 2012). + # See test_const_fold_unicode_subscr + return subs return ast.Const(w_const, subs.lineno, subs.col_offset) diff --git a/pypy/interpreter/astcompiler/test/test_compiler.py b/pypy/interpreter/astcompiler/test/test_compiler.py --- a/pypy/interpreter/astcompiler/test/test_compiler.py +++ b/pypy/interpreter/astcompiler/test/test_compiler.py @@ -844,7 +844,8 @@ return u"abc"[0] """ counts = self.count_instructions(source) - assert counts == {ops.LOAD_CONST: 1, ops.RETURN_VALUE: 1} + if 0: # xxx later? + assert counts == {ops.LOAD_CONST: 1, ops.RETURN_VALUE: 1} # getitem outside of the BMP should not be optimized source = """def f(): @@ -854,12 +855,20 @@ assert counts == {ops.LOAD_CONST: 2, ops.BINARY_SUBSCR: 1, ops.RETURN_VALUE: 1} + source = """def f(): + return u"\U00012345abcdef"[3] + """ + counts = self.count_instructions(source) + assert counts == {ops.LOAD_CONST: 2, ops.BINARY_SUBSCR: 1, + ops.RETURN_VALUE: 1} + monkeypatch.setattr(optimize, "MAXUNICODE", 0xFFFF) source = """def f(): return u"\uE01F"[0] """ counts = self.count_instructions(source) - assert counts == {ops.LOAD_CONST: 1, ops.RETURN_VALUE: 1} + if 0: # xxx later? + assert counts == {ops.LOAD_CONST: 1, ops.RETURN_VALUE: 1} monkeypatch.undo() # getslice is not yet optimized. diff --git a/pypy/jit/backend/llsupport/asmmemmgr.py b/pypy/jit/backend/llsupport/asmmemmgr.py --- a/pypy/jit/backend/llsupport/asmmemmgr.py +++ b/pypy/jit/backend/llsupport/asmmemmgr.py @@ -277,6 +277,8 @@ from pypy.jit.backend.hlinfo import highleveljitinfo if highleveljitinfo.sys_executable: debug_print('SYS_EXECUTABLE', highleveljitinfo.sys_executable) + else: + debug_print('SYS_EXECUTABLE', '??') # HEX = '0123456789ABCDEF' dump = [] 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,7 +49,8 @@ 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): + or 'heap' not in enable_opts or 'unroll' not in enable_opts + or 'pure' not in enable_opts): optimizations.append(OptSimplify()) 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/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 @@ -6533,9 +6533,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 +6585,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 +7813,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/_multiprocessing/test/test_connection.py b/pypy/module/_multiprocessing/test/test_connection.py --- a/pypy/module/_multiprocessing/test/test_connection.py +++ b/pypy/module/_multiprocessing/test/test_connection.py @@ -157,13 +157,15 @@ raises(IOError, _multiprocessing.Connection, -15) def test_byte_order(self): + import socket + if not 'fromfd' in dir(socket): + skip('No fromfd in socket') # The exact format of net strings (length in network byte # order) is important for interoperation with others # implementations. rhandle, whandle = self.make_pair() whandle.send_bytes("abc") whandle.send_bytes("defg") - import socket sock = socket.fromfd(rhandle.fileno(), socket.AF_INET, socket.SOCK_STREAM) data1 = sock.recv(7) diff --git a/pypy/module/_winreg/test/test_winreg.py b/pypy/module/_winreg/test/test_winreg.py --- a/pypy/module/_winreg/test/test_winreg.py +++ b/pypy/module/_winreg/test/test_winreg.py @@ -198,7 +198,10 @@ import nt r = ExpandEnvironmentStrings(u"%windir%\\test") assert isinstance(r, unicode) - assert r == nt.environ["WINDIR"] + "\\test" + if 'WINDIR' in nt.environ.keys(): + assert r == nt.environ["WINDIR"] + "\\test" + else: + assert r == nt.environ["windir"] + "\\test" def test_long_key(self): from _winreg import ( diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -103,8 +103,8 @@ """.split() for name in constant_names: setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name)) -udir.join('pypy_decl.h').write("/* Will be filled later */") -udir.join('pypy_macros.h').write("/* Will be filled later */") +udir.join('pypy_decl.h').write("/* Will be filled later */\n") +udir.join('pypy_macros.h').write("/* Will be filled later */\n") globals().update(rffi_platform.configure(CConfig_constants)) def copy_header_files(dstdir): diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py --- a/pypy/module/micronumpy/test/test_dtypes.py +++ b/pypy/module/micronumpy/test/test_dtypes.py @@ -185,6 +185,33 @@ assert dtype("float") is dtype(float) + def test_index_int8(self): + from _numpypy import array, int8 + + a = array(range(10), dtype=int8) + b = array([0] * 10, dtype=int8) + for idx in b: a[idx] += 1 + + def test_index_int16(self): + from _numpypy import array, int16 + + a = array(range(10), dtype=int16) + b = array([0] * 10, dtype=int16) + for idx in b: a[idx] += 1 + + def test_index_int32(self): + from _numpypy import array, int32 + + a = array(range(10), dtype=int32) + b = array([0] * 10, dtype=int32) + for idx in b: a[idx] += 1 + + def test_index_int64(self): + from _numpypy import array, int64 + + a = array(range(10), dtype=int64) + b = array([0] * 10, dtype=int64) + for idx in b: a[idx] += 1 class AppTestTypes(BaseNumpyAppTest): def test_abstract_types(self): diff --git a/pypy/module/pypyjit/test_pypy_c/test_00_model.py b/pypy/module/pypyjit/test_pypy_c/test_00_model.py --- a/pypy/module/pypyjit/test_pypy_c/test_00_model.py +++ b/pypy/module/pypyjit/test_pypy_c/test_00_model.py @@ -54,7 +54,8 @@ cmdline += ['--jit', ','.join(jitcmdline)] cmdline.append(str(self.filepath)) # - env={'PYPYLOG': self.log_string + ':' + str(logfile)} + env = os.environ.copy() + env['PYPYLOG'] = self.log_string + ':' + str(logfile) pipe = subprocess.Popen(cmdline, env=env, stdout=subprocess.PIPE, diff --git a/pypy/module/rctime/interp_time.py b/pypy/module/rctime/interp_time.py --- a/pypy/module/rctime/interp_time.py +++ b/pypy/module/rctime/interp_time.py @@ -572,7 +572,7 @@ if i < length and format[i] == '#': # not documented by python i += 1 - if i >= length or format[i] not in "aAbBcdfHIjmMpSUwWxXyYzZ%": + if i >= length or format[i] not in "aAbBcdHIjmMpSUwWxXyYzZ%": raise OperationError(space.w_ValueError, space.wrap("invalid format string")) i += 1 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 long(rctime.mktime(rctime.gmtime(t))) - rctime.timezone == long(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/objspace/flow/operation.py b/pypy/objspace/flow/operation.py --- a/pypy/objspace/flow/operation.py +++ b/pypy/objspace/flow/operation.py @@ -350,8 +350,8 @@ result = op(*args) except Exception, e: etype = e.__class__ - msg = "generated by a constant operation: %s" % ( - name) + msg = "generated by a constant operation:\n\t%s%r" % ( + name, tuple(args)) raise OperationThatShouldNotBePropagatedError( self.wrap(etype), self.wrap(msg)) else: 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/rlib/rposix.py b/pypy/rlib/rposix.py --- a/pypy/rlib/rposix.py +++ b/pypy/rlib/rposix.py @@ -1,9 +1,11 @@ import os -from pypy.rpython.lltypesystem.rffi import CConstant, CExternVariable, INT +from pypy.rpython.lltypesystem.rffi import (CConstant, CExternVariable, + INT, CCHARPP) from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.rlib.rarithmetic import intmask from pypy.rlib.objectmodel import specialize +from pypy.rlib import jit class CConstantErrno(CConstant): # these accessors are used when calling get_errno() or set_errno() @@ -18,9 +20,69 @@ def __setitem__(self, index, value): assert index == 0 ll2ctypes.TLS.errno = value +if os.name == 'nt': + separate_module_sources =[''' + /* Lifted completely from CPython 3.3 Modules/posix_module.c */ + #include <malloc.h> /* for _msize */ + typedef struct { + intptr_t osfhnd; + char osfile; + } my_ioinfo; + extern __declspec(dllimport) char * __pioinfo[]; + #define IOINFO_L2E 5 + #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) + #define IOINFO_ARRAYS 64 + #define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS) + #define FOPEN 0x01 + #define _NO_CONSOLE_FILENO (intptr_t)-2 + /* This function emulates what the windows CRT + does to validate file handles */ + int + _PyVerify_fd(int fd) + { + const int i1 = fd >> IOINFO_L2E; + const int i2 = fd & ((1 << IOINFO_L2E) - 1); + + static size_t sizeof_ioinfo = 0; + + /* Determine the actual size of the ioinfo structure, + * as used by the CRT loaded in memory + */ + if (sizeof_ioinfo == 0 && __pioinfo[0] != NULL) { + sizeof_ioinfo = _msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS; + } + if (sizeof_ioinfo == 0) { + /* This should not happen... */ + goto fail; + } + + /* See that it isn't a special CLEAR fileno */ + if (fd != _NO_CONSOLE_FILENO) { + /* Microsoft CRT would check that 0<=fd<_nhandle but we can't do that. Instead + * we check pointer validity and other info + */ + if (0 <= i1 && i1 < IOINFO_ARRAYS && __pioinfo[i1] != NULL) { + /* finally, check that the file is open */ + my_ioinfo* info = (my_ioinfo*)(__pioinfo[i1] + i2 * sizeof_ioinfo); + if (info->osfile & FOPEN) { + return 1; + } + } + } + fail: + errno = EBADF; + return 0; + } + ''',] + export_symbols = ['_PyVerify_fd'] +else: + separate_module_sources = [] + export_symbols = [] errno_eci = ExternalCompilationInfo( - includes=['errno.h'] + includes=['errno.h','stdio.h'], + separate_module_sources = separate_module_sources, + export_symbols = export_symbols, ) _get_errno, _set_errno = CExternVariable(INT, 'errno', errno_eci, @@ -35,6 +97,21 @@ def set_errno(errno): _set_errno(rffi.cast(INT, errno)) +if os.name == 'nt': + _validate_fd = rffi.llexternal( + "_PyVerify_fd", [rffi.INT], rffi.INT, + compilation_info=errno_eci, + ) + @jit.dont_look_inside + def validate_fd(fd): + if not _validate_fd(fd): + raise OSError(get_errno(), 'Bad file descriptor') +else: + def _validate_fd(fd): + return 1 + + def validate_fd(fd): + return 1 def closerange(fd_low, fd_high): # this behaves like os.closerange() from Python 2.6. diff --git a/pypy/rlib/test/test_rposix.py b/pypy/rlib/test/test_rposix.py --- a/pypy/rlib/test/test_rposix.py +++ b/pypy/rlib/test/test_rposix.py @@ -131,3 +131,15 @@ os.rmdir(self.ufilename) except Exception: pass + + def test_validate_fd(self): + if os.name != 'nt': + skip('relevant for windows only') + assert rposix._validate_fd(0) == 1 + fid = open(str(udir.join('validate_test.txt')), 'w') + fd = fid.fileno() + assert rposix._validate_fd(fd) == 1 + fid.close() + assert rposix._validate_fd(fd) == 0 + + diff --git a/pypy/rpython/annlowlevel.py b/pypy/rpython/annlowlevel.py --- a/pypy/rpython/annlowlevel.py +++ b/pypy/rpython/annlowlevel.py @@ -488,6 +488,8 @@ else: TO = PTR if not hasattr(object, '_carry_around_for_tests'): + if object is None: + return lltype.nullptr(PTR.TO) assert not hasattr(object, '_TYPE') object._carry_around_for_tests = True object._TYPE = TO @@ -557,6 +559,8 @@ """NOT_RPYTHON: hack. Reverse the hacking done in cast_object_to_ptr().""" if isinstance(lltype.typeOf(ptr), lltype.Ptr): ptr = ptr._as_obj() + if ptr is None: + return None if not isinstance(ptr, Class): raise NotImplementedError("cast_base_ptr_to_instance: casting %r to %r" % (ptr, Class)) diff --git a/pypy/rpython/lltypesystem/lltype.py b/pypy/rpython/lltypesystem/lltype.py --- a/pypy/rpython/lltypesystem/lltype.py +++ b/pypy/rpython/lltypesystem/lltype.py @@ -1167,7 +1167,7 @@ try: return self._lookup_adtmeth(field_name) except AttributeError: - raise AttributeError("%r instance has no field %r" % (self._T._name, + raise AttributeError("%r instance has no field %r" % (self._T, field_name)) def __setattr__(self, field_name, val): 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 diff --git a/pypy/rpython/test/test_llann.py b/pypy/rpython/test/test_llann.py --- a/pypy/rpython/test/test_llann.py +++ b/pypy/rpython/test/test_llann.py @@ -9,6 +9,7 @@ from pypy.rpython.annlowlevel import MixLevelHelperAnnotator from pypy.rpython.annlowlevel import PseudoHighLevelCallable from pypy.rpython.annlowlevel import llhelper, cast_instance_to_base_ptr +from pypy.rpython.annlowlevel import cast_base_ptr_to_instance from pypy.rpython.annlowlevel import base_ptr_lltype from pypy.rpython.llinterp import LLInterpreter from pypy.rpython.test.test_llinterp import interpret @@ -502,7 +503,10 @@ self.y = y def f(x, y): - a = A(x, y) + if x > 20: + a = None + else: + a = A(x, y) a1 = cast_instance_to_base_ptr(a) return a1 @@ -510,3 +514,30 @@ assert typeOf(res) == base_ptr_lltype() assert fishllattr(res, 'x') == 5 assert fishllattr(res, 'y') == 10 + + res = interpret(f, [25, 10]) + assert res == nullptr(base_ptr_lltype().TO) + + +def test_cast_base_ptr_to_instance(): + class A: + def __init__(self, x, y): + self.x = x + self.y = y + + def f(x, y): + if x > 20: + a = None + else: + a = A(x, y) + a1 = cast_instance_to_base_ptr(a) + b = cast_base_ptr_to_instance(A, a1) + return a is b + + assert f(5, 10) is True + assert f(25, 10) is True + + res = interpret(f, [5, 10]) + assert res is True + res = interpret(f, [25, 10]) + assert res is True diff --git a/pypy/rpython/tool/rffi_platform.py b/pypy/rpython/tool/rffi_platform.py --- a/pypy/rpython/tool/rffi_platform.py +++ b/pypy/rpython/tool/rffi_platform.py @@ -379,7 +379,7 @@ self.name = name def prepare_code(self): - yield 'if ((%s) < 0) {' % (self.name,) + yield 'if ((%s) <= 0) {' % (self.name,) yield ' long long x = (long long)(%s);' % (self.name,) yield ' printf("value: %lld\\n", x);' yield '} else {' @@ -401,7 +401,7 @@ def prepare_code(self): yield '#ifdef %s' % self.macro yield 'dump("defined", 1);' - yield 'if ((%s) < 0) {' % (self.macro,) + yield 'if ((%s) <= 0) {' % (self.macro,) yield ' long long x = (long long)(%s);' % (self.macro,) yield ' printf("value: %lld\\n", x);' yield '} else {' diff --git a/pypy/tool/compare_last_builds.py b/pypy/tool/compare_last_builds.py new file mode 100644 --- /dev/null +++ b/pypy/tool/compare_last_builds.py @@ -0,0 +1,122 @@ +import os +import urllib2 +import json +import sys +import md5 + +wanted = sys.argv[1:] +if not wanted: + wanted = ['default'] +base = "http://buildbot.pypy.org/json/builders/" + +cachedir = os.environ.get('PYPY_BUILDS_CACHE') +if cachedir and not os.path.exists(cachedir): + os.makedirs(cachedir) + + + +def get_json(url, cache=cachedir): + return json.loads(get_data(url, cache)) + + +def get_data(url, cache=cachedir): + url = str(url) + if cache: + digest = md5.md5() + digest.update(url) + digest = digest.hexdigest() + cachepath = os.path.join(cachedir, digest) + if os.path.exists(cachepath): + with open(cachepath) as fp: + return fp.read() + + print 'GET', url + fp = urllib2.urlopen(url) + try: + data = fp.read() + if cache: + with open(cachepath, 'wb') as cp: + cp.write(data) + return data + finally: + fp.close() + +def parse_log(log): + items = [] + for v in log.splitlines(1): + if not v[0].isspace() and v[1].isspace(): + items.append(v) + return sorted(items) #sort cause testrunner order is non-deterministic + +def gather_logdata(build): + logdata = get_data(str(build['log']) + '?as_text=1') + logdata = logdata.replace('</span><span class="stdout">', '') + logdata = logdata.replace('</span></pre>', '') + del build['log'] + build['log'] = parse_log(logdata) + + +def branch_mapping(l): + keep = 3 - len(wanted) + d = {} + for x in reversed(l): + gather_logdata(x) + if not x['log']: + continue + b = x['branch'] + if b not in d: + d[b] = [] + d[b].insert(0, x) + if len(d[b]) > keep: + d[b].pop() + return d + +def cleanup_build(d): + for a in 'times eta steps slave reason sourceStamp blame currentStep text'.split(): + del d[a] + + props = d.pop(u'logs') + for name, val in props: + if name == u'pytestLog': + d['log'] = val + props = d.pop(u'properties') + for name, val, _ in props: + if name == u'branch': + d['branch'] = val or 'default' + return d + +def collect_builds(d): + name = str(d['basedir']) + builds = d['cachedBuilds'] + l = [] + for build in builds: + d = get_json(base + '%s/builds/%s' % (name, build)) + cleanup_build(d) + l.append(d) + + l = [x for x in l if x['branch'] in wanted and 'log' in x] + d = branch_mapping(l) + return [x for lst in d.values() for x in lst] + + +def only_linux32(d): + return d['own-linux-x86-32'] + + +own_builds = get_json(base, cache=False)['own-linux-x86-32'] + +builds = collect_builds(own_builds) + + +builds.sort(key=lambda x: (wanted.index(x['branch']), x['number'])) +logs = [x.pop('log') for x in builds] +for b, s in zip(builds, logs): + b['resultset'] = len(s) +import pprint +pprint.pprint(builds) + +from difflib import Differ + +for x in Differ().compare(*logs): + if x[0]!=' ': + sys.stdout.write(x) diff --git a/pypy/translator/c/src/cjkcodecs/cjkcodecs.h b/pypy/translator/c/src/cjkcodecs/cjkcodecs.h --- a/pypy/translator/c/src/cjkcodecs/cjkcodecs.h +++ b/pypy/translator/c/src/cjkcodecs/cjkcodecs.h @@ -210,15 +210,15 @@ #define BEGIN_CODECS_LIST /* empty */ #define _CODEC(name) \ - static const MultibyteCodec _pypy_cjkcodec_##name; \ - const MultibyteCodec *pypy_cjkcodec_##name(void) { \ + static MultibyteCodec _pypy_cjkcodec_##name; \ + MultibyteCodec *pypy_cjkcodec_##name(void) { \ if (_pypy_cjkcodec_##name.codecinit != NULL) { \ int r = _pypy_cjkcodec_##name.codecinit(_pypy_cjkcodec_##name.config); \ assert(r == 0); \ } \ return &_pypy_cjkcodec_##name; \ } \ - static const MultibyteCodec _pypy_cjkcodec_##name + static MultibyteCodec _pypy_cjkcodec_##name #define _STATEFUL_METHODS(enc) \ enc##_encode, \ enc##_encode_init, \ diff --git a/pypy/translator/c/src/cjkcodecs/multibytecodec.h b/pypy/translator/c/src/cjkcodecs/multibytecodec.h --- a/pypy/translator/c/src/cjkcodecs/multibytecodec.h +++ b/pypy/translator/c/src/cjkcodecs/multibytecodec.h @@ -131,7 +131,7 @@ /* list of codecs defined in the .c files */ #define DEFINE_CODEC(name) \ - const MultibyteCodec *pypy_cjkcodec_##name(void); + MultibyteCodec *pypy_cjkcodec_##name(void); // _codecs_cn DEFINE_CODEC(gb2312) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit