[pypy-svn] pypy arm-backend-2: merge default

bivab commits-noreply at bitbucket.org
Wed Feb 2 13:50:12 CET 2011


Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r41549:7c31324be2de
Date: 2011-01-25 10:13 +0100
http://bitbucket.org/pypy/pypy/changeset/7c31324be2de/

Log:	merge default

diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -80,11 +80,11 @@
 
 # ____________________________________________________________
 
-def compile_new_loop(metainterp, old_loop_tokens, greenkey, start,
-                     full_preamble_needed=True):
+def compile_new_loop(metainterp, old_loop_tokens, greenkey, start, start_resumedescr):
     """Try to compile a new loop by closing the current history back
     to the first operation.
     """
+    full_preamble_needed=True
     history = metainterp.history
     loop = create_empty_loop(metainterp)
     loop.inputargs = history.inputargs
@@ -102,6 +102,7 @@
     loop.preamble = create_empty_loop(metainterp, 'Preamble ')
     loop.preamble.inputargs = loop.inputargs
     loop.preamble.token = make_loop_token(len(loop.inputargs), jitdriver_sd)
+    loop.preamble.start_resumedescr = start_resumedescr
 
     try:
         old_loop_token = jitdriver_sd.warmstate.optimize_loop(
@@ -390,6 +391,12 @@
         self.copy_all_attrbutes_into(res)
         return res
 
+class ResumeAtPositionDescr(ResumeGuardDescr):
+    def _clone_if_mutable(self):
+        res = ResumeAtPositionDescr()
+        self.copy_all_attrbutes_into(res)
+        return res
+
 class ResumeGuardForcedDescr(ResumeGuardDescr):
 
     def __init__(self, metainterp_sd, jitdriver_sd):
@@ -574,10 +581,14 @@
     new_loop.operations = [op.clone() for op in metainterp.history.operations]
     metainterp_sd = metainterp.staticdata
     state = metainterp.jitdriver_sd.warmstate
+    if isinstance(resumekey, ResumeAtPositionDescr):
+        inline_short_preamble = False
+    else:
+        inline_short_preamble = True
     try:
         target_loop_token = state.optimize_bridge(metainterp_sd,
                                                   old_loop_tokens,
-                                                  new_loop)
+                                                  new_loop, inline_short_preamble)
     except InvalidLoop:
         # XXX I am fairly convinced that optimize_bridge cannot actually raise
         # InvalidLoop
@@ -588,34 +599,9 @@
         # know exactly what we must do (ResumeGuardDescr/ResumeFromInterpDescr)
         prepare_last_operation(new_loop, target_loop_token)
         resumekey.compile_and_attach(metainterp, new_loop)
-        compile_known_target_bridges(metainterp, new_loop)
         record_loop_or_bridge(metainterp_sd, new_loop)
     return target_loop_token
 
-# For backends that not supports emitting guards with preset jump
-# targets, emit mini-bridges containing the jump
-def compile_known_target_bridges(metainterp, bridge):
-    for op in bridge.operations:
-        if op.is_guard():
-            target = op.getjumptarget()
-            if target:
-                mini = create_empty_loop(metainterp, 'fallback')
-                mini.inputargs = op.getfailargs()[:]
-                jmp = ResOperation(rop.JUMP, mini.inputargs[:], None, target)
-                mini.operations = [jmp]
-                descr = op.getdescr()
-                assert isinstance(descr, ResumeGuardDescr)
-                mini.token = bridge.token
-                
-                #descr.compile_and_attach(metainterp, mini)
-                if not we_are_translated():
-                    descr._debug_suboperations = mini.operations
-                send_bridge_to_backend(metainterp.staticdata, descr,
-                                       mini.inputargs, mini.operations,
-                                       bridge.token)
-                record_loop_or_bridge(metainterp.staticdata, mini)
-
-
 def prepare_last_operation(new_loop, target_loop_token):
     op = new_loop.operations[-1]
     if not isinstance(target_loop_token, TerminatingLoopToken):

diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py
--- a/pypy/jit/codewriter/effectinfo.py
+++ b/pypy/jit/codewriter/effectinfo.py
@@ -10,9 +10,9 @@
 
     # the 'extraeffect' field is one of the following values:
     EF_PURE                            = 0 #pure function (and cannot raise)
-    EF_CANNOT_RAISE                    = 1 #a function which cannot raise
-    EF_CAN_RAISE                       = 2 #normal function (can raise)
-    EF_LOOPINVARIANT                   = 3 #special: call it only once per loop
+    EF_LOOPINVARIANT                   = 1 #special: call it only once per loop
+    EF_CANNOT_RAISE                    = 2 #a function which cannot raise
+    EF_CAN_RAISE                       = 3 #normal function (can raise)
     EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 4 #can raise and force virtualizables
 
     # the 'oopspecindex' field is one of the following values:
@@ -60,8 +60,13 @@
             return cls._cache[key]
         result = object.__new__(cls)
         result.readonly_descrs_fields = readonly_descrs_fields
-        result.write_descrs_fields = write_descrs_fields
-        result.write_descrs_arrays = write_descrs_arrays
+        if extraeffect == EffectInfo.EF_LOOPINVARIANT or \
+           extraeffect == EffectInfo.EF_PURE:            
+            result.write_descrs_fields = []
+            result.write_descrs_arrays = []
+        else:
+            result.write_descrs_fields = write_descrs_fields
+            result.write_descrs_arrays = write_descrs_arrays
         result.extraeffect = extraeffect
         result.oopspecindex = oopspecindex
         cls._cache[key] = result

diff --git a/pypy/translator/c/test/test_dtoa.py b/pypy/translator/c/test/test_dtoa.py
deleted file mode 100644
--- a/pypy/translator/c/test/test_dtoa.py
+++ /dev/null
@@ -1,92 +0,0 @@
-from __future__ import with_statement
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.tool.autopath import pypydir
-from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.rlib.rstring import StringBuilder
-import py
-
-includes = []
-libraries = []
-
-cdir = py.path.local(pypydir) / 'translator' / 'c'
-files = [cdir / 'src' / 'dtoa.c']
-include_dirs = [cdir]
-
-eci = ExternalCompilationInfo(
-    include_dirs = include_dirs,
-    libraries = libraries,
-    separate_module_files = files,
-    separate_module_sources = ['''
-        #include <stdlib.h>
-        #include <assert.h>
-        #define WITH_PYMALLOC
-        #include "src/obmalloc.c"
-    '''],
-    export_symbols = ['_Py_dg_strtod',
-                      '_Py_dg_dtoa',
-                      '_Py_dg_freedtoa',
-                      ],
-)
-
-dg_strtod = rffi.llexternal(
-    '_Py_dg_strtod', [rffi.CCHARP, rffi.CCHARPP], rffi.DOUBLE,
-    compilation_info=eci)
-
-dg_dtoa = rffi.llexternal(
-    '_Py_dg_dtoa', [rffi.DOUBLE, rffi.INT, rffi.INT,
-                    rffi.INTP, rffi.INTP, rffi.CCHARPP], rffi.CCHARP,
-    compilation_info=eci)
-
-dg_freedtoa = rffi.llexternal(
-    '_Py_dg_freedtoa', [rffi.CCHARP], lltype.Void,
-    compilation_info=eci)
-
-def strtod(input):
-    with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as end_ptr:
-        with rffi.scoped_str2charp(input) as ll_input:
-            result = dg_strtod(ll_input, end_ptr)
-            if end_ptr[0] and ord(end_ptr[0][0]):
-                offset = (rffi.cast(rffi.LONG, end_ptr[0]) -
-                          rffi.cast(rffi.LONG, ll_input))
-                raise ValueError("invalid input at position %d" % (offset,))
-            return result
-
-def dtoa(value, mode=0, precision=0):
-    builder = StringBuilder(20)
-    with lltype.scoped_alloc(rffi.INTP.TO, 1) as decpt_ptr:
-        with lltype.scoped_alloc(rffi.INTP.TO, 1) as sign_ptr:
-            with lltype.scoped_alloc(rffi.CCHARPP.TO, 1) as end_ptr:
-                output_ptr = dg_dtoa(value, mode, precision,
-                                     decpt_ptr, sign_ptr, end_ptr)
-                try:
-                    buflen = (rffi.cast(rffi.LONG, end_ptr[0]) -
-                              rffi.cast(rffi.LONG, output_ptr))
-                    intpart = rffi.cast(lltype.Signed, decpt_ptr[0])
-                    if intpart <= buflen:
-                        builder.append(rffi.charpsize2str(output_ptr, intpart))
-                    else:
-                        builder.append(rffi.charpsize2str(output_ptr, buflen))
-                        while buflen < intpart:
-                            builder.append('0')
-                            intpart -= 1
-                    builder.append('.')
-                    fracpart = buflen - intpart
-                    if fracpart > 0:
-                        ptr = rffi.ptradd(output_ptr, intpart)
-                        builder.append(rffi.charpsize2str(ptr, fracpart))
-                finally:
-                    dg_freedtoa(output_ptr)
-    return builder.build()
-
-def test_strtod():
-    assert strtod("12345") == 12345.0
-    assert strtod("1.1") == 1.1
-    assert strtod("3.47") == 3.47
-    raises(ValueError, strtod, "123A")
-
-def test_dtoa():
-    assert dtoa(3.47) == "3.47"
-    assert dtoa(1.1) == "1.1"
-    assert dtoa(12.3577) == "12.3577"
-    assert dtoa(10) == "10."
-    assert dtoa(1e100) == "1" + "0" * 100 + "."

diff --git a/pypy/module/pypyjit/test/test_pypy_c.py b/pypy/module/pypyjit/test/test_pypy_c.py
--- a/pypy/module/pypyjit/test/test_pypy_c.py
+++ b/pypy/module/pypyjit/test/test_pypy_c.py
@@ -150,6 +150,14 @@
         _, self.sliced_entrybridge, _ = \
                                     self.parse_rawloops(self.rawentrybridges)
 
+        from pypy.jit.tool.jitoutput import parse_prof
+        summaries  = logparser.extract_category(log, 'jit-summary')
+        if len(summaries) > 0:
+            self.jit_summary = parse_prof(summaries[-1])
+        else:
+            self.jit_summary = None
+        
+
     def parse_rawloops(self, rawloops):
         from pypy.jit.tool.oparser import parse
         loops = [parse(part, no_namespace=True) for part in rawloops]
@@ -1437,7 +1445,6 @@
                          count_debug_merge_point=False)
         
     def test_mod(self):
-        py.test.skip('Results are correct, but traces 1902 times (on trunk too).')
         avalues = ('a', 'b', 7, -42, 8)
         bvalues = ['b'] + range(-10, 0) + range(1,10)
         code = ''
@@ -1466,11 +1473,25 @@
 %s
                 i += 1
             return sa
-        ''' % code, 0, ([a1, b1], 2000 * res1),
+        ''' % code, 150, ([a1, b1], 2000 * res1),
                          ([a2, b2], 2000 * res2),
                          ([a3, b3], 2000 * res3),
                          count_debug_merge_point=False)
         
+    def test_dont_trace_every_iteration(self):
+        self.run_source('''
+        def main(a, b):
+            i = sa = 0
+            while i < 200:
+                if a > 0: pass
+                if 1 < b < 2: pass
+                sa += a % b
+                i += 1
+            return sa
+        ''', 11,  ([10, 20], 200 * (10 % 20)),
+                 ([-10, -20], 200 * (-10 % -20)),
+                        count_debug_merge_point=False)
+        assert self.jit_summary.tracing_no == 2
     def test_id_compare_optimization(self):
         # XXX: lower the instruction count, 35 is the old value.
         self.run_source("""

diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -19,7 +19,7 @@
 from pypy.jit.metainterp.jitexc import JitException, get_llexception
 from pypy.rlib.rarithmetic import intmask
 from pypy.rlib.objectmodel import specialize
-from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr
+from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr, MissingLiveness
 from pypy.jit.codewriter import heaptracker
 from pypy.jit.metainterp.optimizeutil import RetraceLoop
 
@@ -819,8 +819,8 @@
         self.generate_guard(rop.GUARD_CLASS, box, [clsbox], resumepc=orgpc)
         return clsbox
 
-    @arguments("int")
-    def opimpl_loop_header(self, jdindex):
+    @arguments("int", "orgpc")
+    def opimpl_loop_header(self, jdindex, orgpc):
         self.metainterp.seen_loop_header_for_jdindex = jdindex
 
     def verify_green_args(self, jitdriver_sd, varargs):
@@ -832,12 +832,16 @@
     @arguments("orgpc", "int", "boxes3", "jitcode_position", "boxes3")
     def opimpl_jit_merge_point(self, orgpc, jdindex, greenboxes,
                                jcposition, redboxes):
+        resumedescr = compile.ResumeAtPositionDescr()
+        self.capture_resumedata(resumedescr, orgpc)
+        
         any_operation = len(self.metainterp.history.operations) > 0
         jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex]
         self.verify_green_args(jitdriver_sd, greenboxes)
         # xxx we may disable the following line in some context later
         self.debug_merge_point(jitdriver_sd, self.metainterp.in_recursion,
                                greenboxes)
+
         if self.metainterp.seen_loop_header_for_jdindex < 0:
             if not jitdriver_sd.no_loop_header or not any_operation:
                 return
@@ -848,6 +852,7 @@
             "found a loop_header for a JitDriver that does not match "
             "the following jit_merge_point's")
         self.metainterp.seen_loop_header_for_jdindex = -1
+        
         #
         if not self.metainterp.in_recursion:
             assert jitdriver_sd is self.metainterp.jitdriver_sd
@@ -857,7 +862,7 @@
             # much less expensive to blackhole out of.
             saved_pc = self.pc
             self.pc = orgpc
-            self.metainterp.reached_loop_header(greenboxes, redboxes)
+            self.metainterp.reached_loop_header(greenboxes, redboxes, resumedescr)
             self.pc = saved_pc
             # no exception, which means that the jit_merge_point did not
             # close the loop.  We have to put the possibly-modified list
@@ -1075,20 +1080,26 @@
             resumedescr = compile.ResumeGuardDescr()
         guard_op = metainterp.history.record(opnum, moreargs, None,
                                              descr=resumedescr)
+        self.capture_resumedata(resumedescr, resumepc)
+        self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS)
+        # count
+        metainterp.attach_debug_info(guard_op)
+        return guard_op
+
+    def capture_resumedata(self, resumedescr, resumepc=-1):
+        metainterp = self.metainterp
         virtualizable_boxes = None
         if (metainterp.jitdriver_sd.virtualizable_info is not None or
             metainterp.jitdriver_sd.greenfield_info is not None):
             virtualizable_boxes = metainterp.virtualizable_boxes
         saved_pc = self.pc
-        if resumepc >= 0:
-            self.pc = resumepc
-        resume.capture_resumedata(metainterp.framestack, virtualizable_boxes,
-                                  metainterp.virtualref_boxes, resumedescr)
-        self.pc = saved_pc
-        self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS)
-        # count
-        metainterp.attach_debug_info(guard_op)
-        return guard_op
+        try:
+            if resumepc >= 0:
+                self.pc = resumepc
+            resume.capture_resumedata(metainterp.framestack, virtualizable_boxes,
+                                      metainterp.virtualref_boxes, resumedescr)
+        finally:
+            self.pc = saved_pc
 
     def implement_guard_value(self, orgpc, box):
         """Promote the given Box into a Const.  Note: be careful, it's a
@@ -1192,7 +1203,7 @@
                     self.execute_varargs(rop.CALL, allboxes, descr, False))
             elif effect == effectinfo.EF_LOOPINVARIANT:
                 return self.execute_varargs(rop.CALL_LOOPINVARIANT, allboxes,
-                                            descr, True)
+                                            descr, False)
             else:
                 return self.execute_varargs(rop.CALL, allboxes, descr, True)
 
@@ -1703,8 +1714,13 @@
         self.current_merge_points = []
         self.resumekey = key
         self.seen_loop_header_for_jdindex = -1
-        try:
-            self.prepare_resume_from_failure(key.guard_opnum)
+        if isinstance(key, compile.ResumeAtPositionDescr):
+            self.seen_loop_header_for_jdindex = self.jitdriver_sd.index
+            dont_change_position = True
+        else:
+            dont_change_position = False
+        try:            
+            self.prepare_resume_from_failure(key.guard_opnum, dont_change_position)
             if self.resumekey_original_loop_token is None:   # very rare case
                 raise SwitchToBlackhole(ABORT_BRIDGE)
             self.interpret()
@@ -1734,7 +1750,7 @@
             else:
                 duplicates[box] = None
 
-    def reached_loop_header(self, greenboxes, redboxes):
+    def reached_loop_header(self, greenboxes, redboxes, resumedescr):
         duplicates = {}
         self.remove_consts_and_duplicates(redboxes, len(redboxes),
                                           duplicates)
@@ -1789,9 +1805,9 @@
                     bridge_arg_boxes = self.retracing_loop_from.live_arg_boxes
                     self.compile_bridge_and_loop(original_boxes, \
                                                  live_arg_boxes, start,
-                                                 bridge_arg_boxes)
+                                                 bridge_arg_boxes, resumedescr)
                 else:
-                    self.compile(original_boxes, live_arg_boxes, start)
+                    self.compile(original_boxes, live_arg_boxes, start, resumedescr)
                 # creation of the loop was cancelled!
                 #self.staticdata.log('cancelled, tracing more...')
                 self.staticdata.log('cancelled, stopping tracing')
@@ -1808,10 +1824,11 @@
         history.set_future_values(self.cpu, residual_args)
         return loop_token
 
-    def prepare_resume_from_failure(self, opnum):
+    def prepare_resume_from_failure(self, opnum, dont_change_position=False):
         frame = self.framestack[-1]
         if opnum == rop.GUARD_TRUE:     # a goto_if_not that jumps only now
-            frame.pc = frame.jitcode.follow_jump(frame.pc)
+            if not dont_change_position:
+                frame.pc = frame.jitcode.follow_jump(frame.pc)
         elif opnum == rop.GUARD_FALSE:     # a goto_if_not that stops jumping
             pass
         elif opnum == rop.GUARD_VALUE or opnum == rop.GUARD_CLASS:
@@ -1854,14 +1871,14 @@
         cell = self.jitdriver_sd.warmstate.jit_cell_at_key(greenkey)
         cell.set_compiled_merge_points(looptokens)
 
-    def compile(self, original_boxes, live_arg_boxes, start):
+    def compile(self, original_boxes, live_arg_boxes, start, start_resumedescr):
         num_green_args = self.jitdriver_sd.num_green_args
         self.history.inputargs = original_boxes[num_green_args:]
         greenkey = original_boxes[:num_green_args]
         old_loop_tokens = self.get_compiled_merge_points(greenkey)
         self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None)
         loop_token = compile.compile_new_loop(self, old_loop_tokens,
-                                              greenkey, start)
+                                              greenkey, start, start_resumedescr)
         if loop_token is not None: # raise if it *worked* correctly
             self.set_compiled_merge_points(greenkey, old_loop_tokens)
             raise GenerateMergePoint(live_arg_boxes, loop_token)
@@ -1887,7 +1904,7 @@
             self.history.operations.pop()     # remove the JUMP
 
     def compile_bridge_and_loop(self, original_boxes, live_arg_boxes, start,
-                                bridge_arg_boxes):
+                                bridge_arg_boxes, start_resumedescr):
         num_green_args = self.jitdriver_sd.num_green_args
         original_inputargs = self.history.inputargs
         greenkey = original_boxes[:num_green_args]
@@ -1896,7 +1913,7 @@
         self.history.inputargs = original_boxes[num_green_args:]
         greenkey = original_boxes[:num_green_args]
         self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None)
-        loop_token = compile.compile_new_loop(self, [], greenkey, start)
+        loop_token = compile.compile_new_loop(self, [], greenkey, start, start_resumedescr)
         self.history.operations.pop()     # remove the JUMP
         if loop_token is None:
             return

diff --git a/pypy/jit/metainterp/simple_optimize.py b/pypy/jit/metainterp/simple_optimize.py
--- a/pypy/jit/metainterp/simple_optimize.py
+++ b/pypy/jit/metainterp/simple_optimize.py
@@ -47,7 +47,7 @@
             jumpop.setdescr(loop.token)
         return None
 
-def optimize_bridge(metainterp_sd, old_loops, loop):
+def optimize_bridge(metainterp_sd, old_loops, loop, inline_short_preamble):
     optimize_loop(metainterp_sd, [], loop)
     jumpop = loop.operations[-1]
     if jumpop.getopnum() == rop.JUMP:

diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py
--- a/pypy/jit/codewriter/test/test_jtransform.py
+++ b/pypy/jit/codewriter/test/test_jtransform.py
@@ -722,18 +722,19 @@
     tr = Transformer()
     tr.portal_jd = jd
     oplist = tr.rewrite_operation(op)
-    assert len(oplist) == 6
+    assert len(oplist) == 7
     assert oplist[0].opname == '-live-'
     assert oplist[1].opname == 'int_guard_value'
     assert oplist[1].args   == [v1]
     assert oplist[2].opname == '-live-'
     assert oplist[3].opname == 'int_guard_value'
     assert oplist[3].args   == [v2]
-    assert oplist[4].opname == 'jit_merge_point'
-    assert oplist[4].args[0].value == 42
-    assert list(oplist[4].args[1]) == [v1, v2]
-    assert list(oplist[4].args[4]) == [v3, v4]
-    assert oplist[5].opname == '-live-'
+    assert oplist[4].opname == '-live-'
+    assert oplist[5].opname == 'jit_merge_point'
+    assert oplist[5].args[0].value == 42
+    assert list(oplist[5].args[1]) == [v1, v2]
+    assert list(oplist[5].args[4]) == [v3, v4]
+    assert oplist[6].opname == '-live-'
 
 def test_getfield_gc():
     S = lltype.GcStruct('S', ('x', lltype.Char))

diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py
--- a/pypy/jit/metainterp/test/test_compile.py
+++ b/pypy/jit/metainterp/test/test_compile.py
@@ -86,7 +86,7 @@
     metainterp.history.inputargs = loop.inputargs[:]
     #
     loop_tokens = []
-    loop_token = compile_new_loop(metainterp, loop_tokens, [], 0)
+    loop_token = compile_new_loop(metainterp, loop_tokens, [], 0, None)
     assert loop_tokens == [loop_token]
     assert loop_token.number == 1
     assert staticdata.globaldata.loopnumbering == 2
@@ -102,7 +102,7 @@
     metainterp.history.operations = loop.operations[:]
     metainterp.history.inputargs = loop.inputargs[:]
     #
-    loop_token_2 = compile_new_loop(metainterp, loop_tokens, [], 0)
+    loop_token_2 = compile_new_loop(metainterp, loop_tokens, [], 0, None)
     assert loop_token_2 is loop_token
     assert loop_tokens == [loop_token]
     assert len(cpu.seen) == 0

diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -291,11 +291,12 @@
 #__________________________________________________________
 
 def timeval_from_double(d, timeval):
-    timeval.c_tv_sec = int(d)
-    timeval.c_tv_usec = int((d - int(d)) * 1000000)
+    rffi.setintfield(timeval, 'c_tv_sec', int(d))
+    rffi.setintfield(timeval, 'c_tv_usec', int((d - int(d)) * 1000000))
 
 def double_from_timeval(tv):
-    return tv.c_tv_sec + (tv.c_tv_usec / 1000000.0)
+    return rffi.getintfield(tv, 'c_tv_sec') + (
+        rffi.getintfield(tv, 'c_tv_usec') / 1000000.0)
 
 def itimer_retval(space, val):
     w_value = space.wrap(double_from_timeval(val.c_it_value))

diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -9,7 +9,7 @@
 from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr
 from pypy.jit.codewriter import heaptracker
 from pypy.jit.metainterp.jitexc import JitException, get_llexception, reraise
-
+from pypy.jit.metainterp.compile import ResumeAtPositionDescr
 
 def arguments(*argtypes, **kwds):
     resulttype = kwds.pop('returns', None)
@@ -1210,13 +1210,14 @@
             assert kind == 'v'
         return lltype.nullptr(rclass.OBJECTPTR.TO)
 
-    def _prepare_resume_from_failure(self, opnum):
+    def _prepare_resume_from_failure(self, opnum, dont_change_position=False):
         from pypy.jit.metainterp.resoperation import rop
         #
         if opnum == rop.GUARD_TRUE:
             # Produced directly by some goto_if_not_xxx() opcode that did not
             # jump, but which must now jump.  The pc is just after the opcode.
-            self.position = self.jitcode.follow_jump(self.position)
+            if not dont_change_position:
+                self.position = self.jitcode.follow_jump(self.position)
         #
         elif opnum == rop.GUARD_FALSE:
             # Produced directly by some goto_if_not_xxx() opcode that jumped,
@@ -1372,8 +1373,14 @@
         jitdriver_sd,
         resumedescr,
         all_virtuals)
+    if isinstance(resumedescr, ResumeAtPositionDescr):
+        dont_change_position = True
+    else:
+        dont_change_position = False
+
     current_exc = blackholeinterp._prepare_resume_from_failure(
-        resumedescr.guard_opnum)
+        resumedescr.guard_opnum, dont_change_position)
+        
     try:
         _run_forever(blackholeinterp, current_exc)
     finally:

diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1114,6 +1114,13 @@
                                  self.wrap('read-write buffer expected'))
         return buffer
 
+    def bufferstr_new_w(self, w_obj):
+        # Implement the "new buffer interface" (new in Python 2.7)
+        # returning an unwrapped string. It doesn't accept unicode
+        # strings
+        buffer = self.buffer_w(w_obj)
+        return buffer.as_str()
+
     def bufferstr_w(self, w_obj):
         # Directly returns an interp-level str.  Note that if w_obj is a
         # unicode string, this is different from str_w(buffer(w_obj)):

diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -881,7 +881,9 @@
         op1 = SpaceOperation('jit_merge_point', args, None)
         op2 = SpaceOperation('-live-', [], None)
         # ^^^ we need a -live- for the case of do_recursive_call()
-        return ops + [op1, op2]
+        op3 = SpaceOperation('-live-', [], None)
+        # and one for inlined short preambles
+        return ops + [op3, op1, op2]
 
     def handle_jit_marker__loop_header(self, op, jitdriver):
         jd = self.callcontrol.jitdriver_sd_from_jitdriver(jitdriver)

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
@@ -436,9 +436,6 @@
         self.newoperations.append(op)
 
     def store_final_boxes_in_guard(self, op):
-        ###pendingfields = self.heap_op_optimizer.force_lazy_setfields_for_guard()
-        if op.getjumptarget():
-            return op
         descr = op.getdescr()
         assert isinstance(descr, compile.ResumeGuardDescr)
         modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)

diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/test/test_optimizeopt.py
@@ -176,6 +176,15 @@
             metainterp_sd.virtualref_info = self.vrefinfo
         if hasattr(self, 'callinfocollection'):
             metainterp_sd.callinfocollection = self.callinfocollection
+        class FakeDescr(compile.ResumeGuardDescr):
+            class rd_snapshot:
+                class prev:
+                    prev = None
+                    boxes = []
+                boxes = []
+            def clone_if_mutable(self):
+                return self
+        loop.preamble.start_resumedescr = FakeDescr()
         optimize_loop_1(metainterp_sd, loop)
         #
 
@@ -691,12 +700,16 @@
         guard_nonnull(p0) []
         jump(p0)
         """
-        expected = """
+        preamble = """
         [p0]
         setfield_gc(p0, 5, descr=valuedescr)
         jump(p0)
         """
-        self.optimize_loop(ops, expected)
+        expected = """
+        [p0]
+        jump(p0)
+        """
+        self.optimize_loop(ops, expected, preamble)
 
     def test_const_guard_value(self):
         ops = """
@@ -2838,31 +2851,59 @@
 
     def test_call_assembler_invalidates_caches(self):
         ops = '''
-        [p1, i1]
+        [p1, i1, i4]
         setfield_gc(p1, i1, descr=valuedescr)
         i3 = call_assembler(i1, descr=asmdescr)
         setfield_gc(p1, i3, descr=valuedescr)
-        jump(p1, i3)
+        jump(p1, i4, i3)
         '''
-        self.optimize_loop(ops, ops)
+        self.optimize_loop(ops, ops, ops)
+
+    def test_call_assembler_invalidates_heap_knowledge(self):
+        ops = '''
+        [p1, i1, i4]
+        setfield_gc(p1, i1, descr=valuedescr)
+        i3 = call_assembler(i1, descr=asmdescr)
+        setfield_gc(p1, i1, descr=valuedescr)
+        jump(p1, i4, i3)
+        '''
+        self.optimize_loop(ops, ops, ops)
 
     def test_call_pure_invalidates_caches(self):
         # CALL_PURE should still force the setfield_gc() to occur before it
         ops = '''
-        [p1, i1]
+        [p1, i1, i4]
         setfield_gc(p1, i1, descr=valuedescr)
         i3 = call_pure(42, p1, descr=plaincalldescr)
         setfield_gc(p1, i3, descr=valuedescr)
-        jump(p1, i3)
+        jump(p1, i4, i3)
         '''
         expected = '''
-        [p1, i1]
+        [p1, i1, i4]
         setfield_gc(p1, i1, descr=valuedescr)
         i3 = call(p1, descr=plaincalldescr)
         setfield_gc(p1, i3, descr=valuedescr)
-        jump(p1, i3)
+        jump(p1, i4, i3)
         '''
-        self.optimize_loop(ops, expected)
+        self.optimize_loop(ops, expected, expected)
+
+    def test_call_pure_invalidates_heap_knowledge(self):
+        # CALL_PURE should still force the setfield_gc() to occur before it
+        ops = '''
+        [p1, i1, i4]
+        setfield_gc(p1, i1, descr=valuedescr)
+        i3 = call_pure(42, p1, descr=plaincalldescr)
+        setfield_gc(p1, i1, descr=valuedescr)
+        jump(p1, i4, i3)
+        '''
+        expected = '''
+        [p1, i1, i4]
+        setfield_gc(p1, i1, descr=valuedescr)
+        i3 = call(p1, descr=plaincalldescr)
+        setfield_gc(p1, i1, descr=valuedescr)
+        jump(p1, i4, i3)
+        '''
+        self.optimize_loop(ops, expected, expected)
 
     def test_call_pure_constant_folding(self):
         # CALL_PURE is not marked as is_always_pure(), because it is wrong
@@ -3384,7 +3425,6 @@
         """
         expected = """
         [i0]
-        i2 = int_add(i0, 10)
         jump(i0)
         """
         self.optimize_loop(ops, expected, preamble)
@@ -3675,10 +3715,9 @@
         jump(p0, i22)
         """
         expected = """
-        [p0, i22, i1]
+        [p0, i22]
         i331 = force_token()
-        setfield_gc(p0, i1, descr=valuedescr)
-        jump(p0, i22, i1)
+        jump(p0, i22)
         """
         self.optimize_loop(ops, expected)
 
@@ -4184,7 +4223,6 @@
         guard_no_overflow() []
         i2 = int_gt(i1, 1)
         guard_true(i2) []
-        i3 = int_sub(1, i0)
         jump(i0)
         """
         expected = """
@@ -4519,16 +4557,11 @@
         guard_true(i4) []
         i5 = int_gt(i3, 2)
         guard_true(i5) []
-        jump(i0, i1, i22)
-        """
-        expected = """
-        [i0, i1, i22]
-        i3 = int_mul(i22, i1)
-        i4 = int_lt(i3, 10)
-        guard_true(i4) []
-        i5 = int_gt(i3, 2)
-        guard_true(i5) []
-        jump(i0, i1, i22)
+        jump(i0, i1)
+        """
+        expected = """
+        [i0, i1]
+        jump(i0, i1)
         """
         self.optimize_loop(ops, expected, preamble)
 
@@ -4557,19 +4590,43 @@
         guard_true(i4) []
         i5 = int_ge(i3, 2)
         guard_true(i5) []
-        jump(i0, i1, i2)
-        """
-        expected = """
-        [i0, i1, i2]
-        i3 = int_sub(i2, i1)
-        i4 = int_le(i3, 10)
-        guard_true(i4) []
-        i5 = int_ge(i3, 2)
-        guard_true(i5) []
-        jump(i0, i1, i2)
+        jump(i0, i1)
+        """
+        expected = """
+        [i0, i1]
+        jump(i0, i1)
         """
         self.optimize_loop(ops, expected, preamble)
 
+    def test_invariant_ovf(self):
+        ops = """
+        [i0, i1, i10, i11, i12]
+        i2 = int_add_ovf(i0, i1)
+        guard_no_overflow() []
+        i3 = int_sub_ovf(i0, i1)
+        guard_no_overflow() []
+        i4 = int_mul_ovf(i0, i1)
+        guard_no_overflow() []
+        i24 = int_mul_ovf(i10, i11)
+        guard_no_overflow() []
+        i23 = int_sub_ovf(i10, i11)
+        guard_no_overflow() []
+        i22 = int_add_ovf(i10, i11)
+        guard_no_overflow() []
+        jump(i0, i1, i2, i3, i4)
+        """
+        expected = """
+        [i0, i1, i10, i11, i12]
+        i24 = int_mul_ovf(i10, i11)
+        guard_no_overflow() []
+        i23 = int_sub_ovf(i10, i11)
+        guard_no_overflow() []
+        i22 = int_add_ovf(i10, i11)
+        guard_no_overflow() []
+        jump(i0, i1, i10, i11, i12)
+        """
+        self.optimize_loop(ops, expected, ops)
+
     def test_value_proven_to_be_constant_after_two_iterations(self):
         class FakeDescr(AbstractDescr):
             def __init__(self, name):
@@ -4633,6 +4690,47 @@
         """
         self.optimize_loop(ops, expected)
 
+    def test_let_getfield_kill_setfields(self):
+        ops = """
+        [p0]
+        p1 = getfield_gc(p0, descr=valuedescr)
+        setfield_gc(p0, p1, descr=valuedescr)
+        setfield_gc(p0, p1, descr=valuedescr)
+        setfield_gc(p0, p0, descr=valuedescr)        
+        jump(p0)
+        """
+        preamble = """
+        [p0]
+        p1 = getfield_gc(p0, descr=valuedescr)
+        setfield_gc(p0, p0, descr=valuedescr)                
+        jump(p0)
+        """
+        expected = """
+        [p0]
+        jump(p0)
+        """
+        self.optimize_loop(ops, expected, preamble)
+
+    def test_let_getfield_kill_chained_setfields(self):
+        ops = """
+        [p0]
+        p1 = getfield_gc(p0, descr=valuedescr)
+        setfield_gc(p0, p0, descr=valuedescr)        
+        setfield_gc(p0, p1, descr=valuedescr)
+        setfield_gc(p0, p1, descr=valuedescr)
+        jump(p0)
+        """
+        preamble = """
+        [p0]
+        p1 = getfield_gc(p0, descr=valuedescr)
+        jump(p0)
+        """
+        expected = """
+        [p0]
+        jump(p0)
+        """
+        self.optimize_loop(ops, expected, preamble)
+
     def test_inputargs_added_by_forcing_jumpargs(self):
         # FXIME: Can this occur?
         ops = """
@@ -5282,6 +5380,7 @@
         # more generally, supporting non-constant but virtual cases is
         # not obvious, because of the exception UnicodeDecodeError that
         # can be raised by ll_str2unicode()
+        
 
 
 

diff --git a/pypy/jit/metainterp/test/test_basic.py b/pypy/jit/metainterp/test/test_basic.py
--- a/pypy/jit/metainterp/test/test_basic.py
+++ b/pypy/jit/metainterp/test/test_basic.py
@@ -1843,6 +1843,47 @@
                           'int_add': 1, 'int_mul': 1, 'int_sub': 2,
                           'int_gt': 2, 'jump': 2})
 
+    def test_multiple_specialied_versions_array(self):
+        myjitdriver = JitDriver(greens = [], reds = ['idx', 'y', 'x', 'res',
+                                                     'array'])
+        class Base:
+            def __init__(self, val):
+                self.val = val
+        class A(Base):
+            def binop(self, other):
+                return A(self.val + other.val)
+        class B(Base):
+            def binop(self, other):
+                return B(self.val - other.val)
+        def f(x, y):
+            res = x
+            array = [1, 2, 3]
+            array[1] = 7
+            idx = 0
+            while y > 0:
+                myjitdriver.can_enter_jit(idx=idx, y=y, x=x, res=res,
+                                          array=array)
+                myjitdriver.jit_merge_point(idx=idx, y=y, x=x, res=res,
+                                            array=array)
+                res = res.binop(x)
+                res.val += array[idx] + array[1]
+                if y < 7:
+                    idx = 2
+                y -= 1
+            return res
+        def g(x, y):
+            a1 = f(A(x), y)
+            a2 = f(A(x), y)
+            b1 = f(B(x), y)
+            b2 = f(B(x), y)
+            assert a1.val == a2.val
+            assert b1.val == b2.val
+            return a1.val + b1.val
+        res = self.meta_interp(g, [6, 14])
+        assert res == g(6, 14)
+        self.check_loop_count(8)
+        self.check_loops(getarrayitem_gc=16, everywhere=True)
+
     def test_multiple_specialied_versions_bridge(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
         class Base:
@@ -1869,20 +1910,78 @@
         def g(x, y):
             a1 = f(A(x), y, A(x))
             a2 = f(A(x), y, A(x))
+            assert a1.val == a2.val
             b1 = f(B(x), y, B(x))
             b2 = f(B(x), y, B(x))
+            assert b1.val == b2.val
             c1 = f(B(x), y, A(x))
             c2 = f(B(x), y, A(x))
+            assert c1.val == c2.val
             d1 = f(A(x), y, B(x))
             d2 = f(A(x), y, B(x))
-            assert a1.val == a2.val
-            assert b1.val == b2.val
-            assert c1.val == c2.val
             assert d1.val == d2.val
             return a1.val + b1.val + c1.val + d1.val
         res = self.meta_interp(g, [3, 14])
         assert res == g(3, 14)
 
+    def test_failing_inlined_guard(self):
+        myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
+        class Base:
+            def __init__(self, val):
+                self.val = val
+            def getval(self):
+                return self.val
+        class A(Base):
+            def binop(self, other):
+                return A(self.getval() + other.getval())
+        class B(Base):
+            def binop(self, other):
+                return B(self.getval() * other.getval())
+        def f(x, y, z):
+            res = x
+            while y > 0:
+                myjitdriver.can_enter_jit(y=y, x=x, z=z, res=res)
+                myjitdriver.jit_merge_point(y=y, x=x, z=z, res=res)
+                res = res.binop(x)
+                y -= 1
+                if y < 8:
+                    x = z
+            return res
+        def g(x, y):
+            c1 = f(A(x), y, B(x))
+            c2 = f(A(x), y, B(x))
+            assert c1.val == c2.val
+            return c1.val
+        res = self.meta_interp(g, [3, 16])
+        assert res == g(3, 16)
+
+    def test_inlined_guard_in_short_preamble(self):
+        myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
+        class A:
+            def __init__(self, val):
+                self.val = val
+            def getval(self):
+                return self.val
+            def binop(self, other):
+                return A(self.getval() + other.getval())
+        def f(x, y, z):
+            res = x
+            while y > 0:
+                myjitdriver.can_enter_jit(y=y, x=x, z=z, res=res)
+                myjitdriver.jit_merge_point(y=y, x=x, z=z, res=res)
+                res = res.binop(x)
+                y -= 1
+                if y < 7:
+                    x = z
+            return res
+        def g(x, y):
+            a1 = f(A(x), y, A(x))
+            a2 = f(A(x), y, A(x))
+            assert a1.val == a2.val
+            return a1.val
+        res = self.meta_interp(g, [3, 14])
+        assert res == g(3, 14)
+
     def test_specialied_bridge(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
         class A:
@@ -1974,6 +2073,26 @@
         self.check_loops(guard_true=4, guard_class=0, int_add=2, int_mul=2,
                          guard_false=2)
 
+    def test_dont_trace_every_iteration(self):
+        myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa'])
+        
+        def main(a, b):
+            i = sa = 0
+            #while i < 200:
+            while i < 200:
+                myjitdriver.can_enter_jit(a=a, b=b, i=i, sa=sa)
+                myjitdriver.jit_merge_point(a=a, b=b, i=i, sa=sa)
+                if a > 0: pass
+                if b < 2: pass
+                sa += a % b
+                i += 1
+            return sa
+        def g():
+            return main(10, 20) + main(-10, -20)
+        res = self.meta_interp(g, [])
+        assert res == g()
+        self.check_enter_count(3)
+
     def test_current_trace_length(self):
         myjitdriver = JitDriver(greens = ['g'], reds = ['x'])
         @dont_look_inside

diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -198,7 +198,6 @@
 class GuardResOp(ResOpWithDescr):
 
     _fail_args = None
-    _jump_target = None
 
     def getfailargs(self):
         return self._fail_args
@@ -206,22 +205,14 @@
     def setfailargs(self, fail_args):
         self._fail_args = fail_args
 
-    def getjumptarget(self):
-        return self._jump_target
-
-    def setjumptarget(self, jump_target):
-        self._jump_target = jump_target
-
     def copy_and_change(self, opnum, args=None, result=None, descr=None):
         newop = AbstractResOp.copy_and_change(self, opnum, args, result, descr)
         newop.setfailargs(self.getfailargs())
-        newop.setjumptarget(self.getjumptarget())
         return newop
 
     def clone(self):
         newop = AbstractResOp.clone(self)
         newop.setfailargs(self.getfailargs())
-        newop.setjumptarget(self.getjumptarget())        
         return newop
 
 

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
@@ -6,17 +6,19 @@
 from pypy.jit.metainterp.optimizeopt.string import OptString
 from pypy.jit.metainterp.optimizeopt.unroll import optimize_unroll, OptInlineShortPreamble
 
-def optimize_loop_1(metainterp_sd, loop, unroll=True):
+def optimize_loop_1(metainterp_sd, loop, unroll=True, inline_short_preamble=True):
     """Optimize loop.operations to remove internal overheadish operations. 
     """
     opt_str = OptString()
-    optimizations = [OptInlineShortPreamble(),
-                     OptIntBounds(),
+    optimizations = [OptIntBounds(),
                      OptRewrite(),
                      OptVirtualize(),
                      opt_str,
                      OptHeap(),
                     ]
+    if inline_short_preamble:
+        optimizations = [OptInlineShortPreamble()] +  optimizations
+        
     if metainterp_sd.jit_ffi:
         from pypy.jit.metainterp.optimizeopt.fficall import OptFfiCall
         optimizations = optimizations + [
@@ -31,6 +33,6 @@
         optimizer = Optimizer(metainterp_sd, loop, optimizations)
         optimizer.propagate_all_forward()
 
-def optimize_bridge_1(metainterp_sd, bridge):
+def optimize_bridge_1(metainterp_sd, bridge, inline_short_preamble=True):
     """The same, but for a bridge. """
-    optimize_loop_1(metainterp_sd, bridge, False)
+    optimize_loop_1(metainterp_sd, bridge, False, inline_short_preamble)


More information about the Pypy-commit mailing list