Author: Armin Rigo <ar...@tunes.org>
Branch: cffi-handle-lifetime
Changeset: r80141:a698430306bd
Date: 2015-10-12 17:37 +0200
http://bitbucket.org/pypy/pypy/changeset/a698430306bd/

Log:    hg merge default

diff --git a/rpython/annotator/annrpython.py b/rpython/annotator/annrpython.py
--- a/rpython/annotator/annrpython.py
+++ b/rpython/annotator/annrpython.py
@@ -79,14 +79,11 @@
         annmodel.TLS.check_str_without_nul = (
             self.translator.config.translation.check_str_without_nul)
 
-        flowgraph, inputcells = self.get_call_parameters(function, args_s, 
policy)
-        if not isinstance(flowgraph, FunctionGraph):
-            assert isinstance(flowgraph, annmodel.SomeObject)
-            return flowgraph
+        flowgraph, inputs_s = self.get_call_parameters(function, args_s, 
policy)
 
         if main_entry_point:
             self.translator.entry_point_graph = flowgraph
-        return self.build_graph_types(flowgraph, inputcells, 
complete_now=complete_now)
+        return self.build_graph_types(flowgraph, inputs_s, 
complete_now=complete_now)
 
     def get_call_parameters(self, function, args_s, policy):
         desc = self.bookkeeper.getdesc(function)
diff --git a/rpython/jit/backend/arm/opassembler.py 
b/rpython/jit/backend/arm/opassembler.py
--- a/rpython/jit/backend/arm/opassembler.py
+++ b/rpython/jit/backend/arm/opassembler.py
@@ -508,6 +508,21 @@
         self._store_and_reset_exception(self.mc, resloc)
         return fcond
 
+    def emit_op_save_exc_class(self, op, arglocs, regalloc, fcond):
+        resloc = arglocs[0]
+        self.mc.gen_load_int(r.ip.value, self.cpu.pos_exception())
+        self.load_reg(self.mc, resloc, r.ip)
+        return fcond
+
+    def emit_op_save_exception(self, op, arglocs, regalloc, fcond):
+        resloc = arglocs[0]
+        self._store_and_reset_exception(self.mc, resloc)
+        return fcond
+
+    def emit_op_restore_exception(self, op, arglocs, regalloc, fcond):
+        self._restore_exception(self.mc, arglocs[1], arglocs[0])
+        return fcond
+
     def emit_op_debug_merge_point(self, op, arglocs, regalloc, fcond):
         return fcond
     emit_op_jit_debug = emit_op_debug_merge_point
diff --git a/rpython/jit/backend/arm/regalloc.py 
b/rpython/jit/backend/arm/regalloc.py
--- a/rpython/jit/backend/arm/regalloc.py
+++ b/rpython/jit/backend/arm/regalloc.py
@@ -707,6 +707,17 @@
                     [loc, loc1, resloc, pos_exc_value, pos_exception])
         return arglocs
 
+    def prepare_op_save_exception(self, op, fcond):
+        resloc = self.force_allocate_reg(op)
+        return [resloc]
+    prepare_op_save_exc_class = prepare_op_save_exception
+
+    def prepare_op_restore_exception(self, op, fcond):
+        boxes = op.getarglist()
+        loc0 = self.make_sure_var_in_reg(op.getarg(0), boxes)  # exc class
+        loc1 = self.make_sure_var_in_reg(op.getarg(1), boxes)  # exc instance
+        return [loc0, loc1]
+
     def prepare_op_guard_no_exception(self, op, fcond):
         loc = self.make_sure_var_in_reg(ConstInt(self.cpu.pos_exception()))
         arglocs = self._prepare_guard(op, [loc])
diff --git a/rpython/jit/backend/llgraph/runner.py 
b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -45,8 +45,6 @@
                 # we don't care about the value 13 here, because we gonna
                 # fish it from the extra slot on frame anyway
                 op.getdescr().make_a_counter_per_value(op, 13)
-            elif opnum == rop.BRIDGE_EXCEPTION:
-                assert len(self.operations) == 0   # must be first
             if op.getdescr() is not None:
                 if op.is_guard() or op.getopnum() == rop.FINISH:
                     newdescr = op.getdescr()
@@ -906,8 +904,9 @@
             values.append(value)
         if hasattr(descr, '_llgraph_bridge'):
             if propagate_exception:
-                assert (descr._llgraph_bridge.operations[0].opnum ==
-                        rop.BRIDGE_EXCEPTION)
+                assert (descr._llgraph_bridge.operations[0].opnum in
+                        (rop.SAVE_EXC_CLASS, rop.GUARD_EXCEPTION,
+                         rop.GUARD_NO_EXCEPTION))
             target = (descr._llgraph_bridge, -1)
             values = [value for value in values if value is not None]
             raise Jump(target, values)
@@ -1229,8 +1228,32 @@
     def execute_keepalive(self, descr, x):
         pass
 
-    def execute_bridge_exception(self, descr):
-        pass
+    def execute_save_exc_class(self, descr):
+        lle = self.last_exception
+        if lle is None:
+            return 0
+        else:
+            return support.cast_to_int(lle.args[0])
+
+    def execute_save_exception(self, descr):
+        lle = self.last_exception
+        if lle is None:
+            res = lltype.nullptr(llmemory.GCREF.TO)
+        else:
+            res = lltype.cast_opaque_ptr(llmemory.GCREF, lle.args[1])
+        self.last_exception = None
+        return res
+
+    def execute_restore_exception(self, descr, kls, e):
+        kls = heaptracker.int2adr(kls)
+        if e:
+            value = lltype.cast_opaque_ptr(rclass.OBJECTPTR, e)
+            assert llmemory.cast_ptr_to_adr(value.typeptr) == kls
+            lle = LLException(value.typeptr, e)
+        else:
+            assert kls == llmemory.NULL
+            lle = None
+        self.last_exception = lle
 
 
 def _getdescr(op):
diff --git a/rpython/jit/backend/llsupport/rewrite.py 
b/rpython/jit/backend/llsupport/rewrite.py
--- a/rpython/jit/backend/llsupport/rewrite.py
+++ b/rpython/jit/backend/llsupport/rewrite.py
@@ -119,6 +119,7 @@
         # barriers.  We do this on each "basic block" of operations, which in
         # this case means between CALLs or unknown-size mallocs.
         #
+        operations = self.remove_bridge_exception(operations)
         for i in range(len(operations)):
             op = operations[i]
             assert op.get_forwarded() is None
@@ -168,9 +169,6 @@
                 continue
             if op.getopnum() == rop.JUMP or op.getopnum() == rop.FINISH:
                 self.emit_pending_zeros()
-            if op.getopnum() == rop.BRIDGE_EXCEPTION:
-                self.remove_bridge_exception(operations, i)
-                continue
             #
             self.emit_op(op)
         return self._newops
@@ -686,13 +684,17 @@
             size = max(size, 2 * WORD)
             return (size + WORD-1) & ~(WORD-1)     # round up
 
-    def remove_bridge_exception(self, operations, i):
-        """Check that the 'bridge_exception' operation occurs at the
-        start of the bridge."""
-        if i == 0:
-            return     # first operation, ok
-        if i == 1 and operations[0].getopnum() == rop.INCREMENT_DEBUG_COUNTER:
-            return     # 2nd operation after INCREMENT_DEBUG_COUNTER, ok
-        # not ok!
-        assert we_are_translated()
-        raise BridgeExceptionNotFirst
+    def remove_bridge_exception(self, operations):
+        """Check a common case: 'save_exception' immediately followed by
+        'restore_exception' at the start of the bridge."""
+        # XXX should check if the boxes are used later; but we just assume
+        # they aren't for now
+        start = 0
+        if operations[0].getopnum() == rop.INCREMENT_DEBUG_COUNTER:
+            start = 1
+        if len(operations) >= start + 3:
+            if (operations[start+0].getopnum() == rop.SAVE_EXC_CLASS and
+                operations[start+1].getopnum() == rop.SAVE_EXCEPTION and
+                operations[start+2].getopnum() == rop.RESTORE_EXCEPTION):
+                return operations[:start] + operations[start+3:]
+        return operations
diff --git a/rpython/jit/backend/test/runner_test.py 
b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -2099,6 +2099,60 @@
         excvalue = self.cpu.grab_exc_value(deadframe)
         assert not excvalue
 
+    def test_save_restore_exceptions(self):
+        exc_tp = None
+        exc_ptr = None
+        def func(i):
+            if hasattr(self.cpu, '_exception_emulator'):
+                assert not self.cpu._exception_emulator[0]
+                assert not self.cpu._exception_emulator[1]
+            called.append(i)
+            if i:
+                raise LLException(exc_tp, exc_ptr)
+
+        ops = '''
+        [i0]
+        i1 = same_as_i(1)
+        call_n(ConstClass(fptr), i0, descr=calldescr)
+        i2 = save_exc_class()
+        p2 = save_exception()
+        call_n(ConstClass(fptr), 0, descr=calldescr)
+        restore_exception(i2, p2)
+        p0 = guard_exception(ConstClass(xtp)) [i1]
+        finish(p0)
+        '''
+        FPTR = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void))
+        fptr = llhelper(FPTR, func)
+        calldescr = self.cpu.calldescrof(FPTR.TO, FPTR.TO.ARGS, FPTR.TO.RESULT,
+                                         EffectInfo.MOST_GENERAL)
+
+        xtp = lltype.malloc(rclass.OBJECT_VTABLE, immortal=True)
+        xtp.subclassrange_min = 1
+        xtp.subclassrange_max = 3
+        X = lltype.GcStruct('X', ('parent', rclass.OBJECT),
+                            hints={'vtable':  xtp._obj})
+        xx = lltype.malloc(X)
+        xx.parent.typeptr = xtp
+        xptr = lltype.cast_opaque_ptr(llmemory.GCREF, xx)
+
+        exc_tp = xtp
+        exc_ptr = xptr
+        loop = parse(ops, self.cpu, namespace=locals())
+        looptoken = JitCellToken()
+        self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+        called = []
+        deadframe = self.cpu.execute_token(looptoken, 5)
+        assert called == [5, 0]
+        assert self.cpu.get_ref_value(deadframe, 0) == xptr
+        excvalue = self.cpu.grab_exc_value(deadframe)
+        assert not excvalue
+        called = []
+        deadframe = self.cpu.execute_token(looptoken, 0)
+        assert called == [0, 0]
+        assert self.cpu.get_int_value(deadframe, 0) == 1
+        excvalue = self.cpu.grab_exc_value(deadframe)
+        assert not excvalue
+
     def test_cond_call_gc_wb(self):
         def func_void(a):
             record.append(rffi.cast(lltype.Signed, a))
diff --git a/rpython/jit/backend/x86/assembler.py 
b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -1609,6 +1609,15 @@
         self.implement_guard(guard_token)
         self._store_and_reset_exception(self.mc, resloc)
 
+    def genop_save_exc_class(self, op, arglocs, resloc):
+        self.mc.MOV(resloc, heap(self.cpu.pos_exception()))
+
+    def genop_save_exception(self, op, arglocs, resloc):
+        self._store_and_reset_exception(self.mc, resloc)
+
+    def genop_discard_restore_exception(self, op, arglocs):
+        self._restore_exception(self.mc, arglocs[1], arglocs[0])
+
     def _store_and_reset_exception(self, mc, excvalloc=None, exctploc=None,
                                    tmploc=None):
         """ Resest the exception. If excvalloc is None, then store it on the
diff --git a/rpython/jit/backend/x86/regalloc.py 
b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -418,6 +418,17 @@
         self.perform_guard(op, [loc, loc1], resloc)
         self.rm.possibly_free_var(box)
 
+    def consider_save_exception(self, op):
+        resloc = self.rm.force_allocate_reg(op)
+        self.perform(op, [], resloc)
+    consider_save_exc_class = consider_save_exception
+
+    def consider_restore_exception(self, op):
+        args = op.getarglist()
+        loc0 = self.rm.make_sure_var_in_reg(op.getarg(0), args)  # exc class
+        loc1 = self.rm.make_sure_var_in_reg(op.getarg(1), args)  # exc instance
+        self.perform_discard(op, [loc0, loc1])
+
     consider_guard_no_overflow = consider_guard_no_exception
     consider_guard_overflow    = consider_guard_no_exception
     consider_guard_not_forced  = consider_guard_no_exception
diff --git a/rpython/jit/metainterp/executor.py 
b/rpython/jit/metainterp/executor.py
--- a/rpython/jit/metainterp/executor.py
+++ b/rpython/jit/metainterp/executor.py
@@ -386,7 +386,9 @@
                          rop.CALL_MALLOC_NURSERY_VARSIZE_FRAME,
                          rop.NURSERY_PTR_INCREMENT,
                          rop.LABEL,
-                         rop.BRIDGE_EXCEPTION,
+                         rop.SAVE_EXC_CLASS,
+                         rop.SAVE_EXCEPTION,
+                         rop.RESTORE_EXCEPTION,
                          ):      # list of opcodes never executed by pyjitpl
                 continue
             raise AssertionError("missing %r" % (key,))
diff --git a/rpython/jit/metainterp/pyjitpl.py 
b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -2487,17 +2487,28 @@
             # 'test_guard_no_exception_incorrectly_removed_from_bridge'
             # shows a corner case in which just putting GuARD_NO_EXCEPTION
             # here is a bad idea: the optimizer might remove it too.
-            # So we put a pair BRIDGE_EXCEPTION / GUARD_(NO)_EXCEPTION.
-            # The BRIDGE_EXCEPTION is meant to re-raise the exception
-            # caught before the bridge, but in reality it must end up
-            # as the first operation and thus is a no-op for the backends
-            # (it is removed in rewrite.py).  Its real purpose is only to
-            # pass through the optimizer unmodified, so that the following
-            # GUARD_NO_EXCEPTION is not killed.
-            self.history.record(rop.BRIDGE_EXCEPTION, [], None)
-            if exception:
-                self.execute_ll_raised(lltype.cast_opaque_ptr(rclass.OBJECTPTR,
-                                                              exception))
+            # So we put a SAVE_EXCEPTION at the start, and a
+            # RESTORE_EXCEPTION just before the guard.  (rewrite.py will
+            # remove the two if they end up consecutive.)
+
+            # XXX too much jumps between older and newer models; clean up
+            # by killing SAVE_EXC_CLASS, RESTORE_EXCEPTION and GUARD_EXCEPTION
+
+            exception_obj = lltype.cast_opaque_ptr(rclass.OBJECTPTR, exception)
+            if exception_obj:
+                exc_class = heaptracker.adr2int(
+                    llmemory.cast_ptr_to_adr(exception_obj.typeptr))
+            else:
+                exc_class = 0
+            i = len(self.history.operations)
+            op1 = self.history.record(rop.SAVE_EXC_CLASS, [], exc_class)
+            op2 = self.history.record(rop.SAVE_EXCEPTION, [], exception)
+            assert op1 is self.history.operations[i]
+            assert op2 is self.history.operations[i + 1]
+            self.history.operations = [op1, op2] + self.history.operations[:i]
+            self.history.record(rop.RESTORE_EXCEPTION, [op1, op2], None)
+            if exception_obj:
+                self.execute_ll_raised(exception_obj)
             else:
                 self.clear_exception()
             try:
diff --git a/rpython/jit/metainterp/resoperation.py 
b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -696,7 +696,7 @@
     'GUARD_SUBCLASS/2d/n',      # only if supports_guard_gc_type
     '_GUARD_FOLDABLE_LAST',
     'GUARD_NO_EXCEPTION/0d/n',   # may be called with an exception currently 
set
-    'GUARD_EXCEPTION/1d/r',     # may be called with an exception currently set
+    'GUARD_EXCEPTION/1d/r',     # XXX kill me, use only SAVE_EXCEPTION
     'GUARD_NO_OVERFLOW/0d/n',
     'GUARD_OVERFLOW/0d/n',
     'GUARD_NOT_FORCED/0d/n',      # may be called with an exception currently 
set
@@ -827,7 +827,9 @@
     'QUASIIMMUT_FIELD/1d/n',    # [objptr], descr=SlowMutateDescr
     'RECORD_EXACT_CLASS/2/n',   # [objptr, clsptr]
     'KEEPALIVE/1/n',
-    'BRIDGE_EXCEPTION/0/n',     # pyjitpl: prepare_resume_from_failure()
+    'SAVE_EXCEPTION/0/r',
+    'SAVE_EXC_CLASS/0/i',       # XXX kill me
+    'RESTORE_EXCEPTION/2/n',    # XXX kill me
 
     '_CANRAISE_FIRST', # ----- start of can_raise operations -----
     '_CALL_FIRST',
diff --git a/rpython/rlib/rvmprof/cintf.py b/rpython/rlib/rvmprof/cintf.py
--- a/rpython/rlib/rvmprof/cintf.py
+++ b/rpython/rlib/rvmprof/cintf.py
@@ -92,12 +92,13 @@
         PLT = ""
         size_decl = ""
         type_decl = ""
+        extra_align = ""
     else:
         PLT = "@PLT"
         type_decl = "\t.type\t%s, @function" % (tramp_name,)
         size_decl = "\t.size\t%s, .-%s" % (
             tramp_name, tramp_name)
-
+        extra_align = "\t.cfi_def_cfa_offset 8"
 
     assert detect_cpu.autodetect().startswith(detect_cpu.MODEL_X86_64), (
         "rvmprof only supports x86-64 CPUs for now")
@@ -124,15 +125,17 @@
     #       that don't start with \t are silently ignored (<arigato>: WAT!?)
     target.write("""\
 \t.text
+\t.section\t__TEXT,__text,regular,pure_instructions
 \t.globl\t%(tramp_name)s
+\t.align\t4, 0x90
 %(type_decl)s
 %(tramp_name)s:
 \t.cfi_startproc
 \tpushq\t%(reg)s
 \t.cfi_def_cfa_offset 16
 \tcall %(cont_name)s%(PLT)s
+%(extra_align)s
 \taddq\t$8, %%rsp
-\t.cfi_def_cfa_offset 8
 \tret
 \t.cfi_endproc
 %(size_decl)s
diff --git a/rpython/rlib/rvmprof/src/vmprof_main.h 
b/rpython/rlib/rvmprof/src/vmprof_main.h
--- a/rpython/rlib/rvmprof/src/vmprof_main.h
+++ b/rpython/rlib/rvmprof/src/vmprof_main.h
@@ -31,7 +31,11 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include "vmprof_getpc.h"
+#ifdef __APPLE__
+#include "libunwind.h"
+#else
 #include "vmprof_unwind.h"
+#endif
 #include "vmprof_mt.h"
 
 
@@ -39,10 +43,12 @@
 
 // functions copied from libunwind using dlopen
 
+#ifndef __APPLE__ // should be linux only probably
 static int (*unw_get_reg)(unw_cursor_t*, int, unw_word_t*) = NULL;
 static int (*unw_step)(unw_cursor_t*) = NULL;
 static int (*unw_init_local)(unw_cursor_t *, unw_context_t *) = NULL;
 static int (*unw_get_proc_info)(unw_cursor_t *, unw_proc_info_t *) = NULL;
+#endif
 
 static int profile_file = -1;
 static long prepare_interval_usec;
@@ -67,6 +73,7 @@
         return "bad value for 'interval'";
     prepare_interval_usec = (int)(interval * 1000000.0);
 
+#ifndef __APPLE__
     if (!unw_get_reg) {
         void *libhandle;
 
@@ -81,6 +88,7 @@
         if (!(unw_step = dlsym(libhandle, UNW_PREFIX  "_step")))
             goto error;
     }
+#endif
     if (prepare_concurrent_bufs() < 0)
         return "out of memory";
 
@@ -206,7 +214,12 @@
     void *ip;
     int n = 0;
     unw_cursor_t cursor;
+#ifdef __APPLE__
+    unw_context_t uc;
+    unw_getcontext(&uc);
+#else
     unw_context_t uc = *ucontext;
+#endif
 
     int ret = unw_init_local(&cursor, &uc);
     assert(ret >= 0);
diff --git a/rpython/rlib/rvmprof/src/vmprof_unwind.h 
b/rpython/rlib/rvmprof/src/vmprof_unwind.h
--- a/rpython/rlib/rvmprof/src/vmprof_unwind.h
+++ b/rpython/rlib/rvmprof/src/vmprof_unwind.h
@@ -64,8 +64,7 @@
 typedef struct unw_cursor
   {
     unw_word_t opaque[UNW_TDEP_CURSOR_LEN];
-  }
-unw_cursor_t;
+  } unw_cursor_t;
 
 #define UNW_REG_IP UNW_X86_64_RIP
 #define UNW_REG_SP UNW_X86_64_RSP
@@ -84,7 +83,7 @@
     int format;                        /* unwind-info format (arch-specific) */
     int unwind_info_size;      /* size of the information (if applicable) */
     void *unwind_info;         /* unwind-info (arch-specific) */
-  }
-unw_proc_info_t;
+  } unw_proc_info_t;
 
 // end of copy
+
diff --git a/rpython/rlib/rvmprof/test/test_rvmprof.py 
b/rpython/rlib/rvmprof/test/test_rvmprof.py
--- a/rpython/rlib/rvmprof/test/test_rvmprof.py
+++ b/rpython/rlib/rvmprof/test/test_rvmprof.py
@@ -2,6 +2,7 @@
 from rpython.tool.udir import udir
 from rpython.rlib import rvmprof
 from rpython.translator.c.test.test_genc import compile
+from rpython.rlib.objectmodel import we_are_translated
 
 
 def test_vmprof_execute_code_1():
@@ -96,7 +97,12 @@
     @rvmprof.vmprof_execute_code("xcode1", lambda code, num: code)
     def main(code, num):
         print num
-        return 42
+        s = 0
+        for i in range(num):
+            s += (i << 1)
+            if s % 32423423423 == 0:
+                print s
+        return s
 
     tmpfilename = str(udir.join('test_rvmprof'))
 
@@ -104,16 +110,37 @@
         code = MyCode()
         rvmprof.register_code(code, get_name)
         fd = os.open(tmpfilename, os.O_WRONLY | os.O_CREAT, 0666)
-        rvmprof.enable(fd, 0.5)
-        res = main(code, 5)
-        assert res == 42
+        if we_are_translated():
+            num = 100000000
+            period = 0.0001
+        else:
+            num = 10000
+            period = 0.9
+        rvmprof.enable(fd, period)
+        res = main(code, num)
+        #assert res == 499999500000
         rvmprof.disable()
         os.close(fd)
         return 0
 
+    def check_profile(filename):
+        from vmprof import read_profile
+
+        prof = read_profile(filename)
+        assert prof.get_tree().name.startswith("py:")
+        assert prof.get_tree().count
+
     assert f() == 0
     assert os.path.exists(tmpfilename)
     fn = compile(f, [], gcpolicy="minimark")
-    os.unlink(tmpfilename)
     assert fn() == 0
-    assert os.path.exists(tmpfilename)
+    try:
+        import vmprof
+    except ImportError:
+        py.test.skip("vmprof unimportable")
+    else:
+        check_profile(tmpfilename)
+    finally:
+        assert os.path.exists(tmpfilename)
+        os.unlink(tmpfilename)
+       
\ No newline at end of file
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to