Author: Wim Lavrijsen <[email protected]>
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
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit