Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r92345:f70ed7c5cc49 Date: 2017-09-07 22:54 +0200 http://bitbucket.org/pypy/pypy/changeset/f70ed7c5cc49/
Log: merge heads diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -1629,12 +1629,15 @@ # return text_w(w_obj) or None return None if self.is_none(w_obj) else self.text_w(w_obj) + @specialize.argtype(1) def bytes_w(self, w_obj): """ Takes an application level :py:class:`bytes` (on PyPy2 this equals `str`) and returns a rpython byte string. """ + assert w_obj is not None return w_obj.str_w(self) + @specialize.argtype(1) def text_w(self, w_obj): """ PyPy2 takes either a :py:class:`str` and returns a rpython byte string, or it takes an :py:class:`unicode` @@ -1644,6 +1647,7 @@ On PyPy3 it takes a :py:class:`str` and it will return an utf-8 encoded rpython string. """ + assert w_obj is not None return w_obj.str_w(self) @not_rpython # tests only; should be replaced with bytes_w or text_w @@ -1692,6 +1696,7 @@ raise oefmt(self.w_ValueError, "byte must be in range(0, 256)") return chr(value) + @specialize.argtype(1) def int_w(self, w_obj, allow_conversion=True): """ Unwrap an app-level int object into an interpret-level int. @@ -1704,26 +1709,35 @@ If allow_conversion=False, w_obj needs to be an app-level int or a subclass. """ + assert w_obj is not None return w_obj.int_w(self, allow_conversion) + @specialize.argtype(1) def int(self, w_obj): + assert w_obj is not None return w_obj.int(self) + @specialize.argtype(1) def uint_w(self, w_obj): + assert w_obj is not None return w_obj.uint_w(self) + @specialize.argtype(1) def bigint_w(self, w_obj, allow_conversion=True): """ Like int_w, but return a rlib.rbigint object and call __long__ if allow_conversion is True. """ + assert w_obj is not None return w_obj.bigint_w(self, allow_conversion) + @specialize.argtype(1) def float_w(self, w_obj, allow_conversion=True): """ Like int_w, but return an interp-level float and call __float__ if allow_conversion is True. """ + assert w_obj is not None return w_obj.float_w(self, allow_conversion) def realtext_w(self, w_obj): @@ -1733,7 +1747,9 @@ raise oefmt(self.w_TypeError, "argument must be a string") return self.bytes_w(w_obj) + @specialize.argtype(1) def unicode_w(self, w_obj): + assert w_obj is not None return w_obj.unicode_w(self) def unicode0_w(self, w_obj): @@ -1758,7 +1774,9 @@ # This is here mostly just for gateway.int_unwrapping_space_method(). return bool(self.int_w(w_obj)) + @specialize.argtype(1) def ord(self, w_obj): + assert w_obj is not None return w_obj.ord(self) # This is all interface for gateway.py. 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 @@ -40,6 +40,7 @@ from rpython.rlib import rawrefcount from rpython.rlib import rthread from rpython.rlib.debug import fatalerror_notb +from rpython.rlib import rstackovf from pypy.objspace.std.typeobject import W_TypeObject, find_best_base from pypy.module.cpyext.cparser import CTypeSpace @@ -940,6 +941,11 @@ message = str(e) state.set_exception(OperationError(space.w_SystemError, space.newtext(message))) + except rstackovf.StackOverflow as e: + rstackovf.check_stack_overflow() + failed = True + state.set_exception(OperationError(space.w_RuntimeError, + space.newtext("maximum recursion depth exceeded"))) else: failed = False diff --git a/rpython/jit/codewriter/call.py b/rpython/jit/codewriter/call.py --- a/rpython/jit/codewriter/call.py +++ b/rpython/jit/codewriter/call.py @@ -185,6 +185,27 @@ FUNC.RESULT, EffectInfo.MOST_GENERAL) return (fnaddr, calldescr) + def _raise_effect_error(self, op, extraeffect, functype, calling_graph): + explanation = [] + if extraeffect == EffectInfo.EF_RANDOM_EFFECTS: + explanation = self.randomeffects_analyzer.explain_analyze_slowly(op) + elif extraeffect == EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE: + explanation = self.virtualizable_analyzer.explain_analyze_slowly(op) + msg = [] + if explanation: + msg = [ + "_______ ERROR AT BOTTOM ______", + "RPython callstack leading to problem:", + ] + msg.extend(explanation) + msg.append("_______ ERROR: ______") + msg.append("operation %r" % op) + msg.append("in graph %s" % (calling_graph or "<unknown>")) + msg.append("this calls a %s function," % (functype, )) + msg.append(" but this contradicts other sources (e.g. it can have random" + " effects): EF=%s" % (extraeffect, )) + raise Exception("\n".join(msg)) + def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE, extraeffect=None, extradescr=None, calling_graph=None): @@ -278,18 +299,13 @@ # check that the result is really as expected if loopinvariant: if extraeffect != EffectInfo.EF_LOOPINVARIANT: - raise Exception( - "operation %r in %s: this calls a _jit_loop_invariant_ function," - " but this contradicts other sources (e.g. it can have random" - " effects): EF=%s" % (op, calling_graph, extraeffect)) + self._raise_effect_error(op, extraeffect, "_jit_loop_invariant_", calling_graph) if elidable: if extraeffect not in (EffectInfo.EF_ELIDABLE_CANNOT_RAISE, EffectInfo.EF_ELIDABLE_OR_MEMORYERROR, EffectInfo.EF_ELIDABLE_CAN_RAISE): - raise Exception( - "operation %r in %s: this calls an elidable function," - " but this contradicts other sources (e.g. it can have random" - " effects): EF=%s" % (op, calling_graph, extraeffect)) + + self._raise_effect_error(op, extraeffect, "elidable", calling_graph) elif RESULT is lltype.Void: raise Exception( "operation %r in %s: this calls an elidable function " diff --git a/rpython/jit/codewriter/test/test_call.py b/rpython/jit/codewriter/test/test_call.py --- a/rpython/jit/codewriter/test/test_call.py +++ b/rpython/jit/codewriter/test/test_call.py @@ -299,11 +299,23 @@ def f4(n, m): return compute_hash(str(n) + str(m)) + T = rffi.CArrayPtr(rffi.TIME_T) + external = rffi.llexternal("time", [T], rffi.TIME_T, releasegil=True) + + def effect(): + return external(lltype.nullptr(T.TO)) + + @jit.elidable + def f5(n, m): + effect() + return 1 + def f(n, m): a = f1(n, m) b = f2(n, m) c = f3(n, m) d = f4(n, m) + f5(n, m) enable_siphash24() return a + len(b) + c + d @@ -323,6 +335,14 @@ call_descr = cc.getcalldescr(call_op) assert call_descr.extrainfo.extraeffect == expected + call_op = f_graph.startblock.operations[4] + assert call_op.opname == 'direct_call' + excinfo = py.test.raises(Exception, cc.getcalldescr, call_op) + lines = excinfo.value.args[0].splitlines() + assert "f5" in lines[2] + assert "effect" in lines[3] + assert "random effects" in lines[-1] + def test_raise_elidable_no_result(): from rpython.jit.backend.llgraph.runner import LLGraphCPU l = [] diff --git a/rpython/translator/backendopt/graphanalyze.py b/rpython/translator/backendopt/graphanalyze.py --- a/rpython/translator/backendopt/graphanalyze.py +++ b/rpython/translator/backendopt/graphanalyze.py @@ -4,6 +4,7 @@ class GraphAnalyzer(object): verbose = False + explanation = None def __init__(self, translator): self.translator = translator @@ -73,6 +74,20 @@ def compute_graph_info(self, graph): return None + def explain_analyze_slowly(self, op): + # this is a hack! usually done before a crash + self.__init__(self.translator) + self.explanation = explanation = [] + oldverbose = self.verbose + self.verbose = True + try: + self.analyze(op) + finally: + del self.explanation + self.verbose = oldverbose + explanation.reverse() + return explanation + def analyze(self, op, seen=None, graphinfo=None): if op.opname == "direct_call": try: @@ -113,7 +128,11 @@ return x def dump_info(self, info): - print '[%s] %s' % (self.__class__.__name__, info) + st = '[%s] %s' % (self.__class__.__name__, info) + if self.explanation is not None: + self.explanation.append(st) + else: + print st def analyze_direct_call(self, graph, seen=None): if seen is None: diff --git a/rpython/translator/backendopt/test/test_writeanalyze.py b/rpython/translator/backendopt/test/test_writeanalyze.py --- a/rpython/translator/backendopt/test/test_writeanalyze.py +++ b/rpython/translator/backendopt/test/test_writeanalyze.py @@ -531,3 +531,37 @@ typed_effects = self._analyze_graph(t, wa, typed_write) typed_effects = self._filter_reads(typed_effects) assert typed_effects == direct_effects + + def test_explanation(self): + class A(object): + def methodname(self): + self.x = 1 + return 1 + def m(self): + raise ValueError + class B(A): + def methodname(self): + return 2 + def m(self): + return 3 + def fancyname(a): + return a.methodname() + def m(a): + return a.m() + def h(flag): + if flag: + obj = A() + else: + obj = B() + fancyname(obj) + m(obj) + + t, wa = self.translate(h, [int]) + hgraph = graphof(t, h) + # fiiiish :-( + block = hgraph.startblock.exits[0].target.exits[0].target + op_call_fancyname = block.operations[0] + + explanation = wa.explain_analyze_slowly(op_call_fancyname) + assert "fancyname" in explanation[0] + assert "methodname" in explanation[1] _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit