def rtype(self, fn, argtypes, resulttype, checkfunction=None): t = TranslationContext() a = t.buildannotator() a.build_types(prefn, [int]) typer = t.buildrtyper() typer.specialize() #t.view() s_result = a.typeannotation(resulttype) from rpython.rtyper import annlowlevel # annotate, normalize and rtype fn after the fact annhelper = annlowlevel.MixLevelHelperAnnotator(typer) graph = annhelper.getgraph(fn, [a.typeannotation(argtype) for argtype in argtypes], s_result) annhelper.finish() t.checkgraphs() if checkfunction is not None: checkfunction(t) # sanity check prefn llinterp = LLInterpreter(typer) res = llinterp.eval_graph(graphof(t, prefn), [1]) assert res == 100 res = llinterp.eval_graph(graphof(t, prefn), [2]) assert res == 201 return t
def test_cancollect_external(): fext1 = rffi.llexternal('fext1', [], lltype.Void, releasegil=False) def g(): fext1() t = rtype(g, []) gg = graphof(t, g) assert not CollectAnalyzer(t).analyze_direct_call(gg) fext2 = rffi.llexternal('fext2', [], lltype.Void, releasegil=True) def g(): fext2() t = rtype(g, []) gg = graphof(t, g) assert CollectAnalyzer(t).analyze_direct_call(gg) S = lltype.GcStruct('S', ('x', lltype.Signed)) FUNC = lltype.Ptr(lltype.FuncType([lltype.Signed], lltype.Void)) fext3 = rffi.llexternal('fext3', [FUNC], lltype.Void, releasegil=False) def h(x): lltype.malloc(S, zero=True) def g(): fext3(h) t = rtype(g, []) gg = graphof(t, g) assert CollectAnalyzer(t).analyze_direct_call(gg)
def test_add_more_subclasses(self): from rpython.rtyper import rclass from rpython.rtyper.lltypesystem.rclass import ll_issubclass from rpython.rtyper.lltypesystem.rclass import CLASSTYPE class Sub3(PBase): def newmethod(self): return 3 def dummyfn(n): x = Sub3() return x.newmethod() def checkfunction(translator): # make sure that there is a sensible comparison defined on the # symbolics bk = translator.annotator.bookkeeper rtyper = translator.rtyper base_classdef = bk.getuniqueclassdef(PBase) base_vtable = rclass.getclassrepr(rtyper, base_classdef).getruntime(CLASSTYPE) sub3_classdef = bk.getuniqueclassdef(Sub3) sub3_vtable = rclass.getclassrepr(rtyper, sub3_classdef).getruntime(CLASSTYPE) assert ll_issubclass(sub3_vtable, base_vtable) assert not ll_issubclass(base_vtable, sub3_vtable) translator = self.rtype(dummyfn, [int], int, checkfunction) base_graph = graphof(translator, PBase.fn.im_func) sub1_graph = graphof(translator, PSub1.fn.im_func) sub2_graph = graphof(translator, PSub2.fn.im_func) sub3_graph = graphof(translator, Sub3.fn.im_func) dummyfn_graph = graphof(translator, dummyfn) assert base_graph.getreturnvar().concretetype == lltype.Signed assert sub1_graph.getreturnvar().concretetype == lltype.Signed assert sub2_graph.getreturnvar().concretetype == lltype.Signed assert sub3_graph.getreturnvar().concretetype == lltype.Signed assert dummyfn_graph.getreturnvar().concretetype == lltype.Signed
def test_memoryerror(self): def f(x): return [x, 42] t, ra = self.translate(f, [int]) result = ra.analyze_direct_call(graphof(t, f)) assert result # ra = RaiseAnalyzer(t) ra.do_ignore_memory_error() result = ra.analyze_direct_call(graphof(t, f)) assert not result # def g(x): try: return f(x) except: raise t, ra = self.translate(g, [int]) ra.do_ignore_memory_error() result = ra.analyze_direct_call(graphof(t, g)) assert not result # def h(x): return {5:6}[x] t, ra = self.translate(h, [int]) ra.do_ignore_memory_error() # but it's potentially a KeyError result = ra.analyze_direct_call(graphof(t, h)) assert result
def test_llexternal(self): from rpython.rtyper.lltypesystem.rffi import llexternal from rpython.rtyper.lltypesystem import lltype z = llexternal('z', [lltype.Signed], lltype.Signed) def f(x): return z(x) t, ra = self.translate(f, [int]) fgraph = graphof(t, f) backend_optimizations(t) assert fgraph.startblock.operations[0].opname == 'direct_call' result = ra.can_raise(fgraph.startblock.operations[0]) assert not result z = lltype.functionptr(lltype.FuncType([lltype.Signed], lltype.Signed), 'foobar') def g(x): return z(x) t, ra = self.translate(g, [int]) ggraph = graphof(t, g) assert ggraph.startblock.operations[0].opname == 'direct_call' result = ra.can_raise(ggraph.startblock.operations[0]) assert result
def check_inline(self, func, in_func, sig, entry=None, inline_guarded_calls=False, graph=False): if entry is None: entry = in_func t = self.translate(entry, sig) # inline! sanity_check(t) # also check before inlining (so we don't blame it) if option.view: t.view() raise_analyzer = canraise.RaiseAnalyzer(t) inliner = Inliner( t, graphof(t, in_func), func, t.rtyper.lltype_to_classdef_mapping(), inline_guarded_calls, raise_analyzer=raise_analyzer, ) inliner.inline_all() if option.view: t.view() sanity_check(t) interp = LLInterpreter(t.rtyper) def eval_func(args): return interp.eval_graph(graphof(t, entry), args) if graph: return eval_func, graphof(t, func) return eval_func
def test_normalize_f2_as_taking_string_argument(self): def f1(l1): pass def f2(l2): pass def g(n): if n > 0: f1("123") f = f1 else: f2("b") f = f2 f("a") # The call table looks like: # # FuncDesc(f1) FuncDesc(f2) # -------------------------------------------- # line g+2: graph1 # line g+5: graph2 # line g+7: graph1 graph2 # # But all lines get compressed to a single line. translator = self.rtype(g, [int], annmodel.s_None) f1graph = graphof(translator, f1) f2graph = graphof(translator, f2) s_l1 = translator.annotator.binding(f1graph.getargs()[0]) s_l2 = translator.annotator.binding(f2graph.getargs()[0]) assert s_l1.__class__ == annmodel.SomeString # and not SomeChar assert s_l2.__class__ == annmodel.SomeString # and not SomeChar
def test_multiple_calls(): class A: pass class B(A): pass def g2(b, i): b.i = h(i) def g1(a, b, i): a.b = b g2(b, h(i)) return a.b.i def h(x): return x + 42 def fn(i): a = A() b = B() x = h(i) return g1(a, b, x) t, graph = rtype(fn, [int]) callgraph, caller_candidates = check_inlining(t, graph, [0], 3 * 42) print callgraph assert caller_candidates == {graph: True} assert len(callgraph) == 1 g1graph = graphof(t, g1) g2graph = graphof(t, g2) assert callgraph == {graph: {g1graph: True}} callgraph, caller_candidates = check_inlining(t, graph, [0], 3 * 42) assert callgraph == {graph: {g2graph: True}}
def test_normalize_abstract_method(self): class Base: def fn(self): raise NotImplementedError class Sub1(Base): def fn(self): return 1 class Sub2(Base): def fn(self): return -2 def dummyfn(n): if n == 1: x = Sub1() else: x = Sub2() return x.fn() translator = self.rtype(dummyfn, [int], int) base_graph = graphof(translator, Base.fn.im_func) sub1_graph = graphof(translator, Sub1.fn.im_func) sub2_graph = graphof(translator, Sub2.fn.im_func) assert base_graph.getreturnvar().concretetype == lltype.Signed assert sub1_graph.getreturnvar().concretetype == lltype.Signed assert sub2_graph.getreturnvar().concretetype == lltype.Signed llinterp = LLInterpreter(translator.rtyper) res = llinterp.eval_graph(graphof(translator, dummyfn), [1]) assert res == 1 res = llinterp.eval_graph(graphof(translator, dummyfn), [2]) assert res == -2
def test_half_exceptiontransformed_graphs(): from rpython.translator import exceptiontransform def f1(x): if x < 0: raise ValueError return 754 def g1(x): try: return f1(x) except ValueError: return 5 def f2(x): if x < 0: raise ValueError return 21 def g2(x): try: return f2(x) except ValueError: return 6 f3 = lltype.functionptr(lltype.FuncType([lltype.Signed], lltype.Signed), "f3", _callable=f1) def g3(x): try: return f3(x) except ValueError: return 7 def f(flag, x): if flag == 1: return g1(x) elif flag == 2: return g2(x) else: return g3(x) t = TranslationContext() t.buildannotator().build_types(f, [int, int]) t.buildrtyper().specialize() etrafo = exceptiontransform.ExceptionTransformer(t) etrafo.create_exception_handling(graphof(t, f1)) etrafo.create_exception_handling(graphof(t, g2)) etrafo.create_exception_handling(graphof(t, g3)) graph = graphof(t, f) interp = LLInterpreter(t.rtyper) res = interp.eval_graph(graph, [1, -64]) assert res == 5 res = interp.eval_graph(graph, [2, -897]) assert res == 6 res = interp.eval_graph(graph, [3, -9831]) assert res == 7
def test_annotate_r_dict(): t = TranslationContext() a = t.buildannotator() a.build_types(func_r_dict, []) #t.view() graph = graphof(t, strange_key_eq) assert a.binding(graph.getargs()[0]).knowntype == str assert a.binding(graph.getargs()[1]).knowntype == str graph = graphof(t, strange_key_hash) assert a.binding(graph.getargs()[0]).knowntype == str
def test_cancollect(): S = lltype.GcStruct('S', ('x', lltype.Signed)) def g(): lltype.malloc(S, zero=True) t = rtype(g, []) gg = graphof(t, g) assert CollectAnalyzer(t).analyze_direct_call(gg) def g(x): return -x t = rtype(g, [int]) gg = graphof(t, g) assert not CollectAnalyzer(t).analyze_direct_call(gg)
def test_inline_all(self): def g(x): return x + 1 def f(x): return g(x) * g(x + 1) * g(x + 2) * g(x + 3) * g(x + 4) * g(x + 5) t = self.translate(f, [int]) sanity_check(t) # also check before inlining (so we don't blame it) simple_inline_function(t, graphof(t, g), graphof(t, f)) sanity_check(t) assert summary(graphof(t, f)) == {"int_add": 11, "int_mul": 5} interp = LLInterpreter(t.rtyper) result = interp.eval_graph(graphof(t, f), [10]) assert result == f(10)
def test_find_loop_blocks3(): import os def ps(loops): return 42.0, 42.1 def f(loops): benchtime, stones = ps(abs(loops)) s = "" # annotator happiness if loops >= 0: s = ( "RPystone(%s) time for %d passes = %f" % (23, loops, benchtime) + "\n" + ("This machine benchmarks at %f pystones/second" % stones) ) os.write(1, s) if loops == 12345: f(loops - 1) t = TranslationContext() t.buildannotator().build_types(f, [int]) t.buildrtyper().specialize() graph = graphof(t, f) backedges = find_backedges(graph) assert backedges == [] loop_blocks = find_loop_blocks(graph) assert len(loop_blocks) == 0
def test_premature_death(self): import os from rpython.annotator.listdef import s_list_of_strings inputtypes = [s_list_of_strings] def debug(msg): os.write(2, "debug: " + msg + '\n') def entry_point(argv): #debug("entry point starting") for arg in argv: #debug(" argv -> " + arg) r = arg.replace('_', '-') #debug(' replaced -> ' + r) a = r.lower() #debug(" lowered -> " + a) return 0 t = self.translateopt(entry_point, inputtypes, mallocs=True) entry_point_graph = graphof(t, entry_point) argv = t.rtyper.getrepr(inputtypes[0]).convert_const(['./pypy-c']) interp = LLInterpreter(t.rtyper) interp.eval_graph(entry_point_graph, [argv])
def test_replace_we_are_jitted(self): from rpython.rlib import jit def f(): if jit.we_are_jitted(): return 1 return 2 + jit.we_are_jitted() t = self.translateopt(f, []) graph = graphof(t, f) # by default, replace_we_are_jitted is off assert graph.startblock.operations[0].args[0].value is jit._we_are_jitted t = self.translateopt(f, [], replace_we_are_jitted=True) graph = graphof(t, f) assert graph.startblock.exits[0].args[0].value == 2
def check(self, fn, signature, args, expected_result, must_be_removed=True, inline=None): remover = self.MallocRemover() t = TranslationContext() t.buildannotator().build_types(fn, signature) t.buildrtyper().specialize() graph = graphof(t, fn) if inline is not None: from rpython.translator.backendopt.inline import auto_inline_graphs auto_inline_graphs(t, t.graphs, inline) if option.view: t.view() # to detect broken intermediate graphs, # we do the loop ourselves instead of calling remove_simple_mallocs() while True: progress = remover.remove_mallocs_once(graph) simplify.transform_dead_op_vars_in_blocks(list(graph.iterblocks()), [graph]) if progress and option.view: t.view() if expected_result is not Ellipsis: interp = LLInterpreter(t.rtyper) res = interp.eval_graph(graph, args) assert res == expected_result if not progress: break if must_be_removed: self.check_malloc_removed(graph) return graph
def test_cutoff(self): py.test.skip("cutoff: disabled") from rpython.rlib.unroll import unrolling_iterable cutoff = 20 attrs = unrolling_iterable(["s%s" % i for i in range(cutoff + 5)]) class A(object): def __init__(self, y): for attr in attrs: setattr(self, attr, y) def f(self): self.x = 1 res = 0 for attr in attrs: res += getattr(self, attr) return res def h(flag): obj = A(flag) return obj.f() t, wa = self.translate(h, [int]) wa.cutoff = cutoff hgraph = graphof(t, h) op_call_f = hgraph.startblock.operations[-1] # check that we fished the expected ops assert op_call_f.opname == "direct_call" assert op_call_f.args[0].value._obj._name == 'A.f' result = wa.analyze(op_call_f) assert result is top_set
def check(self, fn, signature, args, expected_result, expected_mallocs=0, expected_calls=0): t = TranslationContext() self.translator = t t.buildannotator().build_types(fn, signature) t.buildrtyper().specialize() graph = graphof(t, fn) if option.view: t.view() self.original_graph_count = len(t.graphs) # to detect broken intermediate graphs, # we do the loop ourselves instead of calling remove_simple_mallocs() maxiter = 100 mallocv = MallocVirtualizer(t.graphs, t.rtyper, verbose=True) while True: progress = mallocv.remove_mallocs_once() if progress and option.view: t.view() t.checkgraphs() if expected_result is not DONT_CHECK_RESULT: interp = LLInterpreter(t.rtyper) if not isinstance(expected_result, CHECK_RAISES): res = interp.eval_graph(graph, args) assert res == expected_result else: excinfo = py.test.raises(LLException, interp.eval_graph, graph, args) assert expected_result.excname in str(excinfo.value) if not progress: break maxiter -= 1 assert maxiter > 0, "infinite loop?" self.check_malloc_removed(graph, expected_mallocs, expected_calls) return graph
def test_lookup_graphs_abstract(): from rpython.translator.translator import TranslationContext, graphof class A: pass class B(A): def foo(self): pass class C(A): def foo(self): pass def fn(flag): obj = flag and B() or C() obj.foo() return obj t = TranslationContext() t.buildannotator().build_types(fn, [int]) t.buildrtyper(type_system='ootype').specialize() graph = graphof(t, fn) TYPE_A = graph.getreturnvar().concretetype TYPE_B = TYPE_A._subclasses[0] TYPE_C = TYPE_A._subclasses[1] assert len(TYPE_A._lookup_graphs('ofoo')) == 2 assert len(TYPE_B._lookup_graphs('ofoo')) == 1 assert len(TYPE_C._lookup_graphs('ofoo')) == 1
def test_auto_inlining_small_call_big_call_count(self): def leaf(n): total = 0 i = 0 while i < n: total += i if total > 100: raise OverflowError i += 1 return total def g(n): return leaf(n) def f(n): try: return g(n) except OverflowError: return -1 eval_func, t = self.check_auto_inlining(f, [int], multiplier=10, call_count_check=True) f_graph = graphof(t, f) assert len(collect_called_graphs(f_graph, t)) == 0 result = eval_func([10]) assert result == 45 result = eval_func([15]) assert result == -1
def test_list(self): def g(x, y, z): return f(x, y, z) def f(x, y, z): l = [0] * x l.append(y) return len(l) + z t, wa = self.translate(g, [int, int, int]) ggraph = graphof(t, g) assert ggraph.startblock.operations[0].opname == 'direct_call' result = sorted(wa.analyze(ggraph.startblock.operations[0])) array, A = result[0] assert array == "array" assert A.TO.OF == lltype.Signed struct, S1, name = result[1] assert struct == "struct" assert S1.TO.items == A assert S1.TO.length == lltype.Signed assert name == "items" struct, S2, name = result[2] assert struct == "struct" assert name == "length" assert S1 is S2
def test_read_really(self): class A(object): def __init__(self, y): self.y = y def f(self): self.x = 1 return self.y def h(flag): obj = A(flag) return obj.f() t, wa = self.translate(h, [int]) hgraph = graphof(t, h) op_call_f = hgraph.startblock.operations[-1] # check that we fished the expected ops assert op_call_f.opname == "direct_call" assert op_call_f.args[0].value._obj._name == 'A.f' result = wa.analyze(op_call_f) assert len(result) == 2 result = list(result) result.sort() [(struct1, T1, name1), (struct2, T2, name2)] = result assert struct1 == "readstruct" assert name1.endswith("y") assert struct2 == "struct" assert name2.endswith("x") assert T1 == T2
def test_tuple(): def f(x, y): return h(x + 1, x * y) def h(x, y): return x, y def g(x): a, b = f(x, x*5) return a + b t, graph = rtype(g, [int]) callgraph, caller_candidates = check_inlining(t, graph, [2], 23) assert caller_candidates == {graph: True} assert len(callgraph) == 2 fgraph = graphof(t, f) hgraph = graphof(t, h) assert callgraph == {graph: {fgraph: True}, fgraph: {hgraph: True}}
def test_remove_duplicate_write_barrier(): from rpython.translator.c.genc import CStandaloneBuilder from rpython.flowspace.model import summary class A(object): pass glob_a_1 = A() glob_a_2 = A() def f(a, cond): a.x = a a.z = a if cond: a.y = a def g(): f(glob_a_1, 5) f(glob_a_2, 0) t = rtype(g, []) t.config.translation.gc = "minimark" cbuild = CStandaloneBuilder(t, g, t.config, gcpolicy=FrameworkGcPolicy2) db = cbuild.generate_graphs_for_llinterp() ff = graphof(t, f) #ff.show() assert summary(ff)['direct_call'] == 1 # only one remember_young_pointer
def test_llexternal_with_callback(self): from rpython.rtyper.lltypesystem.rffi import llexternal from rpython.rtyper.lltypesystem import lltype class Abc: pass abc = Abc() FUNC = lltype.FuncType([lltype.Signed], lltype.Signed) z = llexternal('z', [lltype.Ptr(FUNC)], lltype.Signed) def g(n): abc.foobar = n return n + 1 def f(x): return z(g) t, wa = self.translate(f, [int]) fgraph = graphof(t, f) backend_optimizations(t) assert fgraph.startblock.operations[0].opname == 'direct_call' result = wa.analyze(fgraph.startblock.operations[0]) assert len(result) == 1 (struct, T, name), = result assert struct == "struct" assert name.endswith("foobar")
def test_dont_remove_with__del__(self): import os delcalls = [0] class A(object): nextid = 0 def __init__(self): self.id = self.nextid self.nextid += 1 def __del__(self): delcalls[0] += 1 #os.write(1, "__del__\n") def f(x=int): a = A() i = 0 while i < x: a = A() os.write(1, str(delcalls[0]) + "\n") i += 1 return 1 t = TranslationContext() t.buildannotator().build_types(f, [int]) t.buildrtyper().specialize() graph = graphof(t, f) backend_optimizations(t) op = graph.startblock.exits[0].target.exits[1].target.operations[0] assert op.opname == "malloc"
def test_remove_same_as(): def nothing(x): return x def f(): nothing(False) if nothing(True): return 42 else: return 666 t = TranslationContext() t.buildannotator().build_types(f, []) t.buildrtyper().specialize() # now we make the 'if True' appear f_graph = graphof(t, f) simple_inline_function(t, nothing, f_graph) # here, the graph looks like v21=same_as(True); exitswitch: v21 remove_same_as(f_graph) t.checkgraphs() # only one path should be left for block in f_graph.iterblocks(): assert len(block.exits) <= 1 interp = LLInterpreter(t.rtyper) result = interp.eval_graph(f_graph, []) assert result == 42
def test_remove_same_as_nonconst(): from rpython.rlib.nonconst import NonConstant from rpython.rtyper.lltypesystem.lloperation import llop from rpython.rtyper.lltypesystem import lltype def f(): if NonConstant(False): x = llop.same_as(lltype.Signed, 666) return 42 t = TranslationContext() t.buildannotator().build_types(f, []) t.buildrtyper().specialize() f_graph = graphof(t, f) # simple_inline_function(t, nothing, f_graph) # here, the graph looks like v21=same_as(True); exitswitch: v21 remove_same_as(f_graph) t.checkgraphs() # only one path should be left for block in f_graph.iterblocks(): assert len(block.exits) <= 1 for block in t.annotator.annotated: assert None not in block.operations interp = LLInterpreter(t.rtyper) result = interp.eval_graph(f_graph, []) assert result == 42
def test_secondary_backendopt(self): # checks an issue with a newly added graph that calls an # already-exception-transformed graph. This can occur e.g. # from a late-seen destructor added by the GC transformer # which ends up calling existing code. def common(n): if n > 5: raise ValueError def main(n): common(n) def later(n): try: common(n) return 0 except ValueError: return 1 t = TranslationContext() t.buildannotator().build_types(main, [int]) t.buildrtyper().specialize() exctransformer = t.getexceptiontransformer() exctransformer.create_exception_handling(graphof(t, common)) from rpython.annotator import model as annmodel from rpython.rtyper.annlowlevel import MixLevelHelperAnnotator annhelper = MixLevelHelperAnnotator(t.rtyper) later_graph = annhelper.getgraph(later, [annmodel.SomeInteger()], annmodel.SomeInteger()) annhelper.finish() annhelper.backend_optimize() # ^^^ as the inliner can't handle exception-transformed graphs, # this should *not* inline common() into later(). if option.view: later_graph.show() common_graph = graphof(t, common) found = False for block in later_graph.iterblocks(): for op in block.operations: if op.opname == "direct_call" and op.args[0].value._obj.graph is common_graph: found = True assert found, "cannot find the call (buggily inlined?)" from rpython.rtyper.llinterp import LLInterpreter llinterp = LLInterpreter(t.rtyper) res = llinterp.eval_graph(later_graph, [10]) assert res == 1
def test_indirect_call(self): def g1(): raise ValueError def g2(): return 2 def f(x): if x: g = g1 else: g = g2 return g() def h(x): return f(x) t, ra = self.translate(h, [int]) hgraph = graphof(t, h) result = ra.can_raise(hgraph.startblock.operations[0]) assert result
def test_call_function(): class C: pass def f(): c = C() c.x = 1 return c def g(): return f().x t, transformer = rtype_and_transform(g, [], _TestGCTransformer) ggraph = graphof(t, g) for i, op in enumerate(ggraph.startblock.operations): if op.opname == "direct_call": break else: assert False, "direct_call not found!" assert ggraph.startblock.operations[i + 1].opname != 'gc_push_alive'
def test_for_loop(self): def f(n): total = 0 for i in range(n): total += i return total t = self.translateopt(f, [int], mallocs=True) # this also checks that the BASE_INLINE_THRESHOLD is enough # for 'for' loops f_graph = graph = graphof(t, f) self.check_malloc_removed(f_graph) interp = LLInterpreter(t.rtyper) res = interp.eval_graph(f_graph, [11]) assert res == 55
def test_bug_inlined_if(self): def f(x, flag): if flag: y = x else: y = x + 1 return y * 5 def myfunc(x): return f(x, False) - f(x, True) assert myfunc(10) == 5 t = self.translateopt(myfunc, [int], inline_threshold=HUGE_THRESHOLD) interp = LLInterpreter(t.rtyper) res = interp.eval_graph(graphof(t, myfunc), [10]) assert res == 5
def test_method(self): class A(object): def f(self): return 1 def m(self): raise ValueError class B(A): def f(self): return 2 def m(self): return 3 def f(a): return a.f() def m(a): return a.m() def h(flag): if flag: obj = A() else: obj = B() f(obj) m(obj) t, ra = self.translate(h, [int]) hgraph = graphof(t, h) # fiiiish :-( block = hgraph.startblock.exits[0].target.exits[0].target op_call_f = block.operations[0] op_call_m = block.operations[1] # check that we fished the expected ops def check_call(op, fname): assert op.opname == "direct_call" assert op.args[0].value._obj._name == fname check_call(op_call_f, "f") check_call(op_call_m, "m") assert not ra.can_raise(op_call_f) assert ra.can_raise(op_call_m)
def test_inserting_zeroing_op(self): from rpython.rtyper.lltypesystem import lltype S = lltype.GcStruct("S", ('x', lltype.Signed)) def f(x): s = lltype.malloc(S) s.x = 0 return s.x t = TranslationContext() t.buildannotator().build_types(f, [int]) t.buildrtyper().specialize() g = graphof(t, f) etrafo = exceptiontransform.ExceptionTransformer(t) etrafo.create_exception_handling(g) ops = dict.fromkeys([o.opname for b, o in g.iterblockops()]) assert 'zero_gc_pointers_inside' in ops
def check(self, f, argtypes, no_getfields=0): t = self.translate(f, argtypes) getfields = 0 graph = graphof(t, f) removenoops.remove_same_as(graph) checkgraph(graph) storesink_graph(graph) checkgraph(graph) if option.view: t.view() for block in graph.iterblocks(): for op in block.operations: if op.opname == 'getfield': getfields += 1 if no_getfields != getfields: py.test.fail("Expected %d, got %d getfields" % (no_getfields, getfields))
def test_del_inheritance(self): from rpython.rlib import rgc class State: pass s = State() s.a_dels = 0 s.b_dels = 0 class A(object): def __del__(self): s.a_dels += 1 class B(A): def __del__(self): s.b_dels += 1 class C(A): pass def f(): A() B() C() A() B() C() rgc.collect() return s.a_dels * 10 + s.b_dels res = f() assert res == 42 t = TranslationContext() t.buildannotator().build_types(f, []) t.buildrtyper().specialize() graph = graphof(t, f) TYPEA = graph.startblock.operations[0].args[0].value RTTIA = getRuntimeTypeInfo(TYPEA) TYPEB = graph.startblock.operations[3].args[0].value RTTIB = getRuntimeTypeInfo(TYPEB) TYPEC = graph.startblock.operations[6].args[0].value RTTIC = getRuntimeTypeInfo(TYPEC) queryptra = RTTIA._obj.query_funcptr # should not raise queryptrb = RTTIB._obj.query_funcptr # should not raise queryptrc = RTTIC._obj.query_funcptr # should not raise destrptra = RTTIA._obj.destructor_funcptr destrptrb = RTTIB._obj.destructor_funcptr destrptrc = RTTIC._obj.destructor_funcptr assert destrptra == destrptrc assert typeOf(destrptra).TO.ARGS[0] != typeOf(destrptrb).TO.ARGS[0] assert destrptra is not None assert destrptrb is not None
def test_write_to_new_struct_3(self): class A(object): pass prebuilt = A() def f(x): if x > 5: a = A() else: a = A() a.baz = x return a t, wa = self.translate(f, [int]) fgraph = graphof(t, f) result = wa.analyze_direct_call(fgraph) assert not result
def create_interlink_node(db): """ Translates the create_interlink_impl() function and returns a jvm.Method object that allows it to be called. """ translator = db.genoo.translator for func, type_list in HELPERS.items(): translator.annotator.build_types(func, type_list) translator.rtyper.specialize_more_blocks() helpers = {} for func in HELPERS.keys(): graph = graphof(translator, func) helpers[func.func_name] = db.pending_function(graph) raise_OSError_graph = translator.rtyper.exceptiondata.fn_raise_OSError.graph helpers["throwOSError"] = db.pending_function(raise_OSError_graph) db.create_interlink_node(helpers)
def test_remove_unaryops(): # We really want to use remove_unaryops for more complex operations, but # it's easier to test it with operations on ints here. def f(x): i = llop.int_invert(lltype.Signed, x) i = llop.int_add(lltype.Signed, x, 1) return llop.int_neg(lltype.Signed, i) t = TranslationContext() t.buildannotator().build_types(f, [int]) t.buildrtyper().specialize() f_graph = graphof(t, f) remove_unaryops(f_graph, ["int_neg", "int_invert"]) t.checkgraphs() interp = LLInterpreter(t.rtyper) result = interp.eval_graph(f_graph, [-2]) assert result == -1
def test_write_to_new_struct_2(self): class A(object): pass def f(x): a = A() # a few extra blocks i = 10 while i > 0: i -= 1 # done a.baz = x # writes to a fresh new struct are ignored return a t, wa = self.translate(f, [int]) fgraph = graphof(t, f) result = wa.analyze_direct_call(fgraph) assert not result
def test_canrelease_instantiate(): class O: pass class A(O): pass class B(O): pass classes = [A, B] def g(i): classes[i]() t = rtype(g, [int]) gg = graphof(t, g) assert not gilanalysis.GilAnalyzer(t).analyze_direct_call(gg)
def test_write_to_new_struct_4(self): class A(object): pass prebuilt = A() def f(x): if x > 5: a = A() else: a = prebuilt a.baz = x return a t, wa = self.translate(f, [int]) fgraph = graphof(t, f) result = wa.analyze_direct_call(fgraph) assert len(result) == 1 and 'baz' in list(result)[0][-1]
def test__del__(self): class A(object): def __init__(self): self.a = 2 def __del__(self): self.a = 3 def f(): a = A() return a.a t = TranslationContext() t.buildannotator().build_types(f, []) t.buildrtyper().specialize() graph = graphof(t, f) TYPE = graph.startblock.operations[0].args[0].value RTTI = getRuntimeTypeInfo(TYPE) RTTI._obj.query_funcptr # should not raise destrptr = RTTI._obj.destructor_funcptr assert destrptr is not None
def test_instantiate(self): from rpython.rlib.objectmodel import instantiate class A: pass class B(A): pass def g(x): if x: C = A else: C = B a = instantiate(C) def f(x): return g(x) t, wa = self.translate(f, [int]) fgraph = graphof(t, f) result = wa.analyze(fgraph.startblock.operations[0]) assert not result
def test_method(self): class A(object): def f(self): self.x = 1 return 1 def m(self): raise ValueError class B(A): def f(self): return 2 def m(self): return 3 def f(a): return a.f() def m(a): return a.m() def h(flag): if flag: obj = A() else: obj = B() f(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_f = block.operations[0] op_call_m = block.operations[1] # check that we fished the expected ops def check_call(op, fname): assert op.opname == "direct_call" assert op.args[0].value._obj._name == fname check_call(op_call_f, "f") check_call(op_call_m, "m") result = wa.analyze(op_call_f) assert len(result) == 1 (struct, T, name), = result assert struct == "struct" assert name.endswith("x") assert not wa.analyze(op_call_m)
def test_remove_duplicate_casts(): class A(object): def __init__(self, x, y): self.x = x self.y = y def getsum(self): return self.x + self.y class B(A): def __init__(self, x, y, z): A.__init__(self, x, y) self.z = z def getsum(self): return self.x + self.y + self.z def f(x, switch): a = A(x, x + 1) b = B(x, x + 1, x + 2) if switch: c = A(x, x + 1) else: c = B(x, x + 1, x + 2) return a.x + a.y + b.x + b.y + b.z + c.getsum() assert f(10, True) == 75 graph, t = get_graph(f, [int, bool], all_opts=False) num_cast_pointer = len(getops(graph)['cast_pointer']) changed = remove_duplicate_casts(graph, t) assert changed ops = getops(graph) assert len(ops['cast_pointer']) < num_cast_pointer print len(ops['cast_pointer']), num_cast_pointer graph_getsum = graphof(t, B.getsum.im_func) num_cast_pointer = len(getops(graph_getsum)['cast_pointer']) changed = remove_duplicate_casts(graph_getsum, t) assert changed if option.view: t.view() check_graph(graph, [10, True], 75, t) ops = getops(graph_getsum) assert len(ops['cast_pointer']) < num_cast_pointer print len(ops['cast_pointer']), num_cast_pointer
def test_method_recursive(self): class A: def m(self, x): if x > 0: return self.m(x-1) else: return 42 def m(a): return a.m(2) def h(): obj = A() m(obj) t, ra = self.translate(h, []) hgraph = graphof(t, h) # fiiiish :-( block = hgraph.startblock op_call_m = block.operations[-1] assert op_call_m.opname == "direct_call" assert not ra.can_raise(op_call_m)
def test_range_iter(self): def fn(start, stop, step): res = 0 if step == 0: if stop >= start: r = range(start, stop, 1) else: r = range(start, stop, -1) else: r = range(start, stop, step) for i in r: res = res * 51 + i return res t = self.translateopt(fn, [int, int, int], merge_if_blocks=True) interp = LLInterpreter(t.rtyper) for args in [2, 7, 0], [7, 2, 0], [10, 50, 7], [50, -10, -3]: assert interp.eval_graph(graphof(t, fn), args) == intmask(fn(*args))
def test_interiorfield(self): A = lltype.GcArray(lltype.Struct('x', ('x', lltype.Signed), ('y', lltype.Signed))) def g(x): a = lltype.malloc(A, 1) a[0].y = 3 return f(a, x) def f(a, x): a[0].x = x return a[0].y t, wa = self.translate(g, [int]) ggraph = graphof(t, g) result = wa.analyze(ggraph.startblock.operations[-1]) res = list(result) assert ('readinteriorfield', lltype.Ptr(A), 'y') in res assert ('interiorfield', lltype.Ptr(A), 'x') in res
def test_gctransformed(): t = TranslationContext() a = t.buildannotator() a.build_types(g, [int]) a.simplify() t.buildrtyper().specialize() backend_optimizations(t) t.checkgraphs() n = insert_ll_stackcheck(t) t.checkgraphs() assert n == 1 exctransf = t.getexceptiontransformer() f_graph = graphof(t, f) exctransf.create_exception_handling(f_graph) if option.view: f_graph.show() check(f_graph, 'f') class GCTransform(shadowstack.ShadowStackFrameworkGCTransformer): from rpython.memory.gc.generation import GenerationGC as \ GCClass GC_PARAMS = {} gctransf = GCTransform(t) gctransf.transform_graph(f_graph) if option.view: f_graph.show() relevant = check(f_graph, 'f') for p in relevant: in_between = False reload = 0 for spaceop in p: if spaceop.opname == 'direct_call': target = direct_target(spaceop) if target == 'f': in_between = False elif target == 'stack_check___': in_between = True if in_between and spaceop.opname == 'gc_reload_possibly_moved': reload += 1 assert reload == 0
def test_join_blocks_cleans_links(): from rpython.rtyper.lltypesystem import lltype from rpython.flowspace.model import Constant from rpython.translator.backendopt.removenoops import remove_same_as def f(x): return bool(x + 2) def g(x): if f(x): return 1 else: return 2 graph, t = translate(g, [int], backend_optimize=False) fgraph = graphof(t, f) fgraph.startblock.exits[0].args = [Constant(True, lltype.Bool)] # does not crash: previously join_blocks would barf on this remove_same_as(graph) backend_optimizations(t)
def test_instantiate(self): # instantiate is interesting, because it leads to one of the few cases of # an indirect call without a list of graphs from rpython.rlib.objectmodel import instantiate class A: pass class B(A): pass def g(x): if x: C = A else: C = B a = instantiate(C) def f(x): return g(x) t, ra = self.translate(f, [int]) fgraph = graphof(t, f) result = ra.can_raise(fgraph.startblock.operations[0]) assert result
def test_exceptiontransformed_add_ovf(): from rpython.translator import exceptiontransform def f(x, y): try: return ovfcheck(x + y) except OverflowError: return -42 t = TranslationContext() t.buildannotator().build_types(f, [int, int]) t.buildrtyper().specialize() etrafo = exceptiontransform.ExceptionTransformer(t) graph = graphof(t, f) etrafo.create_exception_handling(graph) interp = LLInterpreter(t.rtyper) res = interp.eval_graph(graph, [1, -64]) assert res == -63 res = interp.eval_graph(graph, [1, sys.maxint]) assert res == -42
def test_arraybarrier(): S = lltype.GcStruct("S", ('x', lltype.Signed)) A = lltype.GcArray(lltype.Ptr(S)) def f(): s1 = lltype.malloc(S) s1.x = 1 s2 = lltype.malloc(S) s2.x = 2 a = lltype.malloc(A, 1) a[0] = s1 a[0] = s2 t, transformer = rtype_and_transform(f, [], RefcountingGCTransformer, check=False) graph = graphof(t, f) ops = getops(graph) assert len(ops['getarrayitem']) == 2 assert len(ops['bare_setarrayitem']) == 2 assert len(ops['bare_setfield']) == 2
def test_bare_setfield(): from rpython.rtyper.lltypesystem.lloperation import llop class A: def __init__(self, obj): self.x = obj class B: def __init__(self, i): self.i = i def f(i): v = B(i) inst = A(v) llop.setfield(lltype.Void, inst, 'x', v) llop.bare_setfield(lltype.Void, inst, 'x', v) t, transformer = rtype_and_transform(f, [int], _TestGCTransformer, check=False) ops = getops(graphof(t, f))
def fix_graph_of_g(translator): from rpython.translator.translator import graphof from rpython.flowspace.model import Constant from rpython.rtyper.lltypesystem import rffi layoutbuilder = cls.ensure_layoutbuilder(translator) type_id = layoutbuilder.get_type_id(P) # # now fix the do_malloc_fixedsize in the graph of g graph = graphof(translator, g) for op in graph.startblock.operations: if op.opname == 'do_malloc_fixedsize': op.args = [ Constant(type_id, llgroup.HALFWORD), Constant(llmemory.sizeof(P), lltype.Signed), Constant(False, lltype.Bool), # has_finalizer Constant(False, lltype.Bool), # is_finalizer_light Constant(False, lltype.Bool) ] # contains_weakptr break else: assert 0, "oups, not found"
def test_implicit_cast(self): z = llexternal('z', [USHORT, ULONG, USHORT, DOUBLE], USHORT, sandboxsafe=True) # to allow the wrapper to be inlined def f(x, y, xx, yy): return z(x, y, xx, yy) a = RPythonAnnotator() r = a.build_types(f, [int, int, int, int]) rtyper = RPythonTyper(a) rtyper.specialize() a.translator.rtyper = rtyper backend_optimizations(a.translator) if option.view: a.translator.view() graph = graphof(a.translator, f) s = summary(graph) # there should be not too many operations here by now expected = {'force_cast': 3, 'cast_int_to_float': 1, 'direct_call': 1} for k, v in expected.items(): assert s[k] == v
def test_simple_barrier(): S = lltype.GcStruct("S", ('x', lltype.Signed)) T = lltype.GcStruct("T", ('s', lltype.Ptr(S))) def f(): s1 = lltype.malloc(S) s1.x = 1 s2 = lltype.malloc(S) s2.x = 2 t = lltype.malloc(T) t.s = s1 t.s = s2 return t t, transformer = rtype_and_transform(f, [], RefcountingGCTransformer, check=False) graph = graphof(t, f) ops = getops(graph) assert len(ops['getfield']) == 2 assert len(ops['bare_setfield']) == 4