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