importpyfromrpython.rtyper.lltypesystemimportlltypefromrpython.rtyper.ootypesystemimportootypefromrpython.translator.translatorimportTranslationContext,graphoffromrpython.translator.simplifyimportget_funcobjfromrpython.translator.backendopt.writeanalyzeimportWriteAnalyzer,top_setfromrpython.translator.backendopt.writeanalyzeimportReadWriteAnalyzerfromrpython.translator.backendopt.allimportbackend_optimizationsclassBaseTest(object):type_system=NoneAnalyzer=WriteAnalyzerdeftranslate(self,func,sig):t=TranslationContext()t.buildannotator().build_types(func,sig)t.buildrtyper(type_system=self.type_system).specialize()ifpy.test.config.option.view:t.view()returnt,self.Analyzer(t)classBaseTestWriteAnalyze(BaseTest):deftest_writes_simple(self):defg(x):returnTruedeff(x):returng(x-1)t,wa=self.translate(f,[int])fgraph=graphof(t,f)result=wa.analyze(fgraph.startblock.operations[0])assertnotresultdeftest_writes_recursive(self):fromrpython.translator.transformimportinsert_ll_stackcheckdefg(x):returnf(x)deff(x):ifx:returng(x-1)return1t,wa=self.translate(f,[int])insert_ll_stackcheck(t)ggraph=graphof(t,g)result=wa.analyze(ggraph.startblock.operations[-1])assertnotresultdeftest_write_to_new_struct(self):classA(object):passdeff(x):a=A()a.baz=x# writes to a fresh new struct are ignoredreturnat,wa=self.translate(f,[int])fgraph=graphof(t,f)result=wa.analyze_direct_call(fgraph)assertnotresultdeftest_write_to_new_struct_2(self):classA(object):passdeff(x):a=A()# a few extra blocksi=10whilei>0:i-=1# donea.baz=x# writes to a fresh new struct are ignoredreturnat,wa=self.translate(f,[int])fgraph=graphof(t,f)result=wa.analyze_direct_call(fgraph)assertnotresultdeftest_write_to_new_struct_3(self):classA(object):passprebuilt=A()deff(x):ifx>5:a=A()else:a=A()a.baz=xreturnat,wa=self.translate(f,[int])fgraph=graphof(t,f)result=wa.analyze_direct_call(fgraph)assertnotresultdeftest_write_to_new_struct_4(self):classA(object):passprebuilt=A()deff(x):ifx>5:a=A()else:a=prebuilta.baz=xreturnat,wa=self.translate(f,[int])fgraph=graphof(t,f)result=wa.analyze_direct_call(fgraph)assertlen(result)==1and'baz'inlist(result)[0][-1]deftest_write_to_new_struct_5(self):classA(object):baz=123deff(x):ifx:a=A()else:a=A()a.baz+=1t,wa=self.translate(f,[int])fgraph=graphof(t,f)result=wa.analyze_direct_call(fgraph)assertnotresultdeftest_method(self):classA(object):deff(self):self.x=1return1defm(self):raiseValueErrorclassB(A):deff(self):return2defm(self):return3deff(a):returna.f()defm(a):returna.m()defh(flag):ifflag: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].targetop_call_f=block.operations[0]op_call_m=block.operations[1]# check that we fished the expected opsdefcheck_call(op,fname):assertop.opname=="direct_call"assertget_funcobj(op.args[0].value)._name==fnamecheck_call(op_call_f,"f")check_call(op_call_m,"m")result=wa.analyze(op_call_f)assertlen(result)==1(struct,T,name),=resultassertstruct=="struct"assertname.endswith("x")assertnotwa.analyze(op_call_m)deftest_instantiate(self):# instantiate is interesting, because it leads to one of the few cases of# an indirect call without a list of graphsfromrpython.rlib.objectmodelimportinstantiateclassA:passclassB(A):passdefg(x):ifx:C=Aelse:C=Ba=instantiate(C)deff(x):returng(x)t,wa=self.translate(f,[int])fgraph=graphof(t,f)result=wa.analyze(fgraph.startblock.operations[0])ifself.type_system=='lltype':assertresultistop_setelse:assertnotresult# ootype is more precise in this casedeftest_llexternal(self):fromrpython.rtyper.lltypesystem.rffiimportllexternalfromrpython.rtyper.lltypesystemimportlltypez=llexternal('z',[lltype.Signed],lltype.Signed)deff(x):returnz(x)t,wa=self.translate(f,[int])fgraph=graphof(t,f)backend_optimizations(t)assertfgraph.startblock.operations[0].opname=='direct_call'result=wa.analyze(fgraph.startblock.operations[0])assertnotresultdeftest_contains(self):defg(x,y,z):l=[x]returnf(l,y,z)deff(x,y,z):returnyinxt,wa=self.translate(g,[int,int,int])ggraph=graphof(t,g)assertggraph.startblock.operations[-1].opname=='direct_call'result=wa.analyze(ggraph.startblock.operations[-1])assertnotresultclassTestLLtype(BaseTestWriteAnalyze):type_system='lltype'deftest_list(self):defg(x,y,z):returnf(x,y,z)deff(x,y,z):l=[0]*xl.append(y)returnlen(l)+zt,wa=self.translate(g,[int,int,int])ggraph=graphof(t,g)assertggraph.startblock.operations[0].opname=='direct_call'result=sorted(wa.analyze(ggraph.startblock.operations[0]))array,A=result[0]assertarray=="array"assertA.TO.OF==lltype.Signedstruct,S1,name=result[1]assertstruct=="struct"assertS1.TO.items==AassertS1.TO.length==lltype.Signedassertname=="items"struct,S2,name=result[2]assertstruct=="struct"assertname=="length"assertS1isS2deftest_llexternal_with_callback(self):fromrpython.rtyper.lltypesystem.rffiimportllexternalfromrpython.rtyper.lltypesystemimportlltypeclassAbc:passabc=Abc()FUNC=lltype.FuncType([lltype.Signed],lltype.Signed)z=llexternal('z',[lltype.Ptr(FUNC)],lltype.Signed)defg(n):abc.foobar=nreturnn+1deff(x):returnz(g)t,wa=self.translate(f,[int])fgraph=graphof(t,f)backend_optimizations(t)assertfgraph.startblock.operations[0].opname=='direct_call'result=wa.analyze(fgraph.startblock.operations[0])assertlen(result)==1(struct,T,name),=resultassertstruct=="struct"assertname.endswith("foobar")classTestOOtype(BaseTestWriteAnalyze):type_system='ootype'deftest_array(self):defg(x,y,z):returnf(x,y,z)deff(x,y,z):l=[0]*xl[1]=42returnlen(l)+zt,wa=self.translate(g,[int,int,int])ggraph=graphof(t,g)assertggraph.startblock.operations[0].opname=='direct_call'result=sorted(wa.analyze(ggraph.startblock.operations[0]))assertlen(result)==1array,A=result[0]assertarray=='array'assertA.ITEMisootype.Signeddeftest_list(self):defg(x,y,z):returnf(x,y,z)deff(x,y,z):l=[0]*xl.append(z)returnlen(l)+zt,wa=self.translate(g,[int,int,int])ggraph=graphof(t,g)assertggraph.startblock.operations[0].opname=='direct_call'result=wa.analyze(ggraph.startblock.operations[0])assertresultistop_setclassTestLLtypeReadWriteAnalyze(BaseTest):Analyzer=ReadWriteAnalyzertype_system='lltype'deftest_read_simple(self):defg(x):returnTruedeff(x):returng(x-1)t,wa=self.translate(f,[int])fgraph=graphof(t,f)result=wa.analyze(fgraph.startblock.operations[0])assertnotresultdeftest_read_really(self):classA(object):def__init__(self,y):self.y=ydeff(self):self.x=1returnself.ydefh(flag):obj=A(flag)returnobj.f()t,wa=self.translate(h,[int])hgraph=graphof(t,h)op_call_f=hgraph.startblock.operations[-1]# check that we fished the expected opsassertop_call_f.opname=="direct_call"assertget_funcobj(op_call_f.args[0].value)._name=='A.f'result=wa.analyze(op_call_f)assertlen(result)==2result=list(result)result.sort()[(struct1,T1,name1),(struct2,T2,name2)]=resultassertstruct1=="readstruct"assertname1.endswith("y")assertstruct2=="struct"assertname2.endswith("x")assertT1==T2deftest_contains(self):defg(x,y,z):l=[x]returnf(l,y,z)deff(x,y,z):returnyinxt,wa=self.translate(g,[int,int,int])ggraph=graphof(t,g)assertggraph.startblock.operations[-1].opname=='direct_call'result=wa.analyze(ggraph.startblock.operations[-1])ARRAYPTR=list(result)[0][1]assertlist(result)==[("readarray",ARRAYPTR)]assertisinstance(ARRAYPTR.TO,lltype.GcArray)deftest_adt_method(self):defll_callme(n):returnnll_callme=lltype.staticAdtMethod(ll_callme)S=lltype.GcStruct('S',('x',lltype.Signed),adtmeths={'yep':True,'callme':ll_callme})defg(p,x,y,z):p.x=xifp.yep:z*=p.callme(y)returnzdeff(x,y,z):p=lltype.malloc(S)returng(p,x,y,z)t,wa=self.translate(f,[int,int,int])fgraph=graphof(t,f)assertfgraph.startblock.operations[-1].opname=='direct_call'result=wa.analyze(fgraph.startblock.operations[-1])assertlist(result)==[("struct",lltype.Ptr(S),"x")]