def test_cancollect_external(): fext1 = rffi.llexternal('fext1', [], lltype.Void, threadsafe=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, threadsafe=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, threadsafe=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_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 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 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 pypy.rpython 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_add_more_subclasses(self): from pypy.rpython import rclass from pypy.rpython.lltypesystem.rclass import ll_issubclass from pypy.rpython.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_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_llexternal(self): from pypy.rpython.lltypesystem.rffi import llexternal from pypy.rpython.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 test_half_exceptiontransformed_graphs(): from pypy.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(test_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 get_graph(arg, translator): from pypy.translator.translator import graphof if isinstance(arg, Variable): return None f = arg.value from pypy.rpython.lltypesystem import lltype from pypy.rpython.ootypesystem import ootype if not isinstance(f, lltype._ptr) and not isinstance(f, ootype._callable): return None funcobj = get_funcobj(f) try: callable = funcobj._callable except (AttributeError, KeyError, AssertionError): return None try: return funcobj.graph except AttributeError: return None try: callable = funcobj._callable return graphof(translator, callable) except (AttributeError, KeyError, AssertionError): return None
def translate(func, argtypes, backend_optimize=True): t = TranslationContext() t.buildannotator().build_types(func, argtypes) t.buildrtyper().specialize() if backend_optimize: backend_optimizations(t) return graphof(t, func), t
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_substruct(): class A(object): pass class B(object): pass def g(a, b): a.b = b a.b.x = 1 return a.b def f(): a0 = A() b0 = B() return g(a0, b0).x t, adi, graph = build_adi(f, []) g_graph = graphof(t, g) a0var = graph.startblock.operations[0].result b0var = graph.startblock.operations[3].result a0state = adi.getstate(a0var) b0state = adi.getstate(b0var) assert len(a0state.creation_points) == 1 a0crep = a0state.creation_points.keys()[0] assert not a0crep.escapes assert a0crep.changes assert len(b0state.creation_points) == 1 b0crep = b0state.creation_points.keys()[0] assert b0crep.escapes assert b0crep.changes
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 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(type_system=self.type_system).specialize() graph = graphof(t, fn) if inline is not None: from pypy.translator.backendopt.inline import auto_inline_graphs auto_inline_graphs(t, t.graphs, inline) if option.view: t.view() # to detect missing keepalives and 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())) 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 enum_direct_calls(translator, func): blocks = [] graph = graphof(translator, func) for block in graph.iterblocks(): for op in block.operations: if op.opname == 'direct_call': yield op
def hannotate(func, argtypes, policy=P_DEFAULT, annotator=False, inline=None, backendoptimize=False): # build the normal ll graphs for ll_function t = TranslationContext() a = t.buildannotator() a.build_types(func, argtypes) rtyper = t.buildrtyper() rtyper.specialize() if inline: auto_inlining(t, threshold=inline) if backendoptimize: from pypy.translator.backendopt.all import backend_optimizations backend_optimizations(t) graph1 = graphof(t, func) # build hint annotator types hannotator = HintAnnotator(base_translator=t, policy=policy) hs = hannotator.build_types(graph1, [SomeLLAbstractConstant(v.concretetype, {OriginFlags(): True}) for v in graph1.getargs()]) hannotator.simplify() t = hannotator.translator if conftest.option.view: t.view() if annotator: return hs, hannotator else: return hs
def test_specialize_deepfreeze_calls(): l1 = [1,2,3,4,5] l2 = [6,7,8,9,10] def getlist(n): if n: return l1 else: return l2 def ll_get(l, i): return l[i] def ll_function(n, i): l = getlist(n) l2 = ll_get(l, 0) l = hint(l, deepfreeze=True) res = ll_get(l, i) return res hs, ha = hannotate(ll_function, [int, int], annotator=True, policy=P_NOVIRTUAL) assert hs.deepfrozen assert hs.concretetype == lltype.Signed ll_get_graph = graphof(ha.base_translator, ll_get) gdesc = ha.bookkeeper.getdesc(ll_get_graph) assert len(gdesc._cache) == 2 assert 'xDxx' in gdesc._cache v1, v2 = gdesc._cache['xDxx'].getargs() assert isinstance(ha.binding(v1), SomeLLAbstractConstant) assert isinstance(ha.binding(v2), SomeLLAbstractConstant) assert ha.binding(v1).deepfrozen
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_lookup_graphs_abstract(): from pypy.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_premature_death(self): import os from pypy.annotation.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_instantiate(self): # instantiate is interesting, because it leads to one of the few cases of # an indirect call without a list of graphs from pypy.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 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(type_system=self.type_system).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() #simplify.transform_dead_op_vars_in_blocks(list(graph.iterblocks())) 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_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_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 get_funcobj(op_call_f.args[0].value)._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_llexternal_with_callback(self): from pypy.rpython.lltypesystem.rffi import llexternal from pypy.rpython.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_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_indirect_sometimes_residual_pure_but_fixed_red_call(): def h1(x): return x-2 def h2(x): return x*4 l = [h1, h2] def f(n, x): frozenl = hint(l, deepfreeze=True) h = frozenl[n&1] z = h(x) hint(z, concrete=True) return z P = StopAtXPolicy(h1) P.oopspec = True P.entrypoint_returns_red = False hs, hannotator = hannotate(f, [int, int], policy=P, annotator=True) assert hs.is_green() #tsgraph = graphof(hannotator.translator, h2) #hs = hannotator.binding(tsgraph.getargs()[0]) #assert hs.is_green() tsgraph = graphof(hannotator.translator, f) hs = hannotator.binding(tsgraph.getargs()[0]) assert hs.is_green() hs = hannotator.binding(tsgraph.getargs()[1]) assert hs.is_green()
def fix_graph_of_g(translator): from pypy.translator.translator import graphof from pypy.objspace.flow.model import Constant from pypy.rpython.lltypesystem import rffi layoutbuilder = cls.ensure_layoutbuilder(translator) type_id = layoutbuilder.get_type_id(P) # # now fix the do_malloc_fixedsize_clear in the graph of g graph = graphof(translator, g) for op in graph.startblock.operations: if op.opname == 'do_malloc_fixedsize_clear': 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_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
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) queryptr = RTTI._obj.query_funcptr # should not raise destrptr = RTTI._obj.destructor_funcptr assert destrptr is not None
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_indirect_sometimes_residual_pure_red_call(self, setup=setup_for_indirect_call): def h1(x): return x-2 def h2(x): return x*4 call, lst = setup(h1, h2) def f(n, x): frozenl = hint(lst, deepfreeze=True) h = frozenl[n&1] return call(h, x) P = StopAtXPolicy(h1) P.oopspec = True P.entrypoint_returns_red = False hs, hannotator = self.hannotate(f, [int, int], policy=P, annotator=True) assert not hs.is_green() assert isinstance(hs, SomeLLAbstractConstant) tsgraph = graphof(hannotator.translator, h2) hs = hannotator.binding(tsgraph.getargs()[0]) assert not hs.is_green()
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 get_funcobj(op.args[0].value)._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_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_untagged_subclasses(): def g(x): return x.attrvalue # should not produce a call to ll_unboxed_getclass def fn(n): y = C(12) if n > 0: x = B(5) else: x = D(5) return g(x) interp, graph = get_interpreter(fn, [-1000]) t = interp.typer.annotator.translator ggraph = graphof(t, g) assert summary(ggraph) == {'cast_pointer': 2, 'getfield': 2} res = interp.eval_graph(graph, [-1000]) assert res == 68 res = interp.eval_graph(graph, [3]) assert res == 66
def make_deallocator(TYPE, attr="static_deallocation_funcptr_for_type", cls=RefcountingGCTransformer): if TYPE._is_varsize(): def f(): return lltype.malloc(TYPE, 1) else: def f(): return lltype.malloc(TYPE) t = TranslationContext() t.buildannotator().build_types(f, []) t.buildrtyper().specialize() transformer = cls(t) fptr = getattr(transformer, attr)(TYPE) transformer.transform_graph(graphof(t, f)) transformer.finish(backendopt=False) if conftest.option.view: t.view() if fptr: return fptr._obj.graph, t else: return None, t
def llinterp_stackless_function(fn, returntranslator=False, assert_unwind=True): def wrapper(argv): return fn() t = rtype_stackless_function(wrapper) st = StacklessTransformer(t, wrapper, assert_unwind=assert_unwind) st.transform_all() if conftest.option.view: t.view() graph = graphof(t, st.slp_entry_point) r_list_of_strings = t.rtyper.getrepr( t.annotator.binding(graph.startblock.inputargs[0])) ll_list = r_list_of_strings.convert_const(['']) interp = llinterp.LLInterpreter(t.rtyper) res = interp.eval_graph(graph, [ll_list]) if returntranslator: return res, t else: return res
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_call(): class A(object): pass def g(b): return b.i + 2 def f(): a = A() a.i = 2 return g(a) t, adi, graph = build_adi(f, []) g_graph = graphof(t, g) bvar = g_graph.startblock.inputargs[0] bstate = adi.getstate(bvar) bcrep, = bstate.creation_points assert not bcrep.escapes avar = graph.startblock.operations[0].result astate = adi.getstate(avar) acrep, = astate.creation_points assert not acrep.escapes
def test_specialize_calls(self): def ll_add(x, y): return x+y def ll_function(x,y): z0 = ll_add(y, 2) z1 = ll_add(x, y) x1 = hint(x, concrete=True) z2 = ll_add(x1, y) return z2 hs, ha = self.hannotate(ll_function, [int, int], annotator=True) assert hs.eager_concrete assert hs.concretetype == lltype.Signed ll_add_graph = graphof(ha.base_translator, ll_add) gdesc = ha.bookkeeper.getdesc(ll_add_graph) assert len(gdesc._cache) == 2 assert 'Exxx' in gdesc._cache v1, v2 = gdesc._cache['Exxx'].getargs() assert isinstance(ha.binding(v1), SomeLLAbstractConstant) assert isinstance(ha.binding(v2), SomeLLAbstractConstant) assert ha.binding(v1).eager_concrete assert not ha.binding(v2).is_fixed()
def test_adt_method(self): def ll_callme(n): return n ll_callme = lltype.staticAdtMethod(ll_callme) S = lltype.GcStruct('S', ('x', lltype.Signed), adtmeths = {'yep': True, 'callme': ll_callme}) def g(p, x, y, z): p.x = x if p.yep: z *= p.callme(y) return z def f(x, y, z): p = lltype.malloc(S) return g(p, x, y, z) t, wa = self.translate(f, [int, int, int]) fgraph = graphof(t, f) assert fgraph.startblock.operations[-1].opname == 'direct_call' result = wa.analyze(fgraph.startblock.operations[-1]) assert list(result) == [("struct", lltype.Ptr(S), "x")]
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 task_hintannotate_lltype(self): from pypy.jit.hintannotator.annotator import HintAnnotator from pypy.jit.hintannotator.model import OriginFlags from pypy.jit.hintannotator.model import SomeLLAbstractConstant get_portal = self.extra['portal'] PORTAL, POLICY = get_portal(self) t = self.translator self.portal_graph = graphof(t, PORTAL) hannotator = HintAnnotator(base_translator=t, policy=POLICY) self.hint_translator = hannotator.translator hs = hannotator.build_types(self.portal_graph, [ SomeLLAbstractConstant(v.concretetype, {OriginFlags(): True}) for v in self.portal_graph.getargs() ]) count = hannotator.bookkeeper.nonstuboriggraphcount stubcount = hannotator.bookkeeper.stuboriggraphcount self.log.info("The hint-annotator saw %d graphs" " (and made stubs for %d graphs)." % (count, stubcount)) n = len(list(hannotator.translator.graphs[0].iterblocks())) self.log.info("portal has %d blocks" % n) self.hannotator = hannotator
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 pypy.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]) if self.type_system == 'lltype': assert result is top_set else: assert not result # ootype is more precise in this case
def test_dynamic_deallocator(): class A(object): pass class B(A): pass def f(x): a = A() a.x = 1 b = B() b.x = 2 b.y = 3 if x: c = a else: c = b return c.x t, transformer = rtype_and_transform( f, [int], RefcountingGCTransformer, check=False) fgraph = graphof(t, f) s_instance = t.annotator.bookkeeper.valueoftype(A) TYPE = t.rtyper.getrepr(s_instance).lowleveltype.TO p = transformer.dynamic_deallocation_funcptr_for_type(TYPE) t.rtyper.specialize_more_blocks()
def test_dont_transform_too_much(): def check(x): if x: rstack.stack_unwind() def f(x): return x + 2 def g(x): check(x) return f(x) + x + 1 def example(): return g(one()) + 1 res, t = llinterp_stackless_function(example, returntranslator=True) assert res == 6 ggraph = graphof(t, g) for block, op in ggraph.iterblockops(): if op.opname == 'direct_call': if op.args[0].value._obj._callable is f: assert op != block.operations[-1]
def test_getfield_pyobj(): class S: pass def f(thing): s = S() s.x = thing return s.x t, transformer = rtype_and_transform(f, [object], _TestGCTransformer) fgraph = graphof(t, f) pyobj_getfields = 0 pyobj_setfields = 0 for b in fgraph.iterblocks(): for op in b.operations: if op.opname == 'getfield' and var_ispyobj(op.result): pyobj_getfields += 1 elif op.opname == 'bare_setfield' and var_ispyobj(op.args[2]): pyobj_setfields += 1 # although there's only one explicit getfield in the code, a # setfield on a pyobj must get the old value out and decref it assert pyobj_getfields >= 2 assert pyobj_setfields >= 1
def graphof(self, func): rtyper = self.metainterp_sd.cpu.rtyper return graphof(rtyper.annotator.translator, func)
def translate(func, argtypes): t = TranslationContext() t.buildannotator().build_types(func, argtypes) t.buildrtyper().specialize() return graphof(t, func), t
def translate(func, argtypes, type_system="lltype"): t = TranslationContext() t.buildannotator().build_types(func, argtypes) t.entry_point_graph = graphof(t, func) t.buildrtyper(type_system=type_system).specialize() return graphof(t, func), t
def eval_func(args): return interp.eval_graph(graphof(t, entry), args)