diff --git a/com.ibm.wala.cast/.classpath b/com.ibm.wala.cast/.classpath new file mode 100644 index 000000000..0097c17f8 --- /dev/null +++ b/com.ibm.wala.cast/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/com.ibm.wala.cast/.cvsignore b/com.ibm.wala.cast/.cvsignore new file mode 100644 index 000000000..23f0c70e0 --- /dev/null +++ b/com.ibm.wala.cast/.cvsignore @@ -0,0 +1,2 @@ +bin +domo-trace.txt* diff --git a/com.ibm.wala.cast/.externalToolBuilders/make DOMO.Ast.launch b/com.ibm.wala.cast/.externalToolBuilders/make DOMO.Ast.launch new file mode 100644 index 000000000..a091cdb99 --- /dev/null +++ b/com.ibm.wala.cast/.externalToolBuilders/make DOMO.Ast.launch @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/com.ibm.wala.cast/.project b/com.ibm.wala.cast/.project new file mode 100644 index 000000000..220237197 --- /dev/null +++ b/com.ibm.wala.cast/.project @@ -0,0 +1,38 @@ + + + com.ibm.wala.cast + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.ui.externaltools.ExternalToolBuilder + full,incremental, + + + LaunchConfigHandle + <project>/.externalToolBuilders/make DOMO.Ast.launch + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/com.ibm.wala.cast/META-INF/MANIFEST.MF b/com.ibm.wala.cast/META-INF/MANIFEST.MF new file mode 100644 index 000000000..fe84f9257 --- /dev/null +++ b/com.ibm.wala.cast/META-INF/MANIFEST.MF @@ -0,0 +1,25 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: WALA CAst core Plug-in +Bundle-SymbolicName: com.ibm.wala.cast +Bundle-Version: 1.0.0 +Bundle-Activator: com.ibm.wala.cast.plugin.AstPlugin +Bundle-Vendor: IBM +Bundle-Localization: plugin +Require-Bundle: org.eclipse.core.runtime, + com.ibm.wala.core +Eclipse-AutoStart: true +Export-Package: com.ibm.wala.cast.analysis.typeInference, + com.ibm.wala.cast.ipa.callgraph, + com.ibm.wala.cast.ir.cfg, + com.ibm.wala.cast.ir.ssa, + com.ibm.wala.cast.ir.ssa.analysis, + com.ibm.wala.cast.ir.translator, + com.ibm.wala.cast.loader, + com.ibm.wala.cast.plugin, + com.ibm.wala.cast.tree, + com.ibm.wala.cast.tree.impl, + com.ibm.wala.cast.tree.visit, + com.ibm.wala.cast.types, + com.ibm.wala.cast.util + diff --git a/com.ibm.wala.cast/build.properties b/com.ibm.wala.cast/build.properties new file mode 100644 index 000000000..c820afa01 --- /dev/null +++ b/com.ibm.wala.cast/build.properties @@ -0,0 +1,4 @@ +source.. = source/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/com.ibm.wala.cast/build.xml b/com.ibm.wala.cast/build.xml new file mode 100644 index 000000000..fe41fc819 --- /dev/null +++ b/com.ibm.wala.cast/build.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/com.ibm.wala.cast/data/the-cast-system.eps b/com.ibm.wala.cast/data/the-cast-system.eps new file mode 100644 index 000000000..6fcf78776 --- /dev/null +++ b/com.ibm.wala.cast/data/the-cast-system.eps @@ -0,0 +1,749 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner +%%Title: the-cast-system.eps +%%CreationDate: Tue Apr 18 07:55:26 2006 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%Pages: 1 +%%BoundingBox: 14 14 175 177 +%%EndComments +%%BeginProlog +% Use own dictionary to avoid conflicts +10 dict begin +%%EndProlog +%%Page: 1 1 +% Translate for offset +14.173228346456694 14.173228346456694 translate +% Translate to begin of first scanline +0 161.98724409448818 translate +159.98740157480313 -161.98724409448818 scale +% Image geometry +160 162 8 +% Transformation matrix +[ 160 0 0 162 0 0 ] +% Strings to hold RGB-samples per scanline +/rstr 160 string def +/gstr 160 string def +/bstr 160 string def +{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop} +{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop} +{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop} +true 3 +%%BeginData: 34016 ASCII Bytes +colorimage +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +]`/*%0HJiHs*t~> +]`/*%0HJiHs*t~> +]`/*%0HJiHs*t~> +]`/)P!!'1%s*t~> +]`/)P!!'1%s*t~> +]`/)P!!'1%s*t~> +]`/*1!!)kqs*t~> +]`/*1!!)kqs*t~> +]`/*1!!)kqs*t~> +ci4+FSrWI5s8N(us*t~> +ci4+FSrWI5s8N(us*t~> +ci4+FSrWI5s8N(us*t~> +ci4*p!!'t-s8N(us*t~> +ci4*p!!'t-s8N(us*t~> +ci4*p!!'t-s8N(us*t~> +ci4+G!!)ufs8N(us*t~> +ci4+G!!)ufs8N(us*t~> +ci4+G!!)ufs8N(us*t~> +cN!nEnGiLgWW.J~> +cN!nEnGiLgWW.J~> +cN!nEnGiLgWW.J~> +cN!nEnGiLgWW.J~> +cN!nEnGiLgWW.J~> +cN!nEnGiLgWW.J~> +cN!nEqu6cfVDFk@s8N(us*t~> +cN!nEqu6cfVDFk@s8N(us*t~> +cN!nEqu6cfVDFk@s8N(us*t~> +cN!nErr32aQ:;#X!)!+frrB%uJ,~> +cN!nErr32aQ:;#X!)!+frrB%uJ,~> +cN!nErr32aQ:;#X!)!+frrB%uJ,~> +e,KdBaeaPo!!(W+2Z`gV!.OeErrB%uJ,~> +e,KdBaeaPo!!(W+2Z`gV!.OeErrB%uJ,~> +e,KdBaeaPo!!(W+2Z`gV!.OeErrB%uJ,~> +ec,Yc"o/-'$S>5!R_Ie\q>^HpqYpcRJiFJP7dfmJ#M!T8"Ulr"gs,kL~> +ec,Yc"o/-'$S>5!R_Ie\q>^HpqYpcRJiFJP7dfmJ#M!T8"Ulr"gs,kL~> +ec,Yc"o/-'$S>5!R_Ie\q>^HpqYpcRJiFJP7dfmJ#M!T8"Ulr"gs,kL~> +ec,qX#"W?YTY1=*jmiBN!;uiudSU&C!!%<;rrV\%!rDru#Fj$=J,~> +ec,qX#"W?YTY1=*jmiBN!;uiudSU&C!!%<;rrV\%!rDru#Fj$=J,~> +ec,qX#"W?YTY1=*jmiBN!;uiudSU&C!!%<;rrV\%!rDru#Fj$=J,~> +eGfOHr;ZcsnGiLgrr3?"EWQ4jRH"+I!&sWO%+QR&"_>RDn[("N!2e*BJ,~> +eGfOHr;ZcsnGiLgrr3?"EWQ4jRH"+I!&sWO%+QR&"_>RDn[("N!2e*BJ,~> +eGfOHr;ZcsnGiLgrr3?"EWQ4jRH"+I!&sWO%+QR&"_>RDn[("N!2e*BJ,~> +cN!nEnGiLgs8N8T-iaR8r;Q]tp&H!)rrgRZ!%H@orri$X!#PFWs*t~> +cN!nEnGiLgs8N8T-iaR8r;Q]tp&H!)rrgRZ!%H@orri$X!#PFWs*t~> +cN!nEnGiLgs8N8T-iaR8r;Q]tp&H!)rrgRZ!%H@orri$X!#PFWs*t~> +cN!nEnGiLg"ol:J!&)t$rrE*,q#:KQ'`^DeqYpZ.!!'7Ms*t~> +cN!nEnGiLg"ol:J!&)t$rrE*,q#:KQ'`^DeqYpZ.!!'7Ms*t~> +cN!nEnGiLg"ol:J!&)t$rrE*,q#:KQ'`^DeqYpZ.!!'7Ms*t~> +cN!nEnGiLg"NCcK9_8,\!<<5trri*M!&O9Frs%hnBbUOIR*bk`~> +cN!nEnGiLg"NCcK9_8,\!<<5trri*M!&O9Frs%hnBbUOIR*bk`~> +cN!nEnGiLg"NCcK9_8,\!<<5trri*M!&O9Frs%hnBbUOIR*bk`~> +cN!nEnGiLg!tbNBrV?Kn!;ZX%H2nfEs8(!,@4;6V!!3^Wq9].l~> +cN!nEnGiLg!tbNBrV?Kn!;ZX%H2nfEs8(!,@4;6V!!3^Wq9].l~> +cN!nEnGiLg!tbNBrV?Kn!;ZX%H2nfEs8(!,@4;6V!!3^Wq9].l~> +cN!nEnGiIf!Fu-(s8N)qrs%?c!,-=3#lO`+!@hljps/ni~> +cN!nEnGiIf!Fu-(s8N)qrs%?c!,-=3#lO`+!@hljps/ni~> +cN!nEnGiIf!Fu-(s8N)qrs%?c!,-=3#lO`+!@hljps/ni~> +cN!nEnGiLg!Drahs8N)qrr?^/!!F9:J[b'is*t~> +cN!nEnGiLg!Drahs8N)qrr?^/!!F9:J[b'is*t~> +cN!nEnGiLg!Drahs8N)qrr?^/!!F9:J[b'is*t~> +cN!nEnGiLg!;?-drrDrr#Or*#+B!p&lG`dR~> +cN!nEnGiLg!;?-drrDrr#Or*#+B!p&lG`dR~> +cN!nEnGiLg!;?-drrDrr#Or*#+B!p&lG`dR~> +cN!nEp\t<^YO_YlrrD`lrrDrr!hfTK_#Jo~> +cN!nEp\t<^YO_YlrrD`lrrDrr!hfTK_#Jo~> +cN!nEp\t<^YO_YlrrD`lrrDrr!hfTK_#Jo~> +cN!nEp\t;/!*T:#rrD`lrrDrr!aYk^_#Jo~> +cN!nEp\t;/!*T:#rrD`lrrDrr!aYk^_#Jo~> +cN!nEp\t;/!*T:#rrD`lrrDrr!aYk^_#Jo~> +cN!nEq#:HK$ijH/s8N)ls8N)rrrObPaS#Q8d3(F:d/SU~> +cN!nEq#:HK$ijH/s8N)ls8N)rrrObPaS#Q8d3(F:d/SU~> +cN!nEq#:HK$ijH/s8N)ls8N)rrrObPaS#Q8d3(F:d/SU~> +cN!nEq>UT_-NGFVrVultp&G$lqu6^-!:fa^"-*?]`mFa9~> +cN!nEq>UT_-NGFVrVultp&G$lqu6^-!:fa^"-*?]`mFa9~> +cN!nEq>UT_-NGFVrVultp&G$lqu6^-!:fa^"-*?]`mFa9~> +cN!nEqYp]\0*!E\r;Zcsp&G$lqu6^"!;uQj"6:*q>gNG#~> +cN!nEqYp]\0*!E\r;Zcsp&G$lqu6^"!;uQj"6:*q>gNG#~> +cN!nEqYp]\0*!E\r;Zcsp&G$lqu6^"!;uQj"6:*q>gNG#~> +cN!nEqu6f:)urCoqu?Zrp&G$lqu6^/!:0CZ"Rn#D2YGDrJ,~> +cN!nEqu6f:)urCoqu?Zrp&G$lqu6^/!:0CZ"Rn#D2YGDrJ,~> +cN!nEqu6f:)urCoqu?Zrp&G$lqu6^/!:0CZ"Rn#D2YGDrJ,~> +cN!nErVm&mEruD_r;-Hn!;6Bl!;lct3<6Vbrrh@7!&O)hs*t~> +cN!nErVm&mEruD_r;-Hn!;6Bl!;lct3<6Vbrrh@7!&O)hs*t~> +cN!nErVm&mEruD_r;-Hn!;6Bl!;lct3<6Vbrrh@7!&O)hs*t~> +cN!nEs8N9"RMc)@Xn_qr!;6Bl!;lctM?$9Frrr=l&HGJpc2W:~> +cN!nEs8N9"RMc)@Xn_qr!;6Bl!;lctM?$9Frrr=l&HGJpc2W:~> +cN!nEs8N9"RMc)@Xn_qr!;6Bl!;lctM?$9Frrr=l&HGJpc2W:~> +cN!nE#2c1$!!$'cp](6np&G$lqu7/r*<8dHmelOoKI$U$JGm^lJ,~> +cN!nE#2c1$!!$'cp](6np&G$lqu7/r*<8dHmelOoKI$U$JGm^lJ,~> +cN!nE#2c1$!!$'cp](6np&G$lqu7/r*<8dHmelOoKI$U$JGm^lJ,~> +cMn(\!!`K(.CAgK"7-!fg@tUL`;fnuqu6]A(A\"4!DLtbs*t~> +cMn(\!!`K(.CAgK"7-!fg@tUL`;fnuqu6]A(A\"4!DLtbs*t~> +cMn(\!!`K(.CAgK"7-!fg@tUL`;fnuqu6]A(A\"4!DLtbs*t~> +cMn'+&/%^>rUp0mi!h'rp\t??&3fsers7t?1CjR$5(VG/s*t~> +cMn'+&/%^>rUp0mi!h'rp\t??&3fsers7t?1CjR$5(VG/s*t~> +cMn'+&/%^>rUp0mi!h'rp\t??&3fsers7t?1CjR$5(VG/s*t~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcG6>!W:F=s*t~> +JcG6>!W:F=s*t~> +JcG6>!W:F=s*t~> +JcG<@"Rq"M9%rt +JcG<@"Rq"M9%rt +JcG<@"Rq"M9%rt +JcG?A#0S;-'b +JcG?A#0S;-'b +JcG?A#0S;-'b +nGboQmGljD_S*:XYH=gnR\6agWNND4N.?Y0C1L^M:JYY)<`_aX5!VG,6qL'L8kVcM@U<&C9M8?$ +=_M8aJ7(uC:e!oPr_,CG8OG^46UOFF90ka-5W_M@?@uEG6;C?Q8Ol376VC3P;cm+)C3"E,CjV>< +R%pXhP)P`j,9J!>&epW)s*t~> +nGboQmGljD_S*:XYH=gnR\6agWNND4N.?Y0C1L^M:JYY)<`_aX5!VG,6qL'L8kVcM@U<&C9M8?$ +=_M8aJ7(uC:e!oPr_,CG8OG^46UOFF90ka-5W_M@?@uEG6;C?Q8Ol376VC3P;cm+)C3"E,CjV>< +R%pXhP)P`j,9J!>&epW)s*t~> +nGboQmGljD_S*:XYH=gnR\6agWNND4N.?Y0C1L^M:JYY)<`_aX5!VG,6qL'L8kVcM@U<&C9M8?$ +=_M8aJ7(uC:e!oPr_,CG8OG^46UOFF90ka-5W_M@?@uEG6;C?Q8Ol376VC3P;cm+)C3"E,CjV>< +R%pXhP)P`j,9J!>&epW)s*t~> +pA\gnZ@>b2)&F,&%hK3]&JQ9i@NZ6n&1KY3=_Air)BL^r7kbo",<-eg*u>J!(D%W1)]KSN,UFfb +0/P@5-QtrG0/H..-m9]S(+LXO*$?@F*$?CE)&aP4&/#T\%4=#)8IH1K-6X?K+V>M-&e>N`%hTKs +>%/Td%hL0N8Qf[K)]BbS3_(kD(adi.s*t~> +pA\gnZ@>b2)&F,&%hK3]&JQ9i@NZ6n&1KY3=_Air)BL^r7kbo",<-eg*u>J!(D%W1)]KSN,UFfb +0/P@5-QtrG0/H..-m9]S(+LXO*$?@F*$?CE)&aP4&/#T\%4=#)8IH1K-6X?K+V>M-&e>N`%hTKs +>%/Td%hL0N8Qf[K)]BbS3_(kD(adi.s*t~> +pA\gnZ@>b2)&F,&%hK3]&JQ9i@NZ6n&1KY3=_Air)BL^r7kbo",<-eg*u>J!(D%W1)]KSN,UFfb +0/P@5-QtrG0/H..-m9]S(+LXO*$?@F*$?CE)&aP4&/#T\%4=#)8IH1K-6X?K+V>M-&e>N`%hTKs +>%/Td%hL0N8Qf[K)]BbS3_(kD(adi.s*t~> +p]#T[;'?Ye%hK9b(D@K$((q]ACf25d&/#Tr-6\",p=BY*#]e<(Dn5:(*k7E*[;pJ&eu$.5s$(u&g7u&%hK9b(D@K$((q]A +Cf25d&/#Te*@;gD'bh8l+!;a_5s%bPqY:)@~> +p]#T[;'?Ye%hK9b(D@K$((q]ACf25d&/#Tr-6\",p=BY*#]e<(Dn5:(*k7E*[;pJ&eu$.5s$(u&g7u&%hK9b(D@K$((q]A +Cf25d&/#Te*@;gD'bh8l+!;a_5s%bPqY:)@~> +p]#T[;'?Ye%hK9b(D@K$((q]ACf25d&/#Tr-6\",p=BY*#]e<(Dn5:(*k7E*[;pJ&eu$.5s$(u&g7u&%hK9b(D@K$((q]A +Cf25d&/#Te*@;gD'bh8l+!;a_5s%bPqY:)@~> +p]#M$'H7o()'Tt:+!D[pCfDZ#+%dar)E&uX,UXZT*#K2"-Pd[X.OcQ--lsEG&/Q&t+ +p]#M$'H7o()'Tt:+!D[pCfDZ#+%dar)E&uX,UXZT*#K2"-Pd[X.OcQ--lsEG&/Q&t+ +p]#M$'H7o()'Tt:+!D[pCfDZ#+%dar)E&uX,UXZT*#K2"-Pd[X.OcQ--lsEG&/Q&t+ +p]"W(<&Q!B-n6r33(PVR6TZe2'1l\E=\)=h2a'5f3%Qd2*YT,4-T`h"0,5$8'GqW +p]"W(<&Q!B-n6r33(PVR6TZe2'1l\E=\)=h2a'5f3%Qd2*YT,4-T`h"0,5$8'GqW +p]"W(<&Q!B-n6r33(PVR6TZe2'1l\E=\)=h2a'5f3%Qd2*YT,4-T`h"0,5$8'GqW +p]"#;(E4,$',V?%'eVp65Xmms.o14>(cb&::c^EtC11Kq()%5u,O=,:Fs&,pt;l(`+#/'b1ir-R(,Y%hKQs-l3g<&/,ln*#1(p2aBhq +3@dmH0,Q]=/5SAa5AFV7,Sh%))^@O(NVNO(~> +p]"#;(E4,$',V?%'eVp65Xmms.o14>(cb&::c^EtC11Kq()%5u,O=,:Fs&,pt;l(`+#/'b1ir-R(,Y%hKQs-l3g<&/,ln*#1(p2aBhq +3@dmH0,Q]=/5SAa5AFV7,Sh%))^@O(NVNO(~> +p]"#;(E4,$',V?%'eVp65Xmms.o14>(cb&::c^EtC11Kq()%5u,O=,:Fs&,pt;l(`+#/'b1ir-R(,Y%hKQs-l3g<&/,ln*#1(p2aBhq +3@dmH0,Q]=/5SAa5AFV7,Sh%))^@O(NVNO(~> +p]"V=,S(k9/NQ0_0fi')5#EFJ-o4:R1J^"F+sJ'L.6:ir)A!T80g.92&g9%C(`sYD4=2@'*YSu* +*ZuLC'H.fB6:ELE*@E]o.2WpI+rqXH+=83E&J?#r&Io3c(DJ23rX^Fp,S(k9/NQ0_0fi')5#EFJ +-o4:R1J^"F+sJ'L.6:ir)A!T81kk/fs*t~> +p]"V=,S(k9/NQ0_0fi')5#EFJ-o4:R1J^"F+sJ'L.6:ir)A!T80g.92&g9%C(`sYD4=2@'*YSu* +*ZuLC'H.fB6:ELE*@E]o.2WpI+rqXH+=83E&J?#r&Io3c(DJ23rX^Fp,S(k9/NQ0_0fi')5#EFJ +-o4:R1J^"F+sJ'L.6:ir)A!T81kk/fs*t~> +p]"V=,S(k9/NQ0_0fi')5#EFJ-o4:R1J^"F+sJ'L.6:ir)A!T80g.92&g9%C(`sYD4=2@'*YSu* +*ZuLC'H.fB6:ELE*@E]o.2WpI+rqXH+=83E&J?#r&Io3c(DJ23rX^Fp,S(k9/NQ0_0fi')5#EFJ +-o4:R1J^"F+sJ'L.6:ir)A!T81kk/fs*t~> +o)DKS2&-o>'Gqi/*#]kH1H%-P4=V'Gqi/*#]kH1H%-P +4=V +o)DKS2&-o>'Gqi/*#]kH1H%-P4=V'Gqi/*#]kH1H%-P +4=V +o)DKS2&-o>'Gqi/*#]kH1H%-P4=V'Gqi/*#]kH1H%-P +4=V +o)Eem)AEer&eP`g'GW>],p=Zb.5*7n(_mYn&/QT[4Z>/C+=8-K*ucRq,S:\?)Cm6k///X/(`O8: ++rhXH/5&>a/05K?/MA=r(_n&.()\&*)&sG0+:f2=3[>RX*>8u#AmQu-)AEer&eP`g'GW>],p=Zb +&Lf@b*>fM(%M0F%6p3Ib,r,>ls*t~> +o)Eem)AEer&eP`g'GW>],p=Zb.5*7n(_mYn&/QT[4Z>/C+=8-K*ucRq,S:\?)Cm6k///X/(`O8: ++rhXH/5&>a/05K?/MA=r(_n&.()\&*)&sG0+:f2=3[>RX*>8u#AmQu-)AEer&eP`g'GW>],p=Zb +&Lf@b*>fM(%M0F%6p3Ib,r,>ls*t~> +o)Eem)AEer&eP`g'GW>],p=Zb.5*7n(_mYn&/QT[4Z>/C+=8-K*ucRq,S:\?)Cm6k///X/(`O8: ++rhXH/5&>a/05K?/MA=r(_n&.()\&*)&sG0+:f2=3[>RX*>8u#AmQu-)AEer&eP`g'GW>],p=Zb +&Lf@b*>fM(%M0F%6p3Ib,r,>ls*t~> +o)ErN,U=?D&/5in(aV3\*>]S5,9.F5&fN);,q:i1;cbb2*$6:I*YTVS65:4J)C6a]/g1iB)C$%4 +(E+MF0fq9b8h(eu(Gn0/-5dsE'c.o0*$c[E(`Er!(EO,)*Z,Iu*HZ?E,U=?D&/5in(aV3\*>]S5 +,9.F5$kaI**@30o1fII31NrKlJ,~> +o)ErN,U=?D&/5in(aV3\*>]S5,9.F5&fN);,q:i1;cbb2*$6:I*YTVS65:4J)C6a]/g1iB)C$%4 +(E+MF0fq9b8h(eu(Gn0/-5dsE'c.o0*$c[E(`Er!(EO,)*Z,Iu*HZ?E,U=?D&/5in(aV3\*>]S5 +,9.F5$kaI**@30o1fII31NrKlJ,~> +o)ErN,U=?D&/5in(aV3\*>]S5,9.F5&fN);,q:i1;cbb2*$6:I*YTVS65:4J)C6a]/g1iB)C$%4 +(E+MF0fq9b8h(eu(Gn0/-5dsE'c.o0*$c[E(`Er!(EO,)*Z,Iu*HZ?E,U=?D&/5in(aV3\*>]S5 +,9.F5$kaI**@30o1fII31NrKlJ,~> +o)B<9-S6Pb*?67J0K^`t%hK43C0OqSB2i/5$kH7=&T#l.ooqW>Zb-+:gfPu<`r3j7moj::fp1B/1W5) +.O?;_-7L>e,Wd_5-nn1M`V0=^~> +o)B<9-S6Pb*?67J0K^`t%hK43C0OqSB2i/5$kH7=&T#l.ooqW>Zb-+:gfPu<`r3j7moj::fp1B/1W5) +.O?;_-7L>e,Wd_5-nn1M`V0=^~> +o)B<9-S6Pb*?67J0K^`t%hK43C0OqSB2i/5$kH7=&T#l.ooqW>Zb-+:gfPu<`r3j7moj::fp1B/1W5) +.O?;_-7L>e,Wd_5-nn1M`V0=^~> +o)BC&Fc)TWYI;9lg"kB>k3;=)p%\HKrr`5sqYp3gJ,~> +o)BC&Fc)TWYI;9lg"kB>k3;=)p%\HKrr`5sqYp3gJ,~> +o)BC&Fc)TWYI;9lg"kB>k3;=)p%\HKrr`5sqYp3gJ,~> +_Z'c<>ms!XV>l&~> +_Z'c<>ms!XV>l&~> +_Z'c<>ms!XV>l&~> +_Z'V8rVuq.V>l&~> +_Z'V8rVuq.V>l&~> +_Z'V8rVuq.V>l&~> +li.@9JOgsn";E=VK>I?Drr>^k!!%MFs*t~> +li.@9JOgsn";E=VK>I?Drr>^k!!%MFs*t~> +li.@9JOgsn";E=VK>I?Drr>^k!!%MFs*t~> +mf*@dT.9O7!Y8b_kPkSU#lXf(etrCs~> +mf*@dT.9O7!Y8b_kPkSU#lXf(etrCs~> +mf*@dT.9O7!Y8b_kPkSU#lXf(etrCs~> +n,EF50_#,D7b$]&!2]Vo!61l8J,~> +n,EF50_#,D7b$]&!2]Vo!61l8J,~> +n,EF50_#,D7b$]&!2]Vo!61l8J,~> +nG`NX#Q=]2$=9CUlh]krZ?JJ9rVus&OQuiG2Z3UUM5C6&~> +nG`NX#Q=]2$=9CUlh]krZ?JJ9rVus&OQuiG2Z3UUM5C6&~> +nG`NX#Q=]2$=9CUlh]krZ?JJ9rVus&OQuiG2Z3UUM5C6&~> +nc&T@rW!!*JaN43!pY7@rVuq_m/I:-!!!N5!'R1YJ,~> +nc&T@rW!!*JaN43!pY7@rVuq_m/I:-!!!N5!'R1YJ,~> +nc&T@rW!!*JaN43!pY7@rVuq_m/I:-!!!N5!'R1YJ,~> +o)A]QrVusTf^o+G]`J06*UNe2;#gT8:&k@X`r?21;]mC$k5Tr~> +o)A]QrVusTf^o+G]`J06*UNe2;#gT8:&k@X`r?21;]mC$k5Tr~> +o)A]QrVusTf^o+G]`J06*UNe2;#gT8:&k@X`r?21;]mC$k5Tr~> +oD\uq!WW3pp$r%a:&k8EmJdIJ!WW8SXoJH]`r?%TrVur;k5Tr~> +oD\uq!WW3pp$r%a:&k8EmJdIJ!WW8SXoJH]`r?%TrVur;k5Tr~> +oD\uq!WW3pp$r%a:&k8EmJdIJ!WW8SXoJH]`r?%TrVur;k5Tr~> +o`#*D#QOj$r:'^g`XirsmJdH/!!#Feq%E`]`r?&7rW)'[J,~> +o`#*D#QOj$r:'^g`XirsmJdH/!!#Feq%E`]`r?&7rW)'[J,~> +o`#*D#QOj$r:'^g`XirsmJdH/!!#Feq%E`]`r?&7rW)'[J,~> +p&>3j/H>c5q!S.^rTsOkmgK0rXoJE +p&>3j/H>c5q!S.^rTsOkmgK0rXoJE +p&>3j/H>c5q!S.^rTsOkmgK0rXoJE +p&>/7!!!esfDc27!!!u8s8U=D!,'=OrW)'[J,~> +p&>/7!!!esfDc27!!!u8s8U=D!,'=OrW)'[J,~> +p&>/7!!!esfDc27!!!u8s8U=D!,'=OrW)'[J,~> +pAY9E!rr>-fDc!N*<6(irVlsO!"JP?s8E#[s*t~> +pAY9E!rr>-fDc!N*<6(irVlsO!"JP?s8E#[s*t~> +pAY9E!rr>-fDc!N*<6(irVlsO!"JP?s8E#[s*t~> +pAY4b!!#gGrrf2!!!MH_rr\2[!1Cn-rW)`n"SLH]N3W!SJ,~> +pAY4b!!#gGrrf2!!!MH_rr\2[!1Cn-rW)`n"SLH]N3W!SJ,~> +pAY4b!!#gGrrf2!!!MH_rr\2[!1Cn-rW)`n"SLH]N3W!SJ,~> +p\tB/!!!/Wf)Gh0!!$!rrr_Hf!&2InrW!5oe[_6%AP"Hcqu?`7o`'F~> +p\tB/!!!/Wf)Gh0!!$!rrr_Hf!&2InrW!5oe[_6%AP"Hcqu?`7o`'F~> +p\tB/!!!/Wf)Gh0!!$!rrr_Hf!&2InrW!5oe[_6%AP"Hcqu?`7o`'F~> +p\t=c!!$KZrrBq8!!'_0rrYmo!5mgr$i.i1C-F$_#R`,2nFQ\L!!&bcs*t~> +p\t=c!!$KZrrBq8!!'_0rrYmo!5mgr$i.i1C-F$_#R`,2nFQ\L!!&bcs*t~> +p\t=c!!$KZrrBq8!!'_0rrYmo!5mgr$i.i1C-F$_#R`,2nFQ\L!!&bcs*t~> +q#:KN!<<2Uf)GhK!!"GDrr];%!*84]"7Dpa%JKi&1&CnSr7ncED+Gl@!!*qso`'F~> +q#:KN!<<2Uf)GhK!!"GDrr];%!*84]"7Dpa%JKi&1&CnSr7ncED+Gl@!!*qso`'F~> +q#:KN!<<2Uf)GhK!!"GDrr];%!*84]"7Dpa%JKi&1&CnSr7ncED+Gl@!!*qso`'F~> +q#:G8!!#^Drrh*Y!!&,Wrri-1!!M?GrrV%l$1n2t)Z9U9\Jk#=#89!uI%J18rpp)>~> +q#:G8!!#^Drrh*Y!!&,Wrri-1!!M?GrrV%l$1n2t)Z9U9\Jk#=#89!uI%J18rpp)>~> +q#:G8!!#^Drrh*Y!!&,Wrri-1!!M?GrrV%l$1n2t)Z9U9\Jk#=#89!uI%J18rpp)>~> +q>UTr(B=HCf)Gkh!!!Aqq>UP3!!%6.rrV.`"8r3-'2=4acKOirgN6Z8r;QaRp&G5+LT8VglMlA~> +q>UTr(B=HCf)Gkh!!!Aqq>UP3!!%6.rrV.`"8r3-'2=4acKOirgN6Z8r;QaRp&G5+LT8VglMlA~> +q>UTr(B=HCf)Gkh!!!Aqq>UP3!!%6.rrV.`"8r3-'2=4acKOirgN6Z8r;QaRp&G5+LT8VglMlA~> +q>UT5!!!f3fDc!B$NL0;q#:K>!!!W'm/I*P$iU,.$>.!Lnc&l"!!! +q>UT5!!!f3fDc!B$NL0;q#:K>!!!W'm/I*P$iU,.$>.!Lnc&l"!!! +q>UT5!!!f3fDc!B$NL0;q#:K>!!!W'm/I*P$iU,.$>.!Lnc&l"!!! +q>UP6!!$]`rr@oT!!(: +q>UP6!!$]`rr@oT!!(: +q>UP6!!$]`rr@oT!!(: +q>UOC!!'@Wrri3=!!"tOrre/Y!$_@1rrN!lrVusdiT't;!9O62~> +q>UOC!!'@Wrri3=!!"tOrre/Y!$_@1rrN!lrVusdiT't;!9O62~> +q>UOC!!'@Wrri3=!!"tOrre/Y!$_@1rrN!lrVusdiT't;!9O62~> +qYp][!!!2qfDbiIrVuqkpAY9X!rr>"nG`K'rVut +qYp][!!!2qfDbiIrVuqkpAY9X!rr>"nG`K'rVut +qYp][!!!2qfDbiIrVuqkpAY9X!rr>"nG`K'rVut +qYpYp!!"t/rtI9i!#,"jfYt.gNI#5:5qX,X!!"eErrB>'!!$rqs8E#[s*t~> +qYpYp!!"t/rtI9i!#,"jfYt.gNI#5:5qX,X!!"eErrB>'!!$rqs8E#[s*t~> +qYpYp!!"t/rtI9i!#,"jfYt.gNI#5:5qX,X!!"eErrB>'!!$rqs8E#[s*t~> +qYpY?!!$rhrrBn7!!*-%nGiR$oD]!l+92C*rS[_T!9O62~> +qYpY?!!$rhrrBn7!!*-%nGiR$oD]!l+92C*rS[_T!9O62~> +qYpY?!!$rhrrBn7!!*-%nGiR$oD]!l+92C*rS[_T!9O62~> +qYpXj!!&VBrr>ja!!E?1!!#@WrrfM*!!M'Lrs._N6lcIQ@aFZGrW)'[J,~> +qYpXj!!&VBrr>ja!!E?1!!#@WrrfM*!!M'Lrs._N6lcIQ@aFZGrW)'[J,~> +qYpXj!!&VBrr>ja!!E?1!!#@WrrfM*!!M'Lrs._N6lcIQ@aFZGrW)'[J,~> +qYpXE!!('lrtsJl!!!cd4A/jlH&.fa[D^STo)@hY!!(+4rrZR-!*]*r!nL]^qZ$ZuD>Nr*rW)'[ +J,~> +qYpXE!!('lrtsJl!!!cd4A/jlH&.fa[D^STo)@hY!!(+4rrZR-!*]*r!nL]^qZ$ZuD>Nr*rW)'[ +J,~> +qYpXE!!('lrtsJl!!!cd4A/jlH&.fa[D^STo)@hY!!(+4rrZR-!*]*r!nL]^qZ$ZuD>Nr*rW)'[ +J,~> +qYpX3!!)-5rrd- +qYpX3!!)-5rrd- +qYpX3!!)-5rrd- +qYpX$!!)cHrrhcu!!$j)rrh*Z!!1O@rrW]1!9F"V!psq2r;[-`QeD)bF9;LCU%\Nc!9O62~> +qYpX$!!)cHrrhcu!!$j)rrh*Z!!1O@rrW]1!9F"V!psq2r;[-`QeD)bF9;LCU%\Nc!9O62~> +qYpX$!!)cHrrhcu!!$j)rrh*Z!!1O@rrW]1!9F"V!psq2r;[-`QeD)bF9;LCU%\Nc!9O62~> +qYpX#!!)uNrre,X!!M3JrrZ:%!*Ajn!sAT(q>C6oq2Z0e!!,L,qu6bJ!!#:Xs8E#[s*t~> +qYpX#!!)uNrre,X!!M3JrrZ:%!*Ajn!sAT(q>C6oq2Z0e!!,L,qu6bJ!!#:Xs8E#[s*t~> +qYpX#!!)uNrre,X!!M3JrrZ:%!*Ajn!sAT(q>C6oq2Z0e!!,L,qu6bJ!!#:Xs8E#[s*t~> +qYpX-!!)ZFrri0AppAb*ljo9i~> +qYpX-!!)ZFrri0AppAb*ljo9i~> +qYpX-!!)ZFrri0AppAb*ljo9i~> +qYpX?!!)-7rrAko!!(I7rrY[i!+5I"#>bC#Hh>sK-2dfE,,t>:"8)Wo"nquq!9O62~> +qYpX?!!)-7rrAko!!(I7rrY[i!+5I"#>bC#Hh>sK-2dfE,,t>:"8)Wo"nquq!9O62~> +qYpX?!!)-7rrAko!!(I7rrY[i!+5I"#>bC#Hh>sK-2dfE,,t>:"8)Wo"nquq!9O62~> +qYpX]!!($mrrY%W!(uVX"MFd8"Q&nQ!3Z(s!Z$popAY6K!!!c-s8E#hrr_>?X8_noJ,~> +qYpX]!!($mrrY%W!(uVX"MFd8"Q&nQ!3Z(s!Z$popAY6K!!!c-s8E#hrr_>?X8_noJ,~> +qYpX]!!($mrrY%W!(uVX"MFd8"Q&nQ!3Z(s!Z$popAY6K!!!c-s8E#hrr_>?X8_noJ,~> +qYpY+!!&YTrrL^)pAY-.rVur7li.&E!!$U)rrN*eqZ$[9MtHZA"/#Vo1%tYH!:p-l8,rXIq#>j~> +qYpY+!!&YTrrL^)pAY-.rVur7li.&E!!$U)rrN*eqZ$[9MtHZA"/#Vo1%tYH!:p-l8,rXIq#>j~> +qYpY+!!&YTrrL^)pAY-.rVur7li.&E!!$U)rrN*eqZ$[9MtHZA"/#Vo1%tYH!:p-l8,rXIq#>j~> +qYpY^!!$`trrdTI!*0!mrrZ!r!'0?E"KVS'#3,CW#P<'X"s?sLq==Of7fWO%pAb*loD\sO%0-B* +q#>j~> +qYpY^!!$`trrdTI!*0!mrrZ!r!'0?E"KVS'#3,CW#P<'X"s?sLq==Of7fWO%pAb*loD\sO%0-B* +q#>j~> +qYpY^!!$`trrdTI!*0!mrrZ!r!'0?E"KVS'#3,CW#P<'X"s?sLq==Of7fWO%pAb*loD\sO%0-B* +q#>j~> +qYpZ@!!"A2rrMs%rVurFq>UTP!WW5)lMh"c-3+$\iVs&'!<<,'pAb*lo`"sd1]@@SX8)^F~> +qYpZ@!!"A2rrMs%rVurFq>UTP!WW5)lMh"c-3+$\iVs&'!<<,'pAb*lo`"sd1]@@SX8)^F~> +qYpZ@!!"A2rrMs%rVurFq>UTP!WW5)lMh"c-3+$\iVs&'!<<,'pAb*lo`"sd1]@@SX8)^F~> +qYp]s('"?`li-t1rVus$kP>,\CB+>`rosFcRfEEnk2ZIFpFuXJ(]3q+rW)Wk!W#Rj!!%NCs*t~> +qYp]s('"?`li-t1rVus$kP>,\CB+>`rosFcRfEEnk2ZIFpFuXJ(]3q+rW)Wk!W#Rj!!%NCs*t~> +qYp]s('"?`li-t1rVus$kP>,\CB+>`rosFcRfEEnk2ZIFpFuXJ(]3q+rW)Wk!W#Rj!!%NCs*t~> +q>UP+!!$d#rrM+%rVuqJq>UTc$NL0ukl1eZ&HDfNj8T*frVuqap&G!kpAY0f:]:=oKD,=q~> +q>UP+!!$d#rrM+%rVuqJq>UTc$NL0ukl1eZ&HDfNj8T*frVuqap&G!kpAY0f:]:=oKD,=q~> +q>UP+!!$d#rrM+%rVuqJq>UTc$NL0ukl1eZ&HDfNj8T*frVuqap&G!kpAY0f:]:=oKD,=q~> +q>UT;!!!Admf*=:+T;?@FSPk=LB%;gpuhY[ErZ1JmcFHKL].8S2Z37JrW)]m"m.]C!!](gs*t~> +q>UT;!!!Admf*=:+T;?@FSPk=LB%;gpuhY[ErZ1JmcFHKL].8S2Z37JrW)]m"m.]C!!](gs*t~> +q>UT;!!!Admf*=:+T;?@FSPk=LB%;gpuhY[ErZ1JmcFHKL].8S2Z37JrW)]m"m.]C!!](gs*t~> +q#:FS!!#pcrrK,/rVuqQq#:Kn)ZTk[k5PG5rVuqOq>UN8K\uA#!W?g5!!*eno`+mjq#:N'('"=T +aRoL_~> +q#:FS!!#pcrrK,/rVuqQq#:Kn)ZTk[k5PG5rVuqOq>UN8K\uA#!W?g5!!*eno`+mjq#:N'('"=T +aRoL_~> +q#:FS!!#pcrrK,/rVuqQq#:Kn)ZTk[k5PG5rVuqOq>UN8K\uA#!W?g5!!*eno`+mjq#:N'('"=T +aRoL_~> +q#:?3rVuqZo)AaU=oJC%#G:bj!2KMn!7p93"?-;\*;o^6"53hW:%SAciCEkI!>!EGs8E#prrM=g +rVusglgt.,~> +q#:?3rVuqZo)AaU=oJC%#G:bj!2KMn!7p93"?-;\*;o^6"53hW:%SAciCEkI!>!EGs8E#prrM=g +rVusglgt.,~> +q#:?3rVuqZo)AaU=oJC%#G:bj!2KMn!7p93"?-;\*;o^6"53hW:%SAciCEkI!>!EGs8E#prrM=g +rVusglgt.,~> +p\tA,!!!(dp&>*dL(=1_!>riMrrY"V!&!@4!/^[T!4)M%".0&g;t^.lqiD6c!!*qZo)J[hr;R#r +LCX@b"FpC@s*t~> +p\tA,!!!(dp&>*dL(=1_!>riMrrY"V!&!@4!/^[T!4)M%".0&g;t^.lqiD6c!!*qZo)J[hr;R#r +LCX@b"FpC@s*t~> +p\tA,!!!(dp&>*dL(=1_!>riMrrY"V!&!@4!/^[T!4)M%".0&g;t^.lqiD6c!!*qZo)J[hr;R#r +LCX@b"FpC@s*t~> +p\t9g2#[IU?L7Lf!pP4Lr;ZjhkP"oU`Voi;ETI-"ao28?=o84%RfEErVYL/mo8ask!!,:Cnc/Rg +"oeQ%pQ?Ho!!+k#nGe"~> +p\t9g2#[IU?L7Lf!pP4Lr;ZjhkP"oU`Voi;ETI-"ao28?=o84%RfEErVYL/mo8ask!!,:Cnc/Rg +"oeQ%pQ?Ho!!+k#nGe"~> +p\t9g2#[IU?L7Lf!pP4Lr;ZjhkP"oU`Voi;ETI-"ao28?=o84%RfEErVYL/mo8ask!!,:Cnc/Rg +"oeQ%pQ?Ho!!+k#nGe"~> +pAY0X0E(qX$=p#,rVuqhjSo5*rVup:qu6]a(]FC@16ToJqWcCq:^m:& +!Z77&nGiIf"5EI-)#aL:$B"cMs*t~> +pAY0X0E(qX$=p#,rVuqhjSo5*rVup:qu6]a(]FC@16ToJqWcCq:^m:& +!Z77&nGiIf"5EI-)#aL:$B"cMs*t~> +pAY0X0E(qX$=p#,rVuqhjSo5*rVup:qu6]a(]FC@16ToJqWcCq:^m:& +!Z77&nGiIf"5EI-)#aL:$B"cMs*t~> +p&>']:%J>d"(:?arr=;C!!':brrADb!!!N*rrLRlo)Jh)M"U39"9ni+.MVg]!E%\?s*t~> +p&>']:%J>d"(:?arr=;C!!':brrADb!!!N*rrLRlo)Jh)M"U39"9ni+.MVg]!E%\?s*t~> +p&>']:%J>d"(:?arr=;C!!':brrADb!!!N*rrLRlo)Jh)M"U39"9ni+.MVg]!E%\?s*t~> +oD\id-MIKA%;=Perr<9&!!(%"rr@HG!!#UdrrVh>&,6,,!_0!Ym/I&Aqu?d!9?6AuJ,~> +oD\id-MIKA%;=Perr<9&!!(%"rr@HG!!#UdrrVh>&,6,,!_0!Ym/I&Aqu?d!9?6AuJ,~> +oD\id-MIKA%;=Perr<9&!!(%"rr@HG!!#UdrrVh>&,6,,!_0!Ym/I&Aqu?d!9?6AuJ,~> +o)B*s]6-1T$3_2'CTdF#rrc7+#upc^rrgk.#Vt61rsJ=n>qQWi$nl%_kNW!Nbs;dM3.]f\rrN&H +nc++~> +o)B*s]6-1T$3_2'CTdF#rrc7+#upc^rrgk.#Vt61rsJ=n>qQWi$nl%_kNW!Nbs;dM3.]f\rrN&H +nc++~> +o)B*s]6-1T$3_2'CTdF#rrc7+#upc^rrgk.#Vt61rsJ=n>qQWi$nl%_kNW!Nbs;dM3.]f\rrN&H +nc++~> +JcGEC"Rq"M9%rk9J,~> +JcGEC"Rq"M9%rk9J,~> +JcGEC"Rq"M9%rk9J,~> +JcGHD#0S;-'b +JcGHD#0S;-'b +JcGHD#0S;-'b +oD_5TmGljD_S*:XYH=gnR\6agWNND4N.?Y0C1L^M:JYY)<`_aX5!VG,6qL'L8kVcM@U<&C9M8?$ +=_M8aJ7(uC:e!oPr_,CG8OG^46UOFF90ka-5W_M@?@uEG6;C?Q8Ol376VC3P;cm+)C3"E,CjV>< +R%pXhP)P`j,9J!>&epW&s*t~> +oD_5TmGljD_S*:XYH=gnR\6agWNND4N.?Y0C1L^M:JYY)<`_aX5!VG,6qL'L8kVcM@U<&C9M8?$ +=_M8aJ7(uC:e!oPr_,CG8OG^46UOFF90ka-5W_M@?@uEG6;C?Q8Ol376VC3P;cm+)C3"E,CjV>< +R%pXhP)P`j,9J!>&epW&s*t~> +oD_5TmGljD_S*:XYH=gnR\6agWNND4N.?Y0C1L^M:JYY)<`_aX5!VG,6qL'L8kVcM@U<&C9M8?$ +=_M8aJ7(uC:e!oPr_,CG8OG^46UOFF90ka-5W_M@?@uEG6;C?Q8Ol376VC3P;cm+)C3"E,CjV>< +R%pXhP)P`j,9J!>&epW&s*t~> +q>Y-qZ@>b2)&F,&%hK3]&JQ9i@NZ6n&1KY3=_Air)BL^r7kbo",<-eg*u>J!(D%W1)]KSN,UFfb +0/P@5-QtrG0/H..-m9]S(+LXO*$?@F*$?CE)&aP4&/#T\%4=#)8IH1K-6X?K+V>M-&e>N`%hTKs +>%/Td%hL0N8Qf[K)]BbS3_(kD(adi+s*t~> +q>Y-qZ@>b2)&F,&%hK3]&JQ9i@NZ6n&1KY3=_Air)BL^r7kbo",<-eg*u>J!(D%W1)]KSN,UFfb +0/P@5-QtrG0/H..-m9]S(+LXO*$?@F*$?CE)&aP4&/#T\%4=#)8IH1K-6X?K+V>M-&e>N`%hTKs +>%/Td%hL0N8Qf[K)]BbS3_(kD(adi+s*t~> +q>Y-qZ@>b2)&F,&%hK3]&JQ9i@NZ6n&1KY3=_Air)BL^r7kbo",<-eg*u>J!(D%W1)]KSN,UFfb +0/P@5-QtrG0/H..-m9]S(+LXO*$?@F*$?CE)&aP4&/#T\%4=#)8IH1K-6X?K+V>M-&e>N`%hTKs +>%/Td%hL0N8Qf[K)]BbS3_(kD(adi+s*t~> +qYto^;'?Ye%hK9b(D@K$((q]ACf25d&/#Tr-6\",p=BY*#]e<(Dn5:(*k7E*[;pJ&eu$.5s$(u&g7u&%hK9b(D@K$((q]A +Cf25d&/#Te*@;gD'bh8l+!;a_5s%bPqXsl=~> +qYto^;'?Ye%hK9b(D@K$((q]ACf25d&/#Tr-6\",p=BY*#]e<(Dn5:(*k7E*[;pJ&eu$.5s$(u&g7u&%hK9b(D@K$((q]A +Cf25d&/#Te*@;gD'bh8l+!;a_5s%bPqXsl=~> +qYto^;'?Ye%hK9b(D@K$((q]ACf25d&/#Tr-6\",p=BY*#]e<(Dn5:(*k7E*[;pJ&eu$.5s$(u&g7u&%hK9b(D@K$((q]A +Cf25d&/#Te*@;gD'bh8l+!;a_5s%bPqXsl=~> +qYth''H7o()'Tt:+!D[pCfDZ#+%dar)E&uX,UXZT*#K2"-Pd[X.OcQ--lsEG&/Q&t+ +qYth''H7o()'Tt:+!D[pCfDZ#+%dar)E&uX,UXZT*#K2"-Pd[X.OcQ--lsEG&/Q&t+ +qYth''H7o()'Tt:+!D[pCfDZ#+%dar)E&uX,UXZT*#K2"-Pd[X.OcQ--lsEG&/Q&t+ +qYsr+<&Q!B-n6r33(PVR6TZe2'1l\E=\)=h2a'5f3%Qd2*YT,4-T`h"0,5$8'GqW +qYsr+<&Q!B-n6r33(PVR6TZe2'1l\E=\)=h2a'5f3%Qd2*YT,4-T`h"0,5$8'GqW +qYsr+<&Q!B-n6r33(PVR6TZe2'1l\E=\)=h2a'5f3%Qd2*YT,4-T`h"0,5$8'GqW +qYs>>(E4,$',V?%'eVp65Xmms.o14>(cb&::c^EtC11Kq()%5u,O=,:Fs&,pt;l(`+#/'b1ir-R(,Y%hKQs-l3g<&/,ln*#1(p2aBhq +3@dmH0,Q]=/5SAa5AFV7,Sh%))^@O(NV3=%~> +qYs>>(E4,$',V?%'eVp65Xmms.o14>(cb&::c^EtC11Kq()%5u,O=,:Fs&,pt;l(`+#/'b1ir-R(,Y%hKQs-l3g<&/,ln*#1(p2aBhq +3@dmH0,Q]=/5SAa5AFV7,Sh%))^@O(NV3=%~> +qYs>>(E4,$',V?%'eVp65Xmms.o14>(cb&::c^EtC11Kq()%5u,O=,:Fs&,pt;l(`+#/'b1ir-R(,Y%hKQs-l3g<&/,ln*#1(p2aBhq +3@dmH0,Q]=/5SAa5AFV7,Sh%))^@O(NV3=%~> +qYsq@,S(k9/NQ0_0fi')5#EFJ-o4:R1J^"F+sJ'L.6:ir)A!T80g.92&g9%C(`sYD4=2@'*YSu* +*ZuLC'H.fB6:ELE*@E]o.2WpI+rqXH+=83E&J?#r&Io3c(DJ23rX^Fp,S(k9/NQ0_0fi')5#EFJ +-o4:R1J^"F+sJ'L.6:ir)A!T81kk/cs*t~> +qYsq@,S(k9/NQ0_0fi')5#EFJ-o4:R1J^"F+sJ'L.6:ir)A!T80g.92&g9%C(`sYD4=2@'*YSu* +*ZuLC'H.fB6:ELE*@E]o.2WpI+rqXH+=83E&J?#r&Io3c(DJ23rX^Fp,S(k9/NQ0_0fi')5#EFJ +-o4:R1J^"F+sJ'L.6:ir)A!T81kk/cs*t~> +qYsq@,S(k9/NQ0_0fi')5#EFJ-o4:R1J^"F+sJ'L.6:ir)A!T80g.92&g9%C(`sYD4=2@'*YSu* +*ZuLC'H.fB6:ELE*@E]o.2WpI+rqXH+=83E&J?#r&Io3c(DJ23rX^Fp,S(k9/NQ0_0fi')5#EFJ +-o4:R1J^"F+sJ'L.6:ir)A!T81kk/cs*t~> +p&@fV2&-o>'Gqi/*#]kH1H%-P4=V'Gqi/*#]kH1H%-P +4=V +p&@fV2&-o>'Gqi/*#]kH1H%-P4=V'Gqi/*#]kH1H%-P +4=V +p&@fV2&-o>'Gqi/*#]kH1H%-P4=V'Gqi/*#]kH1H%-P +4=V +p&B+p)AEer&eP`g'GW>],p=Zb.5*7n(_mYn&/QT[4Z>/C+=8-K*ucRq,S:\?)Cm6k///X/(`O8: ++rhXH/5&>a/05K?/MA=r(_n&.()\&*)&sG0+:f2=3[>RX*>8u#AmQu-)AEer&eP`g'GW>],p=Zb +&Lf@b*>fM(%M0F%6p3Ib,r,>is*t~> +p&B+p)AEer&eP`g'GW>],p=Zb.5*7n(_mYn&/QT[4Z>/C+=8-K*ucRq,S:\?)Cm6k///X/(`O8: ++rhXH/5&>a/05K?/MA=r(_n&.()\&*)&sG0+:f2=3[>RX*>8u#AmQu-)AEer&eP`g'GW>],p=Zb +&Lf@b*>fM(%M0F%6p3Ib,r,>is*t~> +p&B+p)AEer&eP`g'GW>],p=Zb.5*7n(_mYn&/QT[4Z>/C+=8-K*ucRq,S:\?)Cm6k///X/(`O8: ++rhXH/5&>a/05K?/MA=r(_n&.()\&*)&sG0+:f2=3[>RX*>8u#AmQu-)AEer&eP`g'GW>],p=Zb +&Lf@b*>fM(%M0F%6p3Ib,r,>is*t~> +p&B8Q,U=?D&/5in(aV3\*>]S5,9.F5&fN);,q:i1;cbb2*$6:I*YTVS65:4J)C6a]/g1iB)C$%4 +(E+MF0fq9b8h(eu(Gn0/-5dsE'c.o0*$c[E(`Er!(EO,)*Z,Iu*HZ?E,U=?D&/5in(aV3\*>]S5 +,9.F5$kaI**@30o1fII31NrBiJ,~> +p&B8Q,U=?D&/5in(aV3\*>]S5,9.F5&fN);,q:i1;cbb2*$6:I*YTVS65:4J)C6a]/g1iB)C$%4 +(E+MF0fq9b8h(eu(Gn0/-5dsE'c.o0*$c[E(`Er!(EO,)*Z,Iu*HZ?E,U=?D&/5in(aV3\*>]S5 +,9.F5$kaI**@30o1fII31NrBiJ,~> +p&B8Q,U=?D&/5in(aV3\*>]S5,9.F5&fN);,q:i1;cbb2*$6:I*YTVS65:4J)C6a]/g1iB)C$%4 +(E+MF0fq9b8h(eu(Gn0/-5dsE'c.o0*$c[E(`Er!(EO,)*Z,Iu*HZ?E,U=?D&/5in(aV3\*>]S5 +,9.F5$kaI**@30o1fII31NrBiJ,~> +p&>W<-S6Pb*?67J0K^`t%hK43C0OqSB2i/5$kH7=&T#l.ooqW>Zb-+:gfPu<`r3j7moj::fp1B/1W5) +.O?;_-7L>e,Wd_5-nn1M`Uj+[~> +p&>W<-S6Pb*?67J0K^`t%hK43C0OqSB2i/5$kH7=&T#l.ooqW>Zb-+:gfPu<`r3j7moj::fp1B/1W5) +.O?;_-7L>e,Wd_5-nn1M`Uj+[~> +p&>W<-S6Pb*?67J0K^`t%hK43C0OqSB2i/5$kH7=&T#l.ooqW>Zb-+:gfPu<`r3j7moj::fp1B/1W5) +.O?;_-7L>e,Wd_5-nn1M`Uj+[~> +p&>^)Fc)TWYI;9lg"kB>k3;=)p%\HKrr`5sqYp*dJ,~> +p&>^)Fc)TWYI;9lg"kB>k3;=)p%\HKrr`5sqYp*dJ,~> +p&>^)Fc)TWYI;9lg"kB>k3;=)p%\HKrr`5sqYp*dJ,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +Z2Xq(SrWHNs*t~> +Z2Xq(SrWHNs*t~> +Z2Xq(SrWHNs*t~> +Z2XpR!!'sFs*t~> +Z2XpR!!'sFs*t~> +Z2XpR!!'sFs*t~> +Z2Xq)!!)u*s*t~> +Z2Xq)!!)u*s*t~> +Z2Xq)!!)u*s*t~> +YlF_'[/YX~> +YlF_'[/YX~> +YlF_'[/YX~> +YlF_'[/YX~> +YlF_'[/YX~> +YlF_'[/YX~> +YlF_'qu6cfVDFjYs*t~> +YlF_'qu6cfVDFjYs*t~> +YlF_'qu6cfVDFjYs*t~> +o`#3XSn9u##6lcYg]%Q?Sn9u##6lcYp&G$lrr32aQ:;#X!(uAQ"6_0Jjneu[c!hP+a8,` +o`#3XSn9u##6lcYg]%Q?Sn9u##6lcYp&G$lrr32aQ:;#X!(uAQ"6_0Jjneu[c!hP+a8,` +o`#3XSn9u##6lcYg]%Q?Sn9u##6lcYp&G$lrr32aQ:;#X!(uAQ"6_0Jjneu[c!hP+a8,` +p\t?mUc\\S!!!Garr`.o49>9Y!"A`($LPs3JR&6Uf7u9cqu?_Gjo5Fr!!'t8rrL_Fr;ZgrqYpSj +(&e152>@-$~> +p\t?mUc\\S!!!Garr`.o49>9Y!"A`($LPs3JR&6Uf7u9cqu?_Gjo5Fr!!'t8rrL_Fr;ZgrqYpSj +(&e152>@-$~> +p\t?mUc\\S!!!Garr`.o49>9Y!"A`($LPs3JR&6Uf7u9cqu?_Gjo5Fr!!'t8rrL_Fr;ZgrqYpSj +(&e152>@-$~> +q#:c.,QIfbCo>VHq;lgpqu6_T$XE9&!d"ZVHq;lgpr;Qe5"o/-'$S>5!R_Ie\ +oD]'GCEs&l/8j8>rr_fl!<)os#kW3A!!"`+!%.XD!TluO!!!8us*t~> +q#:c.,QIfbCo>VHq;lgpqu6_T$XE9&!d"ZVHq;lgpr;Qe5"o/-'$S>5!R_Ie\ +oD]'GCEs&l/8j8>rr_fl!<)os#kW3A!!"`+!%.XD!TluO!!!8us*t~> +q#:c.,QIfbCo>VHq;lgpqu6_T$XE9&!d"ZVHq;lgpr;Qe5"o/-'$S>5!R_Ie\ +oD]'GCEs&l/8j8>rr_fl!<)os#kW3A!!"`+!%.XD!TluO!!!8us*t~> +qYpcqA,lTn\c24#"&8grlLb)Yr"f>jr;QusA,lTn\c27$$!7C&AqQbi!!)-JrrV\%!rDru#FkSi +rrE&u$+_2Y!$SWIpAba&rs5Y=!!#O(hZ*ZNs*t~> +qYpcqA,lTn\c24#"&8grlLb)Yr"f>jr;QusA,lTn\c27$$!7C&AqQbi!!)-JrrV\%!rDru#FkSi +rrE&u$+_2Y!$SWIpAba&rs5Y=!!#O(hZ*ZNs*t~> +qYpcqA,lTn\c24#"&8grlLb)Yr"f>jr;QusA,lTn\c27$$!7C&AqQbi!!)-JrrV\%!rDru#FkSi +rrE&u$+_2Y!$SWIpAba&rs5Y=!!#O(hZ*ZNs*t~> +qu6fr9`PNmnG`U>"9<]=rr]k5!7(QC"T(mn$D6hf!;ucprrDHd%+QR&"_>RDn[("N!2fYnrr<<( +ok4=*!cdo4rs8Z/s8V^u!!!\5rr;uup]#a~> +qu6fr9`PNmnG`U>"9<]=rr]k5!7(QC"T(mn$D6hf!;ucprrDHd%+QR&"_>RDn[("N!2fYnrr<<( +ok4=*!cdo4rs8Z/s8V^u!!!\5rr;uup]#a~> +qu6fr9`PNmnG`U>"9<]=rr]k5!7(QC"T(mn$D6hf!;ucprrDHd%+QR&"_>RDn[("N!2fYnrr<<( +ok4=*!cdo4rs8Z/s8V^u!!!\5rr;uup]#a~> +qu6b@!"I*=rrZm6#iYIV!b23Zr;QkA!"I*8s8N)errgRZ!%H@orri$X!#PG.s8N'&eL:Iu,K0N[ +rr<9'e0t@t5iqtErrDfnJ,~> +qu6b@!"I*=rrZm6#iYIV!b23Zr;QkA!"I*8s8N)errgRZ!%H@orri$X!#PG.s8N'&eL:Iu,K0N[ +rr<9'e0t@t5iqtErrDfnJ,~> +qu6b@!"I*=rrZm6#iYIV!b23Zr;QkA!"I*8s8N)errgRZ!%H@orri$X!#PG.s8N'&eL:Iu,K0N[ +rr<9'e0t@t5iqtErrDfnJ,~> +r;QlK!s#Rmrr_Ek!*f0s"8NN/Jc5TNe,o]Tkl:Y_n,EOH'`^DeqYpZ.!!'8$s8N'%$NL06oDARf +!!Su%!!.KGr;Zcsp]#a~> +r;QlK!s#Rmrr_Ek!*f0s"8NN/Jc5TNe,o]Tkl:Y_n,EOH'`^DeqYpZ.!!'8$s8N'%$NL06oDARf +!!Su%!!.KGr;Zcsp]#a~> +r;QlK!s#Rmrr_Ek!*f0s"8NN/Jc5TNe,o]Tkl:Y_n,EOH'`^DeqYpZ.!!'8$s8N'%$NL06oDARf +!!Su%!!.KGr;Zcsp]#a~> +r;Qh5!)2_Y"+1(LbP2#=Z2amYrVlq6!)2SUrrDQg"SaVM1\CVF#4/O-'EA-#r;Z`r!=GUts8;ou +'"7Z:rrDfnJ,~> +r;Qh5!)2_Y"+1(LbP2#=Z2amYrVlq6!)2SUrrDQg"SaVM1\CVF#4/O-'EA-#r;Z`r!=GUts8;ou +'"7Z:rrDfnJ,~> +r;Qh5!)2_Y"+1(LbP2#=Z2amYrVlq6!)2SUrrDQg"SaVM1\CVF#4/O-'EA-#r;Z`r!=GUts8;ou +'"7Z:rrDfnJ,~> +r;QgG!42P%#Pb/o(^)+8pA4dkneD-gp\t:u!&FKP![duSqYpfqVG\66,_>[_s8N)grsF&P)!:kp +c'Mif!WE'#&:+*Ls8N'"+k-5drVusUi;*EQ!;HMD~> +r;QgG!42P%#Pb/o(^)+8pA4dkneD-gp\t:u!&FKP![duSqYpfqVG\66,_>[_s8N)grsF&P)!:kp +c'Mif!WE'#&:+*Ls8N'"+k-5drVusUi;*EQ!;HMD~> +r;QgG!42P%#Pb/o(^)+8pA4dkneD-gp\t:u!&FKP![duSqYpfqVG\66,_>[_s8N)grsF&P)!:kp +c'Mif!WE'#&:+*Ls8N'"+k-5drVusUi;*EQ!;HMD~> +r;Qg(!:9X`!pP%GqZ$XJlMCM_OT5Bbq>UQj$il4`rrNH+m/6kbl$F-A!!+Y9p](6nnc&gN#68FV +3=,Q`"9BufZM=:rrr<&cp](6n!GV?(s8N)ns*t~> +r;Qg(!:9X`!pP%GqZ$XJlMCM_OT5Bbq>UQj$il4`rrNH+m/6kbl$F-A!!+Y9p](6nnc&gN#68FV +3=,Q`"9BufZM=:rrr<&cp](6n!GV?(s8N)ns*t~> +r;Qg(!:9X`!pP%GqZ$XJlMCM_OT5Bbq>UQj$il4`rrNH+m/6kbl$F-A!!+Y9p](6nnc&gN#68FV +3=,Q`"9BufZM=:rrr<&cp](6n!GV?(s8N)ns*t~> +r;Qg(!;c]p%,Yk,!!":#f)",c!+Pg)"Sj5A-2RK<"0)>%ir&fX#QX`#rs[e$#QOiMLt;FW56,0e +s8N)hrr?^/!!F9:J[b(@s8N)ms8N)ms8N)ns*t~> +r;Qg(!;c]p%,Yk,!!":#f)",c!+Pg)"Sj5A-2RK<"0)>%ir&fX#QX`#rs[e$#QOiMLt;FW56,0e +s8N)hrr?^/!!F9:J[b(@s8N)ms8N)ms8N)ns*t~> +r;Qg(!;c]p%,Yk,!!":#f)",c!+Pg)"Sj5A-2RK<"0)>%ir&fX#QX`#rs[e$#QOiMLt;FW56,0e +s8N)hrr?^/!!F9:J[b(@s8N)ms8N)ms8N)ns*t~> +r;R-]!4D='< +r;R-]!4D='< +r;R-]!4D='< +r;Qbaqu?d";8i>2!quZuq>UTs1B8*Wr;Qli#QU.errAGa!!34!`;9K8pAbBks8N)nrs.qpo)J`` +!& +r;Qbaqu?d";8i>2!quZuq>UTs1B8*Wr;Qli#QU.errAGa!!34!`;9K8pAbBks8N)nrs.qpo)J`` +!& +r;Qbaqu?d";8i>2!quZuq>UTs1B8*Wr;Qli#QU.errAGa!!34!`;9K8pAbBks8N)nrs.qpo)J`` +!& +r;R!#EtJ[6JDg5&!mgoaq#:H/!!%-=rr\qp"R>ma#6&ZU#W%"hq#:EB!#YJ1rrDfn#AF0@s8QC* +L[>'@!;?Hm!;?Hm!;HMD~> +r;R!#EtJ[6JDg5&!mgoaq#:H/!!%-=rr\qp"R>ma#6&ZU#W%"hq#:EB!#YJ1rrDfn#AF0@s8QC* +L[>'@!;?Hm!;?Hm!;HMD~> +r;R!#EtJ[6JDg5&!mgoaq#:H/!!%-=rr\qp"R>ma#6&ZU#W%"hq#:EB!#YJ1rrDfn#AF0@s8QC* +L[>'@!;?Hm!;?Hm!;HMD~> +m/I-9!(cka"%N=rhYmHU8H;6FrrRWL8GE/a!;QR"fF.a_s8OYNaS#Q8d3(F:r;ZcspAb-mpAb-m +p]#a~> +m/I-9!(cka"%N=rhYmHU8H;6FrrRWL8GE/a!;QR"fF.a_s8OYNaS#Q8d3(F:r;ZcspAb-mpAb-m +p]#a~> +m/I-9!(cka"%N=rhYmHU8H;6FrrRWL8GE/a!;QR"fF.a_s8OYNaS#Q8d3(F:r;ZcspAb-mpAb-m +p]#a~> +mJd:R&-/-mrr^RJ!*9+!"7-0kTBlLZl4Ucd-NGFVs8NQ/nb)naNW9(!r;ZcspAb-m +pAb-mp]#a~> +mJd:R&-/-mrr^RJ!*9+!"7-0kTBlLZl4Ucd-NGFVs8NQ/nb)naNW9(!r;ZcspAb-m +pAb-mp]#a~> +mJd:R&-/-mrr^RJ!*9+!"7-0kTBlLZl4Ucd-NGFVs8NQ/nb)naNW9(!r;ZcspAb-m +pAb-mp]#a~> +mf*Fg9)p"*pAYG(!!(%=s-WilnEg/XrC[,2p%SLd!;c]ujt?]_j8T&[!s&8mrr_ +mf*Fg9)p"*pAYG(!!(%=s-WilnEg/XrC[,2p%SLd!;c]ujt?]_j8T&[!s&8mrr_ +mf*Fg9)p"*pAYG(!!(%=s-WilnEg/XrC[,2p%SLd!;c]ujt?]_j8T&[!s&8mrr_ +r;QigLu7t,"T2a0!k7k&#iGpf3WK+F!)WLk!qD*(p\tBo@fQS>pAb-mqu6f:)urCorVlp1!:0CZ +"Rn#D2YHtIrrDcmrrDcmrrDfnJ,~> +r;QigLu7t,"T2a0!k7k&#iGpf3WK+F!)WLk!qD*(p\tBo@fQS>pAb-mqu6f:)urCorVlp1!:0CZ +"Rn#D2YHtIrrDcmrrDcmrrDfnJ,~> +r;QigLu7t,"T2a0!k7k&#iGpf3WK+F!)WLk!qD*(p\tBo@fQS>pAb-mqu6f:)urCorVlp1!:0CZ +"Rn#D2YHtIrrDcmrrDcmrrDfnJ,~> +r;QhJ!.+G?"Qr2R!0?aO#BBeEWojE`WVQPqIfOfirrhLR!!&)Qs8N)trrr"8!s!B>r;QgY!4hn) +"QM*71[k2?rrDcmrrDcmrrDfnJ,~> +r;QhJ!.+G?"Qr2R!0?aO#BBeEWojE`WVQPqIfOfirrhLR!!&)Qs8N)trrr"8!s!B>r;QgY!4hn) +"QM*71[k2?rrDcmrrDcmrrDfnJ,~> +r;QhJ!.+G?"Qr2R!0?aO#BBeEWojE`WVQPqIfOfirrhLR!!&)Qs8N)trrr"8!s!B>r;QgY!4hn) +"QM*71[k2?rrDcmrrDcmrrDfnJ,~> +r;Qh0!*oC#"o"&i!!S_[rs.p%!$[=$$ha>q!bD@:qYp`nNtD?qQh:=X!<<'&qjJB&(9RH5!f?tM +qYp`sSe1rqo(i=c!;?Hm!;?Hm!;HMD~> +r;Qh0!*oC#"o"&i!!S_[rs.p%!$[=$$ha>q!bD@:qYp`nNtD?qQh:=X!<<'&qjJB&(9RH5!f?tM +qYp`sSe1rqo(i=c!;?Hm!;?Hm!;HMD~> +r;Qh0!*oC#"o"&i!!S_[rs.p%!$[=$$ha>q!bD@:qYp`nNtD?qQh:=X!<<'&qjJB&(9RH5!f?tM +qYp`sSe1rqo(i=c!;?Hm!;?Hm!;HMD~> +r;R8>!WYHgkkje]E"i9P1X5Fh"c!'X#67s&rsl[C!'d[NqsM.:'EA+hc1Cu8!!_>U,QIgFlhUPj +nJqU'^$bgea+P`="G$IHrr_uq!;lQk!r)`qpAb-mp]#a~> +r;R8>!WYHgkkje]E"i9P1X5Fh"c!'X#67s&rsl[C!'d[NqsM.:'EA+hc1Cu8!!_>U,QIgFlhUPj +nJqU'^$bgea+P`="G$IHrr_uq!;lQk!r)`qpAb-mp]#a~> +r;R8>!WYHgkkje]E"i9P1X5Fh"c!'X#67s&rsl[C!'d[NqsM.:'EA+hc1Cu8!!_>U,QIgFlhUPj +nJqU'^$bgea+P`="G$IHrr_uq!;lQk!r)`qpAb-mp]#a~> +qu6\u');M/1o^KCrrMg4rVur)p\t8q');M/1o^KFrrs&8#64`Q[.aM#bng-U!Wc!Dp\t?1!!'e/ +rrRlS#5A-"eGoTWq#>j~> +qu6\u');M/1o^KCrrMg4rVur)p\t8q');M/1o^KFrrs&8#64`Q[.aM#bng-U!Wc!Dp\t?1!!'e/ +rrRlS#5A-"eGoTWq#>j~> +qu6\u');M/1o^KCrrMg4rVur)p\t8q');M/1o^KFrrs&8#64`Q[.aM#bng-U!Wc!Dp\t?1!!'e/ +rrRlS#5A-"eGoTWq#>j~> +qYpijNBe-Z'LIE"li.*X!!!W-pAYEfNBe-Z'LIE"n,EQL&/%^>rUg*qm!^`$!u!kLg@bIJkTU\s +q#:E!%70ag"6C4Ch>%##~> +qYpijNBe-Z'LIE"li.*X!!!W-pAYEfNBe-Z'LIE"n,EQL&/%^>rUg*qm!^`$!u!kLg@bIJkTU\s +q#:E!%70ag"6C4Ch>%##~> +qYpijNBe-Z'LIE"li.*X!!!W-pAYEfNBe-Z'LIE"n,EQL&/%^>rUg*qm!^`$!u!kLg@bIJkTU\s +q#:E!%70ag"6C4Ch>%##~> +g]%BR*WT`/s*t~> +g]%BR*WT`/s*t~> +g]%BR*WT`/s*t~> +g]%BE"ou>ps*t~> +g]%BE"ou>ps*t~> +g]%BE"ou>ps*t~> +g]%AE!#YZms*t~> +g]%AE!#YZms*t~> +g]%AE!#YZms*t~> +k5POY7sb12rrP(YDMnIE~> +k5POY7sb12rrP(YDMnIE~> +k5POY7sb12rrP(YDMnIE~> +k5PMq!!Mcfrr^4?!6^9"J,~> +k5PMq!!Mcfrr^4?!6^9"J,~> +k5PMq!!Mcfrr^4?!6^9"J,~> +k5PK`!$_:>!^?Z?M>r)~> +k5PK`!$_:>!^?Z?M>r)~> +k5PK`!$_:>!^?Z?M>r)~> +k5PPA"TYe)rr\5\!3:tVJ,~> +k5PPA"TYe)rr\5\!3:tVJ,~> +k5PPA"TYe)rr\5\!3:tVJ,~> +jo5[+!"=qKp +jo5[+!"=qKp +jo5[+!"=qKp +jo5AV3;NUU2"6>$J,~> +jo5AV3;NUU2"6>$J,~> +jo5AV3;NUU2"6>$J,~> +jSoMWGpW_$)+U"iL];l~> +jSoMWGpW_$)+U"iL];l~> +jSoMWGpW_$)+U"iL];l~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +JcF^/J,~> +%%EndData +showpage +%%Trailer +end +%%EOF diff --git a/com.ibm.wala.cast/data/the-cast-system.jpeg b/com.ibm.wala.cast/data/the-cast-system.jpeg new file mode 100644 index 000000000..4d2f2bff0 Binary files /dev/null and b/com.ibm.wala.cast/data/the-cast-system.jpeg differ diff --git a/com.ibm.wala.cast/data/the-cast-system.xcf b/com.ibm.wala.cast/data/the-cast-system.xcf new file mode 100644 index 000000000..d8028e580 Binary files /dev/null and b/com.ibm.wala.cast/data/the-cast-system.xcf differ diff --git a/com.ibm.wala.cast/source/c/.cvsignore b/com.ibm.wala.cast/source/c/.cvsignore new file mode 100644 index 000000000..fca313ff1 --- /dev/null +++ b/com.ibm.wala.cast/source/c/.cvsignore @@ -0,0 +1,3 @@ +Makefile.configuration +CAstWrapper.lib +CAstWrapper.exp diff --git a/com.ibm.wala.cast/source/c/Makefile b/com.ibm.wala.cast/source/c/Makefile new file mode 100644 index 000000000..fe7f614de --- /dev/null +++ b/com.ibm.wala.cast/source/c/Makefile @@ -0,0 +1,90 @@ +# 2006/08/03 Naoshi Tabuchi: tabee@jp.ibm.com +# Adjusted to building with MSVC++. +# NOTE: PLATFORM=cygwin now implies using MSVC, +# thus pathnames must be given in "Windows style," +# e.g. "c:/path/to/something", path separators can be +# slashes, though. + +include Makefile.configuration + +# +# in theory, these definitions should not need to be changed +# + +# 2006/08/03 Naoshi Tabuchi: tabee@jp.ibm.com +# Recent versions of Cygwin's uname return "Cygwin", instead of "cygwin." +PLATFORM=$(shell uname -o | sed -e 's/C/c/') + +C_GENERATED=$(DOMO_AST_BIN)libcast/ + +ifeq ($(PLATFORM),cygwin) + JAVAH_GENERATED=$(shell cygpath -w $(DOMO_AST_BIN)/libcast) + CC=cl +else + JAVAH_GENERATED=$(C_GENERATED) + CC=g++ +endif + +vpath %.cpp jni + +ifeq ($(PLATFORM),cygwin) + PLATFORM_JNI_DIR = win32 +else + PLATFORM_JNI_DIR = $(shell cd $(JAVA_SDK); find include -mindepth 1 -maxdepth 1 -type d) +endif +JAVA_INCLUDES = -I$(JAVA_SDK)include -I$(JAVA_SDK)$(PLATFORM_JNI_DIR) -I$(JAVA_SDK)include/$(PLATFORM_JNI_DIR) + +CAPA_INCLUDE_DIR = include/ +CAPA_INCLUDES = -I$(CAPA_INCLUDE_DIR) -I$(C_GENERATED) + +CAPA_JNI_HEADER = $(C_GENERATED)com_ibm_wala_cast_ir_translator_NativeBridge.h + +INCLUDES = $(CAPA_INCLUDES) $(JAVA_INCLUDES) + +CAPA_SOURCES = $(notdir $(wildcard jni/*.cpp)) +CAPA_OBJECTS = $(patsubst %.cpp,$(C_GENERATED)%.o,$(CAPA_SOURCES)) + +ifeq ($(PLATFORM),cygwin) + ALL_FLAGS = /WL /MD /EHsc /D ZTS /D YY_NO_UNISTD_H /D _USE_32BIT_TIME_T /D __WIN32__ /D WIN32 /D BUILD_CAST_DLL $(INCLUDES) + DLLEXT = dll +else + ALL_FLAGS = -pthread -gstabs+ $(TRACE) $(INCLUDES) -fpic + DLLEXT = so +endif + +ifeq ($(PLATFORM),cygwin) + CC_OUTFLAG = /Fo + LD_OUTFLAG = /link /IMPLIB:$(DOMO_AST_BIN)cast.lib /OUT: + CC_LDFLAGS = /LDd /MD + LIBPREFIX = + POSTPROCESS = && cd $(DOMO_AST_BIN) && mt /manifest $(LIBPREFIX)cast.$(DLLEXT).manifest /outputresource:"$(LIBPREFIX)cast.$(DLLEXT);\#2" +else + CC_OUTFLAG = -o + CC_LDFLAGS = -pthread -shared + LD_OUTFLAG = -o + LIBPREFIX = lib + POSTPROCESS = +endif + +# +# rules +# + +default: $(DOMO_AST_BIN)$(LIBPREFIX)cast.$(DLLEXT) + +bindir: + mkdir -p $(C_GENERATED) + +$(CAPA_JNI_HEADER): $(DOMO_AST_BIN)com/ibm/wala/cast/ir/translator/NativeBridge.class bindir + $(JAVA_SDK)bin/javah -classpath "$(DOMO_AST_BIN)$(JAVAH_CLASS_PATH)" -d "$(JAVAH_GENERATED)" com.ibm.wala.cast.ir.translator.NativeBridge + +$(CAPA_OBJECTS): $(C_GENERATED)%.o: %.cpp $(CAPA_JNI_HEADER) bindir + echo $(CAPA_OBJECTS) + $(CC) $(ALL_FLAGS) $(CC_OUTFLAG)$@ -c $< + +$(DOMO_AST_BIN)$(LIBPREFIX)cast.$(DLLEXT): $(CAPA_OBJECTS) + $(CC) $(CC_LDFLAGS) $^ $(LD_OUTFLAG)$@ $(POSTPROCESS) + +clean: + rm -rf $(DOMO_AST_BIN)$(LIBPREFIX)cast.$(DLLEXT) $(C_GENERATED) hs_err_pid* + diff --git a/com.ibm.wala.cast/source/c/Makefile.configuration.sample b/com.ibm.wala.cast/source/c/Makefile.configuration.sample new file mode 100644 index 000000000..1f6476d22 --- /dev/null +++ b/com.ibm.wala.cast/source/c/Makefile.configuration.sample @@ -0,0 +1,15 @@ +# +# global configuration. adjust for your system. +# + +# The root of the java SDK to use (must end in /) +JAVA_SDK = /opt/sun-jdk-1.5.0.08/ + +# Path .class files of the com.ibm.domo.ast Java code (must end in /) +DOMO_AST_BIN = /my/workspace/path/com.ibm.domo.ast/bin/ + +# Extra stuff needed in the classpath of javah (must start with path separator) +JAVAH_CLASS_PATH = :/my/workspace/path/com.ibm.capa.ast/bin/ + +# enable debugging flags +TRACE = diff --git a/com.ibm.wala.cast/source/c/include/CAstWrapper.h b/com.ibm.wala.cast/source/c/include/CAstWrapper.h new file mode 100755 index 000000000..c64b12023 --- /dev/null +++ b/com.ibm.wala.cast/source/c/include/CAstWrapper.h @@ -0,0 +1,179 @@ +#ifndef _CAST_WRAPPER_H +#define _CAST_WRAPPER_H + +#include +#include +#include "Exceptions.h" + +using namespace std; + + +#ifdef TRACE_CAST_WRAPPER +#define LOG(x) log(x); + +#else +#define LOG(x) + +#endif + +#ifdef _MSC_VER +#ifdef BUILD_CAST_DLL +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT __declspec(dllimport) +#endif +class DLLEXPORT CAstWrapper { +#else + +/** + * This class is a simple wrapper that provides a C++ object veneer + * over JNI calls to a CAst object in Javaland. This wrapper is used + * by the grammar rules of the bison grammar that defines PHP to build + * a CAst tree in Javaland. + */ +class CAstWrapper { +#endif + + +protected: + jobject Ast; + JNIEnv *env; + Exceptions &java_ex; + jclass HashSet; + jmethodID hashSetInit; + jmethodID hashSetAdd; + jclass LinkedList; + jmethodID linkedListInit; + jmethodID linkedListAdd; + +private: + jclass CAstNode; + jclass CAstInterface; + jclass CAstPrinter; + jmethodID castPrint; + jmethodID makeNode0; + jmethodID makeNode1; + jmethodID makeNode2; + jmethodID makeNode3; + jmethodID makeNode4; + jmethodID makeNode5; + jmethodID makeNode6; + jmethodID makeNodeNary; + jmethodID makeNode1Nary; + jmethodID makeBool; + jmethodID makeChar; + jmethodID makeShort; + jmethodID makeInt; + jmethodID makeLong; + jmethodID makeDouble; + jmethodID makeFloat; + jmethodID makeObject; + jmethodID getChild; + jmethodID _getChildCount; + jmethodID getValue; + jmethodID _getKind; + jmethodID toString; + jmethodID getClass; + jmethodID intValue; + jmethodID _getEntityName; + + jobject callReference; + +public: + +#define _INCLUDE_CONSTANTS +#include "cast_constants.h" + +#define _INCLUDE_OPERATORS +#include "cast_operators.h" + +#define _INCLUDE_QUALIFIERS +#include "cast_qualifiers.h" + +#define _INCLUDE_CFM +#include "cast_control_flow_map.h" + +public: + + CAstWrapper(JNIEnv *env, Exceptions &ex, jobject Ast); + + void assertIsCAstNode(jobject, int); + + jobject makeNode(int); + + jobject makeNode(int, jobject); + + jobject makeNode(int, jobject, jobject); + + jobject makeNode(int, jobject, jobject, jobject); + + jobject makeNode(int, jobject, jobject, jobject, jobject); + + jobject makeNode(int, jobject, jobject, jobject, jobject, jobject); + + jobject makeNode(int, jobject, jobject, jobject, jobject, jobject, jobject); + + jobject makeNode(int, jobjectArray); + + jobject makeNode(int, jobject, jobjectArray); + + jobject makeConstant(bool); + + jobject makeConstant(char); + + jobject makeConstant(short); + + jobject makeConstant(int); + + jobject makeConstant(long); + + jobject makeConstant(double); + + jobject makeConstant(float); + + jobject makeConstant(jobject); + + jobject makeConstant(const char *); + + jobject makeConstant(const char *, int); + + jobject getNthChild(jobject, int); + + int getChildCount(jobject); + + int getKind(jobject); + + bool isConstantValue(jobject); + + bool isConstantOfType(jobject, const char *); + + bool isConstantOfType(jobject, jclass); + + bool isSwitchDefaultConstantValue(jobject); + + const char *getStringConstantValue(jobject); + + jobject getConstantValue(jobject); + + int getIntConstantValue(jobject); + + jobjectArray makeArray(list *); + + jobjectArray makeArray(jclass, list *); + + jobjectArray makeArray(int, jobject[]); + + jobjectArray makeArray(jclass, int, jobject[]); + + jobject makeSet(list *); + + jobject makeList(list *); + + jobject getCallReference(); + + const char *getEntityName(jobject); + + void log(jobject); +}; +#endif + diff --git a/com.ibm.wala.cast/source/c/include/Exceptions.h b/com.ibm.wala.cast/source/c/include/Exceptions.h new file mode 100755 index 000000000..6e683dd6d --- /dev/null +++ b/com.ibm.wala.cast/source/c/include/Exceptions.h @@ -0,0 +1,74 @@ +#ifndef EXCEPTIONS_H +#define EXCEPTIONS_H + +/** + * The combination of the macroes and the Exceptions class declared + * in this file is used to provide a (shaky) veneer of exception handling + * to JNI code. + * + * The idea is that a C function called from JNI will be enclosed with + * TRY/CATCH macroes, and the CPP_EXP_NAME variable defined will be passed + * to callees who might want to throw an exception. The callees will use + * the THROW macro to throw exceptions. When a THROW is executed, control + * is transferred to the CATCH, and a RuntimeException is thrown to the + * calling Java code when the C code returns. + * + * WARNING: this is C code, so you should know better than to expect any + * kind of robust, high-level exception-handling semantics. The way to use + * this code is to put a TRY/CATCH combination in the JNI entry point, to do + * only trivial things after the CATCH, and to use only THROW anywhere else. + * + * The implementation does the obvious dance with setjmp and longjmp, which + * is one reason it is rather shaky. For instance, TRY has to be a macro, + * because otherwise the jump buffer would be invalidated when the TRY function + * returned. + */ + +#include + +extern "C" { +#include +} + +#define TRY(CPP_EXP_NAME, JAVA_ENV_VAR) \ +{ jmp_buf jump_buffer; \ + if (setjmp(jump_buffer) == 0) { \ + Exceptions CPP_EXP_NAME(JAVA_ENV_VAR, jump_buffer); + +#define CATCH() \ + } \ +} \ + +#define THROW(CPP_EXP_NAME, MESSAGE) \ +(CPP_EXP_NAME).throwException(__FILE__, __LINE__, MESSAGE) + +#define THROW_ANY_EXCEPTION(CPP_EXP_NAME) \ +(CPP_EXP_NAME).throwAnyException(__FILE__, __LINE__) + +#ifdef _MSC_VER +#ifdef BUILD_CAST_DLL +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT __declspec(dllimport) +#endif +class DLLEXPORT Exceptions { + +#else +class Exceptions { +#endif + +private: + JNIEnv *_java_env; + jmp_buf& _c_env; + jclass _jre; + jmethodID _ctr; + jmethodID _wrapper_ctr; + +public: + Exceptions(JNIEnv *java_env, jmp_buf& c_env); + + void throwException(char *file_name, int line_number); + void throwAnyException(char *file_name, int line_number); + void throwException(char *file_name, int line_number, char *c_message); +}; +#endif diff --git a/com.ibm.wala.cast/source/c/include/cast_constants.h b/com.ibm.wala.cast/source/c/include/cast_constants.h new file mode 100755 index 000000000..02ab5c35e --- /dev/null +++ b/com.ibm.wala.cast/source/c/include/cast_constants.h @@ -0,0 +1,90 @@ +#if defined( _INCLUDE_CONSTANTS ) +#define _CAstNodeType( __id ) static jint __id; + +#elif defined( _CPP_CONSTANTS ) +#define _CAstNodeType( __id ) jint CAstWrapper::__id; + +#elif defined( _CODE_CONSTANTS ) +#define _CAstNodeType( __id ) \ +{ \ + jfieldID f##__id = env->GetStaticFieldID(CAstNode, #__id, "I"); \ + CAstWrapper::__id = env->GetStaticIntField(CAstNode, f##__id); \ + THROW_ANY_EXCEPTION(exp); \ +} + +#else +#error "bad use of CAst constants + +#endif + +#if __WIN32__ +#undef VOID +#undef CONST +#undef ERROR +#endif + +_CAstNodeType(ASSERT) +_CAstNodeType(SWITCH) +_CAstNodeType(LOOP) +_CAstNodeType(BLOCK_STMT) +_CAstNodeType(TRY) +_CAstNodeType(EXPR_STMT) +_CAstNodeType(DECL_STMT) +_CAstNodeType(RETURN) +_CAstNodeType(GOTO) +_CAstNodeType(BREAK) +_CAstNodeType(CONTINUE) +_CAstNodeType(IF_STMT) +_CAstNodeType(THROW) +_CAstNodeType(FUNCTION_STMT) +_CAstNodeType(ASSIGN) +_CAstNodeType(ASSIGN_PRE_OP) +_CAstNodeType(ASSIGN_POST_OP) +_CAstNodeType(LABEL_STMT) +_CAstNodeType(IFGOTO) +_CAstNodeType(EMPTY) +_CAstNodeType(RETURN_WITHOUT_BRANCH) +_CAstNodeType(CATCH) +_CAstNodeType(UNWIND) +_CAstNodeType(MONITOR_ENTER) +_CAstNodeType(MONITOR_EXIT) +_CAstNodeType(FUNCTION_EXPR) +_CAstNodeType(EXPR_LIST) +_CAstNodeType(CALL) +_CAstNodeType(GET_CAUGHT_EXCEPTION) +_CAstNodeType(BLOCK_EXPR) +_CAstNodeType(BINARY_EXPR) +_CAstNodeType(UNARY_EXPR) +_CAstNodeType(IF_EXPR) +_CAstNodeType(ANDOR_EXPR) +_CAstNodeType(NEW) +_CAstNodeType(OBJECT_LITERAL) +_CAstNodeType(VAR) +_CAstNodeType(OBJECT_REF) +_CAstNodeType(CHOICE_EXPR) +_CAstNodeType(CHOICE_CASE) +_CAstNodeType(SUPER) +_CAstNodeType(THIS) +_CAstNodeType(ARRAY_LITERAL) +_CAstNodeType(CAST) +_CAstNodeType(INSTANCEOF) +_CAstNodeType(ARRAY_REF) +_CAstNodeType(ARRAY_LENGTH) +_CAstNodeType(TYPE_OF) +_CAstNodeType(LOCAL_SCOPE) +_CAstNodeType(CONSTANT) +_CAstNodeType(OPERATOR) +_CAstNodeType(PRIMITIVE) +_CAstNodeType(ERROR) +_CAstNodeType(VOID) +_CAstNodeType(ECHO) +_CAstNodeType(EACH_ELEMENT_GET) +_CAstNodeType(EACH_ELEMENT_HAS_NEXT) +_CAstNodeType(LIST_EXPR); +_CAstNodeType(EMPTY_LIST_EXPR); + +#undef _CODE_CONSTANTS +#undef _CPP_CONSTANTS +#undef _INCLUDE_CONSTANTS +#undef _CAstNodeType + diff --git a/com.ibm.wala.cast/source/c/include/cast_control_flow_map.h b/com.ibm.wala.cast/source/c/include/cast_control_flow_map.h new file mode 100644 index 000000000..667e47a1a --- /dev/null +++ b/com.ibm.wala.cast/source/c/include/cast_control_flow_map.h @@ -0,0 +1,29 @@ +#if defined( _INCLUDE_CFM ) +#define _CAstControlFlowMap( __id, __type ) static jobject __id; + +#elif defined( _CPP_CFM ) +#define _CAstControlFlowMap( __id, __type ) jobject CAstWrapper::__id; + +#elif defined( _CODE_CFM ) +#define _CAstControlFlowMap( __id, __type ) \ +{ \ + jfieldID f##__id = env->GetStaticFieldID(CAstControlFlowMap, #__id, __type); \ + THROW_ANY_EXCEPTION(exp); \ + jobject o##__id = env->GetStaticObjectField(CAstControlFlowMap, f##__id); \ + CAstWrapper::__id = env->NewGlobalRef(o##__id); \ + THROW_ANY_EXCEPTION(exp); \ +} + +#else +#error "bad use of CAst control flow map" + +#endif + +_CAstControlFlowMap(SWITCH_DEFAULT, "Ljava/lang/Object;") +_CAstControlFlowMap(EXCEPTION_TO_EXIT, "Lcom/ibm/wala/cast/tree/CAstNode;") + +#undef _CODE_CFM +#undef _CPP_CFM +#undef _INCLUDE_CFM +#undef _CAstControlFlowMap + diff --git a/com.ibm.wala.cast/source/c/include/cast_operators.h b/com.ibm.wala.cast/source/c/include/cast_operators.h new file mode 100755 index 000000000..211134c63 --- /dev/null +++ b/com.ibm.wala.cast/source/c/include/cast_operators.h @@ -0,0 +1,50 @@ +#if defined( _INCLUDE_OPERATORS ) +#define _CAstOperator( __id ) static jobject __id; + +#elif defined( _CPP_OPERATORS ) +#define _CAstOperator( __id ) jobject CAstWrapper::__id; + +#elif defined( _CODE_OPERATORS ) +#define _CAstOperator( __id ) \ +{ \ + jfieldID f##__id = env->GetStaticFieldID(CAstOperator, #__id, "Lcom/ibm/wala/cast/tree/impl/CAstOperator;"); \ + THROW_ANY_EXCEPTION(exp); \ + jobject o##__id = env->GetStaticObjectField(CAstOperator, f##__id); \ + CAstWrapper::__id = env->NewGlobalRef(o##__id); \ + THROW_ANY_EXCEPTION(exp); \ +} + +#else +#error "bad use of CAst operators" + +#endif + +_CAstOperator(OP_ADD) +_CAstOperator(OP_CONCAT) +_CAstOperator(OP_DIV) +_CAstOperator(OP_LSH) +_CAstOperator(OP_MOD) +_CAstOperator(OP_MUL) +_CAstOperator(OP_RSH) +_CAstOperator(OP_URSH) +_CAstOperator(OP_SUB) +_CAstOperator(OP_EQ) +_CAstOperator(OP_GE) +_CAstOperator(OP_GT) +_CAstOperator(OP_LE) +_CAstOperator(OP_LT) +_CAstOperator(OP_NE) +_CAstOperator(OP_NOT) +_CAstOperator(OP_BITNOT) +_CAstOperator(OP_BIT_AND) +_CAstOperator(OP_REL_AND) +_CAstOperator(OP_BIT_OR) +_CAstOperator(OP_REL_OR) +_CAstOperator(OP_BIT_XOR) +_CAstOperator(OP_REL_XOR) + +#undef _CODE_OPERATORS +#undef _CPP_OPERATORS +#undef _INCLUDE_OPERATORS +#undef _CAstOperator + diff --git a/com.ibm.wala.cast/source/c/include/cast_qualifiers.h b/com.ibm.wala.cast/source/c/include/cast_qualifiers.h new file mode 100644 index 000000000..cbf1d6353 --- /dev/null +++ b/com.ibm.wala.cast/source/c/include/cast_qualifiers.h @@ -0,0 +1,39 @@ +#if defined( _INCLUDE_QUALIFIERS ) +#define _CAstQualifier( __id ) static jobject __id; + +#elif defined( _CPP_QUALIFIERS ) +#define _CAstQualifier( __id ) jobject CAstWrapper::__id; + +#elif defined( _CODE_QUALIFIERS ) +#define _CAstQualifier( __id ) \ +{ \ + jfieldID f##__id = env->GetStaticFieldID(CAstQualifier, #__id, "Lcom/ibm/wala/cast/CAstQualifier;"); \ + jobject o##__id = env->GetStaticObjectField(CAstNode, f##__id); \ + CAstWrapper::__id = env->NewGlobalRef(o##__id); \ + THROW_ANY_EXCEPTION(exp); \ +} + +#else +#error "bad use of CAst qualifiers" + +#endif + +_CAstQualifier(STRICTFP) +_CAstQualifier(VOLATILE) +_CAstQualifier(ABSTRACT) +_CAstQualifier(INTERFACE) +_CAstQualifier(NATIVE) +_CAstQualifier(TRANSIENT) +_CAstQualifier(SYNCHRONIZED) +_CAstQualifier(FINAL) +_CAstQualifier(STATIC) +_CAstQualifier(PRIVATE) +_CAstQualifier(PROTECTED) +_CAstQualifier(PUBLIC) +_CAstQualifier(CONST) + +#undef _CODE_QUALIFIERS +#undef _CPP_QUALIFIERS +#undef _INCLUDE_QUALIFIERS +#undef _CAstQualifier + diff --git a/com.ibm.wala.cast/source/c/jni/CAstWrapper.cpp b/com.ibm.wala.cast/source/c/jni/CAstWrapper.cpp new file mode 100755 index 000000000..47065d87b --- /dev/null +++ b/com.ibm.wala.cast/source/c/jni/CAstWrapper.cpp @@ -0,0 +1,460 @@ +#include + +#include + +#include +#include +#include + +#if defined(__MINGW32__) || defined(_MSC_VER) +#define strndup(s,n) strdup(s) +#endif + +#define __SIG( __nm ) "L" __nm ";" + +#define __CTN "com/ibm/wala/cast/CAst" +#define __CTS __SIG( __CTN ) + +#define __CNN "com/ibm/wala/cast/CAstNode" +#define __CNS __SIG( __CNN ) + +#define __CRN "com/ibm/wala/cast/CAstMemberReference" +#define __CRS __SIG( __CRN ) + +#define __OBJN "java/lang/Object" +#define __OBJS __SIG( __OBJN ) + +static const char *__MN = "makeNode"; +static const char *__MC = "makeConstant"; + +static const char *zeroSig = "(I)" __CNS; +static const char *oneSig = "(I" __CNS ")" __CNS; +static const char *twoSig = "(I" __CNS __CNS ")" __CNS; +static const char *threeSig = "(I" __CNS __CNS __CNS ")" __CNS; +static const char *fourSig = "(I" __CNS __CNS __CNS __CNS ")" __CNS; +static const char *fiveSig = "(I" __CNS __CNS __CNS __CNS __CNS ")" __CNS; +static const char *sixSig = "(I" __CNS __CNS __CNS __CNS __CNS __CNS ")" __CNS; +static const char *narySig = "(I[" __CNS ")" __CNS; +static const char *oneNarySig = "(I" __CNS "[" __CNS ")" __CNS; + +static const char *boolSig = "(Z)" __CNS; +static const char *charSig = "(C)" __CNS; +static const char *shortSig = "(S)" __CNS; +static const char *intSig = "(I)" __CNS; +static const char *longSig = "(J)" __CNS; +static const char *doubleSig = "(D)" __CNS; +static const char *floatSig = "(F)" __CNS; +static const char *objectSig = "(" __OBJS ")" __CNS; + +CAstWrapper::CAstWrapper(JNIEnv *env, Exceptions &ex, jobject Ast) + : java_ex(ex), env(env), Ast(Ast) +{ + this->CAstNode = env->FindClass( __CNN ); + this->CAstInterface = env->FindClass( __CTN ); + this->HashSet = env->FindClass("java/util/HashSet"); + this->LinkedList = env->FindClass("java/util/LinkedList"); + + this->makeNode0 = env->GetMethodID(CAstInterface, __MN, zeroSig); + this->makeNode1 = env->GetMethodID(CAstInterface, __MN, oneSig); + this->makeNode2 = env->GetMethodID(CAstInterface, __MN, twoSig); + this->makeNode3 = env->GetMethodID(CAstInterface, __MN, threeSig); + this->makeNode4 = env->GetMethodID(CAstInterface, __MN, fourSig); + this->makeNode5 = env->GetMethodID(CAstInterface, __MN, fiveSig); + this->makeNode6 = env->GetMethodID(CAstInterface, __MN, sixSig); + this->makeNodeNary = env->GetMethodID(CAstInterface, __MN, narySig); + this->makeNode1Nary = env->GetMethodID(CAstInterface, __MN, oneNarySig); + + this->makeBool = env->GetMethodID(CAstInterface, __MC, boolSig); + this->makeChar = env->GetMethodID(CAstInterface, __MC, charSig); + this->makeShort = env->GetMethodID(CAstInterface, __MC, shortSig); + this->makeInt = env->GetMethodID(CAstInterface, __MC, intSig); + this->makeLong = env->GetMethodID(CAstInterface, __MC, longSig); + this->makeDouble = env->GetMethodID(CAstInterface, __MC, doubleSig); + this->makeFloat = env->GetMethodID(CAstInterface, __MC, floatSig); + this->makeObject = env->GetMethodID(CAstInterface, __MC, objectSig); + + this->getChild = env->GetMethodID(CAstNode, "getChild", "(I)" __CNS); + this->_getChildCount = env->GetMethodID(CAstNode, "getChildCount", "()I"); + this->getValue = env->GetMethodID(CAstNode, "getValue", "()" __OBJS); + this->_getKind = env->GetMethodID(CAstNode, "getKind", "()I"); + + jclass CAstMemberReference = env->FindClass( __CRN ); + THROW_ANY_EXCEPTION(java_ex); + jfieldID ff = env->GetStaticFieldID(CAstMemberReference, "FUNCTION", __CRS); + THROW_ANY_EXCEPTION(java_ex); + this->callReference = env->GetStaticObjectField(CAstMemberReference, ff); + THROW_ANY_EXCEPTION(java_ex); + + this->CAstPrinter = env->FindClass("com/ibm/wala/cast/tree/impl/CAstPrinter"); + this->castPrint = env->GetStaticMethodID(CAstPrinter, "print", "(Lcom/ibm/wala/cast/tree/CAstNode;)Ljava/lang/String;"); + + this->hashSetInit = env->GetMethodID(HashSet, "", "()V"); + this->hashSetAdd = env->GetMethodID(HashSet, "add", "(Ljava/lang/Object;)Z"); + + this->linkedListInit = env->GetMethodID(LinkedList, "", "()V"); + this->linkedListAdd = env->GetMethodID(LinkedList, "add", "(Ljava/lang/Object;)Z"); + + jclass obj = env->FindClass( __OBJN ); + this->toString = env->GetMethodID(obj, "toString", "()Ljava/lang/String;"); + this->getClass = env->GetMethodID(obj, "getClass", "()Ljava/lang/Class;"); + + jclass intcls = env->FindClass("java/lang/Integer"); + this->intValue = env->GetMethodID(intcls, "intValue", "()I"); + + jclass castEntity = env->FindClass("com/ibm/wala/cast/tree/CAstEntity"); + this->_getEntityName = env->GetMethodID(castEntity, "getName", "()Ljava/lang/String;"); + + THROW_ANY_EXCEPTION(java_ex); +} + +#define _CPP_CONSTANTS +#include "cast_constants.h" + +#define _CPP_OPERATORS +#include "cast_operators.h" + +#define _CPP_QUALIFIERS +#include "cast_qualifiers.h" + +#define _CPP_CFM +#include "cast_control_flow_map.h" + +void CAstWrapper::log(jobject castTree) { + jstring jstr = (jstring)env->CallStaticObjectMethod(CAstPrinter, castPrint, castTree); + const char *cstr = env->GetStringUTFChars(jstr, NULL); + fprintf(stderr, "%s\n", cstr); + env->ReleaseStringUTFChars(jstr, cstr); + THROW_ANY_EXCEPTION(java_ex); +} + +void CAstWrapper::assertIsCAstNode(jobject obj, int n) { + if (! env->IsInstanceOf(obj, CAstNode)) { + jstring jstr = (jstring)env->CallObjectMethod(obj, toString); + const char *cstr = env->GetStringUTFChars(jstr, NULL); + + jobject cls = env->CallObjectMethod(obj, getClass); + jstring jclsstr = (jstring)env->CallObjectMethod(cls, toString); + const char *cclsstr = env->GetStringUTFChars(jclsstr, NULL); + +#if defined(_MSC_VER) + char* buf = (char*)_alloca(strlen(cstr) + strlen(cclsstr) + 100); +#else + char buf[ strlen(cstr) + strlen(cclsstr) + 100 ]; +#endif + sprintf(buf, "argument %d (%s of type %s) is not a CAstNode\n", n, cstr, cclsstr); + + env->ReleaseStringUTFChars(jstr, cstr); + env->ReleaseStringUTFChars(jclsstr, cclsstr); + THROW(java_ex, buf); + } +} + +jobject CAstWrapper::makeNode(int kind) { + jobject r = env->CallObjectMethod(Ast, makeNode0, (jint) kind); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeNode(int kind, jobject c1) { + assertIsCAstNode(c1, 1); + jobject r = env->CallObjectMethod(Ast, makeNode1, (jint) kind, c1); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeNode(int kind, jobject c1, jobject c2) { + assertIsCAstNode(c1, 1); + assertIsCAstNode(c2, 2); + jobject r = env->CallObjectMethod(Ast, makeNode2, (jint) kind, c1, c2); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeNode(int kind, jobject c1, jobject c2, jobject c3) { + assertIsCAstNode(c1, 1); + assertIsCAstNode(c2, 2); + assertIsCAstNode(c3, 3); + jobject r = env->CallObjectMethod(Ast, makeNode3, (jint) kind, c1, c2, c3); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeNode(int kind, jobject c1, jobject c2, jobject c3, jobject c4) { + assertIsCAstNode(c1, 1); + assertIsCAstNode(c2, 2); + assertIsCAstNode(c3, 3); + assertIsCAstNode(c4, 4); + jobject r = env->CallObjectMethod(Ast, makeNode4, (jint) kind, c1, c2, c3, c4); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeNode(int kind, jobject c1, jobject c2, jobject c3, jobject c4, jobject c5) { + assertIsCAstNode(c1, 1); + assertIsCAstNode(c2, 2); + assertIsCAstNode(c3, 3); + assertIsCAstNode(c4, 4); + assertIsCAstNode(c5, 5); + jobject r = env->CallObjectMethod(Ast, makeNode5, (jint) kind, c1, c2, c3, c4, c5); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeNode(int kind, jobject c1, jobject c2, jobject c3, jobject c4, jobject c5, jobject c6) { + assertIsCAstNode(c1, 1); + assertIsCAstNode(c2, 2); + assertIsCAstNode(c3, 3); + assertIsCAstNode(c4, 4); + assertIsCAstNode(c5, 5); + assertIsCAstNode(c6, 6); + jobject r = env->CallObjectMethod(Ast, makeNode6, (jint) kind, c1, c2, c3, c4, c5, c6); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeNode(int kind, jobjectArray cs) { + jobject r = env->CallObjectMethod(Ast, makeNodeNary, (jint) kind, cs); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeNode(int kind, jobject n, jobjectArray cs) { + jobject r = env->CallObjectMethod(Ast, makeNode1Nary, (jint) kind, n, cs); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeConstant(bool val) { + jobject r = env->CallObjectMethod(Ast, makeBool, (jboolean)val); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeConstant(char val) { + jobject r = env->CallObjectMethod(Ast, makeChar, (jchar)val); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeConstant(short val) { + jobject r = env->CallObjectMethod(Ast, makeShort, (jshort)val); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeConstant(int val) { + jobject r = env->CallObjectMethod(Ast, makeInt, (jint)val); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeConstant(long val) { + jobject r = env->CallObjectMethod(Ast, makeLong, (jlong)val); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeConstant(double val) { + jobject r = env->CallObjectMethod(Ast, makeDouble, (jdouble)val); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeConstant(float val) { + jobject r = env->CallObjectMethod(Ast, makeFloat, (jfloat)val); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeConstant(jobject val) { + jobject r = env->CallObjectMethod(Ast, makeObject, val); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::makeConstant(const char *strData) { + return makeConstant(strData, strlen(strData)); +} + +jobject CAstWrapper::makeConstant(const char *strData, int strLen) { + char *safeData = strndup(strData, strLen); + jobject val = env->NewStringUTF( safeData ); + delete safeData; + jobject r = env->CallObjectMethod(Ast, makeObject, val); + THROW_ANY_EXCEPTION(java_ex); + LOG(r); + return r; +} + +jobject CAstWrapper::getNthChild(jobject castNode, int index) { + jobject result = env->CallObjectMethod(castNode, getChild, index); + THROW_ANY_EXCEPTION(java_ex); + return result; +} + +int CAstWrapper::getChildCount(jobject castNode) { + int result = env->CallIntMethod(castNode, _getChildCount); + THROW_ANY_EXCEPTION(java_ex); + return result; +} + +int CAstWrapper::getKind(jobject castNode) { + jint result = env->CallIntMethod(castNode, _getKind); + THROW_ANY_EXCEPTION(java_ex); + return result; +} + +bool CAstWrapper::isConstantValue(jobject castNode) { + jobject jval = env->CallObjectMethod(castNode, getValue); + THROW_ANY_EXCEPTION(java_ex); + return jval != NULL; +} + +bool CAstWrapper::isConstantOfType(jobject castNode, const char *typeName) { + jclass type = env->FindClass( typeName ); + THROW_ANY_EXCEPTION(java_ex); + + return isConstantOfType(castNode, type); +} + +bool CAstWrapper::isConstantOfType(jobject castNode, jclass type) { + // + // one might think this test against null is not needed, since + // IsInstanceoOf ought to return false given null and any type at + // all, which is what happens with the `instanceof'operator in Java. + // This does not seem to be the case however. + // + if (isConstantValue(castNode)) { + jobject jval = env->CallObjectMethod(castNode, getValue); + THROW_ANY_EXCEPTION(java_ex); + jboolean result = env->IsInstanceOf(jval, type); + THROW_ANY_EXCEPTION(java_ex); + + return (bool) result; + } else { + return false; + } +} + +bool CAstWrapper::isSwitchDefaultConstantValue(jobject castNode) { + jobject jval = env->CallObjectMethod(castNode, getValue); + THROW_ANY_EXCEPTION(java_ex); + + return env->IsSameObject(jval, SWITCH_DEFAULT); +} + +const char *CAstWrapper::getStringConstantValue(jobject castNode) { + jstring jstr = (jstring)env->CallObjectMethod(castNode, getValue); + THROW_ANY_EXCEPTION(java_ex); + const char *cstr1 = env->GetStringUTFChars(jstr, NULL); + const char *cstr2 = strdup( cstr1 ); + env->ReleaseStringUTFChars(jstr, cstr1); + THROW_ANY_EXCEPTION(java_ex); + + return cstr2; +} + +int CAstWrapper::getIntConstantValue(jobject castNode) { + jobject jval = env->CallObjectMethod(castNode, getValue); + THROW_ANY_EXCEPTION(java_ex); + int cval = env->CallIntMethod(jval, intValue); + THROW_ANY_EXCEPTION(java_ex); + + return cval; +} + +jobject CAstWrapper::getConstantValue(jobject castNode) { + jobject jval = env->CallObjectMethod(castNode, getValue); + THROW_ANY_EXCEPTION(java_ex); + return jval; +} + +jobjectArray CAstWrapper::makeArray(list *elts) { + return makeArray(CAstNode, elts); +} + +jobjectArray CAstWrapper::makeArray(jclass type, list *elts) { + jobjectArray result = env->NewObjectArray(elts->size(), type, NULL); + int i = 0; + for(list::iterator it=elts->begin(); it!=elts->end(); it++) { + env->SetObjectArrayElement(result, i++, *it); + } + + THROW_ANY_EXCEPTION(java_ex); + return result; +} + +jobjectArray CAstWrapper::makeArray(int count, jobject elts[]) { + return makeArray(CAstNode, count, elts); +} + +jobjectArray CAstWrapper::makeArray(jclass type, int count, jobject elts[]) { + jobjectArray result = env->NewObjectArray(count, type, NULL); + THROW_ANY_EXCEPTION(java_ex); + + for(int i = 0; i < count; i++) { + env->SetObjectArrayElement(result, i, elts[i]); + } + + THROW_ANY_EXCEPTION(java_ex); + return result; +} + +jobject CAstWrapper::makeSet(list *elts) { + jobject set = env->NewObject(HashSet, hashSetInit); + THROW_ANY_EXCEPTION(java_ex); + + if (elts == NULL) return set; + + for(list::iterator it=elts->begin(); it!=elts->end(); it++) { + env->CallVoidMethod(set, hashSetAdd, *it); + } + + return set; +} + +jobject CAstWrapper::makeList(list *elts) { + jobject set = env->NewObject(LinkedList, linkedListInit); + THROW_ANY_EXCEPTION(java_ex); + + if (elts == NULL) return set; + + for(list::iterator it=elts->begin(); it!=elts->end(); it++) { + env->CallVoidMethod(set, linkedListAdd, *it); + } + + return set; +} + +jobject CAstWrapper::getCallReference() { + return callReference; +} + +const char *CAstWrapper::getEntityName(jobject entity) { + jstring jstr = (jstring) env->CallObjectMethod(entity, _getEntityName); + THROW_ANY_EXCEPTION(java_ex); + + const char *cstr1 = env->GetStringUTFChars(jstr, NULL); + const char *cstr2 = strdup( cstr1 ); + env->ReleaseStringUTFChars(jstr, cstr1); + THROW_ANY_EXCEPTION(java_ex); + + return cstr2; +} diff --git a/com.ibm.wala.cast/source/c/jni/Exceptions.cpp b/com.ibm.wala.cast/source/c/jni/Exceptions.cpp new file mode 100755 index 000000000..35de36649 --- /dev/null +++ b/com.ibm.wala.cast/source/c/jni/Exceptions.cpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include "Exceptions.h" + +Exceptions::Exceptions(JNIEnv *java_env, jmp_buf& c_env) : + _java_env(java_env), + _c_env(c_env) +{ + _jre = java_env->FindClass("java/lang/RuntimeException"); + _ctr = java_env->GetMethodID(_jre, "", "(Ljava/lang/String;)V"); + _wrapper_ctr = + java_env->GetMethodID(_jre, + "", + "(Ljava/lang/String;Ljava/lang/Throwable;)V"); +} + +void Exceptions::throwAnyException(char *file_name, int line_number) { + if (_java_env->ExceptionCheck()) throwException(file_name, line_number); +} + +void Exceptions::throwException(char *file_name, int line_number) { + jthrowable real_ex = _java_env->ExceptionOccurred(); + _java_env->ExceptionClear(); + + char msg[strlen(file_name) + 1024]; + bzero(msg, strlen(file_name) + 1024); + sprintf(msg, "exception at %s:%d", file_name, line_number); + jstring java_message = _java_env->NewStringUTF(msg); + + jthrowable ex = (jthrowable) + _java_env->NewObject(_jre, _wrapper_ctr, java_message, real_ex); + + if (_java_env->ExceptionCheck()) { + jthrowable new_real_ex = _java_env->ExceptionOccurred(); + _java_env->Throw(new_real_ex); + } else { + _java_env->Throw(ex); + } + + longjmp( _c_env, -1 ); +} + +void +Exceptions::throwException(char *file_name, int line_number, char *c_message) { + char msg[strlen(file_name) + strlen(c_message) + 1024]; + bzero(msg, strlen(file_name) + strlen(c_message) + 1024); + sprintf(msg, "exception at %s:%d: %s", file_name, line_number, c_message); + jstring java_message = _java_env->NewStringUTF(msg); + jthrowable ex = (jthrowable)_java_env->NewObject(_jre, _ctr, java_message); + _java_env->Throw(ex); + + longjmp( _c_env, -1 ); +} + diff --git a/com.ibm.wala.cast/source/c/jni/Java_com_ibm_wala_cast_ir_translator_NativeBridge.cpp b/com.ibm.wala.cast/source/c/jni/Java_com_ibm_wala_cast_ir_translator_NativeBridge.cpp new file mode 100644 index 000000000..39c59fde1 --- /dev/null +++ b/com.ibm.wala.cast/source/c/jni/Java_com_ibm_wala_cast_ir_translator_NativeBridge.cpp @@ -0,0 +1,39 @@ + +#include + +#include "CAstWrapper.h" +#include "Exceptions.h" +#include "com_ibm_wala_cast_ir_translator_NativeBridge.h" + +JNIEXPORT void JNICALL +Java_com_ibm_wala_cast_ir_translator_NativeBridge_initialize( + JNIEnv *env, + jclass cls) +{ + TRY(exp, env) + + jclass CAstNode = env->FindClass( "com/ibm/wala/cast/tree/CAstNode" ); + THROW_ANY_EXCEPTION(exp); + jclass CAstOperator = env->FindClass( "com/ibm/wala/cast/tree/impl/CAstOperator" ); + THROW_ANY_EXCEPTION(exp); + jclass CAstQualifier = env->FindClass( "com/ibm/wala/cast/tree/CAstQualifier" ); + THROW_ANY_EXCEPTION(exp); + jclass CAstControlFlowMap = env->FindClass( "com/ibm/wala/cast/tree/CAstControlFlowMap" ); + THROW_ANY_EXCEPTION(exp); + +#define _CODE_CONSTANTS +#include "cast_constants.h" + +#define _CODE_OPERATORS +#include "cast_operators.h" + +#define _CODE_QUALIFIERS +#include "cast_qualifiers.h" + +#define _CODE_CFM +#include "cast_control_flow_map.h" + + CATCH() +} + + diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/analysis/typeInference/AstTypeInference.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/analysis/typeInference/AstTypeInference.java new file mode 100644 index 000000000..2be6e979a --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/analysis/typeInference/AstTypeInference.java @@ -0,0 +1,54 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.analysis.typeInference; + +import com.ibm.wala.analysis.typeInference.*; +import com.ibm.wala.cast.ir.ssa.*; +import com.ibm.wala.ipa.cha.*; +import com.ibm.wala.ssa.*; + +public class AstTypeInference extends TypeInference { + + protected class AstTypeOperatorFactory + extends TypeOperatorFactory + implements AstInstructionVisitor + { + public void visitAstLexicalRead(AstLexicalRead inst) { + result = new DeclaredTypeOperator(new ConeType(cha.getRootClass(), cha)); + } + public void visitAstLexicalWrite(AstLexicalWrite inst) { + } + public void visitAstGlobalRead(AstGlobalRead instruction) { + result = new DeclaredTypeOperator(new ConeType(cha.getRootClass(), cha)); + } + public void visitAstGlobalWrite(AstGlobalWrite instruction) { + } + public void visitNonExceptingThrow(NonExceptingThrowInstruction inst) { + } + public void visitAssert(AstAssertInstruction instruction) { + } + public void visitEachElementGet(EachElementGetInstruction inst) { + result = new DeclaredTypeOperator(new ConeType(cha.getRootClass(), cha)); + } + public void visitEachElementHasNext(EachElementHasNextInstruction inst) { + } + }; + + public AstTypeInference(IR ir, ClassHierarchy cha, boolean doPrimitives) { + super(ir, cha, doPrimitives); + } + + protected void initialize() { + init(ir, new TypeVarFactory(), new AstTypeOperatorFactory()); + } + +} + diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCFAPointerKeys.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCFAPointerKeys.java new file mode 100644 index 000000000..236e88959 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCFAPointerKeys.java @@ -0,0 +1,21 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import com.ibm.wala.ipa.callgraph.propagation.cfa.*; + +public class AstCFAPointerKeys extends DelegatingAstPointerKeys { + + public AstCFAPointerKeys() { + super(new CFAPointerKeys()); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCallGraph.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCallGraph.java new file mode 100644 index 000000000..c40211fef --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstCallGraph.java @@ -0,0 +1,120 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + + +import com.ibm.wala.cast.ir.cfg.*; +import com.ibm.wala.cast.ir.ssa.*; +import com.ibm.wala.cfg.*; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.callgraph.*; +import com.ibm.wala.ipa.callgraph.impl.*; +import com.ibm.wala.ipa.cha.*; +import com.ibm.wala.ssa.*; +import com.ibm.wala.util.*; +import com.ibm.wala.util.collections.*; +import com.ibm.wala.util.graph.traverse.DFS; +import com.ibm.wala.util.warnings.WarningSet; + +import java.util.*; + +public class AstCallGraph extends ExplicitCallGraph { + private final WarningSet warnings; + + public AstCallGraph(ClassHierarchy cha, AnalysisOptions options, WarningSet warnings) { + super(cha, options); + this.warnings = warnings; + } + + public class AstFakeRoot extends FakeRootMethod { + + public AstFakeRoot(ClassHierarchy cha, AnalysisOptions options) { + super(cha, options); + } + + public InducedCFG makeControlFlowGraph() { + return new AstInducedCFG(getStatements(warnings), this, Everywhere.EVERYWHERE); + } + + public AstLexicalRead addGlobalRead(String name) { + AstLexicalRead s = new AstLexicalRead(nextLocal++, null, name); + statements.add(s); + return s; + } + } + + public abstract class ScriptFakeRoot extends AstFakeRoot { + + public ScriptFakeRoot(ClassHierarchy cha, AnalysisOptions options) { + super(cha, options); + } + + public abstract SSAAbstractInvokeInstruction addDirectCall(int functionVn, int[] argVns, CallSiteReference callSite); + + } + + class AstCGNode extends ExplicitNode { + private Set callbacks; + + private AstCGNode(IMethod method, Context context) { + super(method, context); + } + + private void fireCallbacks() { + if (callbacks != null) { + boolean done = false; + while (!done) { + try { + for (Iterator x = callbacks.iterator(); x.hasNext();) { + ((Function) x.next()).apply(null); + } + } catch (ConcurrentModificationException e) { + done = false; + continue; + } + done = true; + } + } + } + + public void addCallback(Function callback) { + if (callbacks == null) + callbacks = new HashSet(1); + callbacks.add(callback); + } + + private void fireCallbacksTransitive() { + for(Iterator nodes = DFS.iterateFinishTime(AstCallGraph.this, new NonNullSingletonIterator(this)); + nodes.hasNext(); ) + { + ((AstCGNode)nodes.next()).fireCallbacks(); + } + } + + public boolean addTarget(CallSiteReference site, CGNode node) { + if (super.addTarget(site, node)) { + fireCallbacksTransitive(); + return true; + } else { + return false; + } + } + } + + protected ExplicitNode makeNode(IMethod method, Context context) { + return new AstCGNode(method, context); + } + + protected CGNode makeFakeRootNode() { + return findOrCreateNode(new AstFakeRoot(cha, options), Everywhere.EVERYWHERE); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstContextInsensitiveSSAContextInterpreter.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstContextInsensitiveSSAContextInterpreter.java new file mode 100644 index 000000000..0577660ee --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstContextInsensitiveSSAContextInterpreter.java @@ -0,0 +1,45 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import com.ibm.wala.cast.loader.*; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.callgraph.*; +import com.ibm.wala.ipa.callgraph.propagation.cfa.*; +import com.ibm.wala.ipa.cha.*; +import com.ibm.wala.ssa.*; +import com.ibm.wala.util.collections.EmptyIterator; +import com.ibm.wala.util.warnings.WarningSet; + +import java.util.*; + +public class AstContextInsensitiveSSAContextInterpreter + extends ContextInsensitiveSSAInterpreter +{ + + public AstContextInsensitiveSSAContextInterpreter(AnalysisOptions options, ClassHierarchy cha) { + super(options, cha); + } + + public boolean understands(IMethod method, Context context) { + return method instanceof AstMethod; + } + + public Iterator iterateCallSites(CGNode N, WarningSet warnings) { + IR ir = getIR(N, warnings); + if (ir == null) { + return EmptyIterator.instance(); + } else { + return ir.iterateCallSites(); + } + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstGlobalPointerKey.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstGlobalPointerKey.java new file mode 100644 index 000000000..371f79687 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstGlobalPointerKey.java @@ -0,0 +1,38 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import com.ibm.wala.ipa.callgraph.propagation.*; + +public class AstGlobalPointerKey extends AbstractPointerKey { + private final String globalName; + public String getName() { + return globalName; + } + + public AstGlobalPointerKey(String globalName) { + this.globalName = globalName; + } + + public boolean equals(Object x) { + return (x instanceof AstGlobalPointerKey) && + ((AstGlobalPointerKey)x).globalName.equals(globalName); + } + + public int hashCode() { + return globalName.hashCode(); + } + + public String toString() { + return "[global: " + globalName + "]"; + } +} + diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstPointerKeyFactory.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstPointerKeyFactory.java new file mode 100644 index 000000000..52a2cc9e9 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstPointerKeyFactory.java @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import com.ibm.wala.ipa.callgraph.propagation.*; + +import java.util.*; + +public interface AstPointerKeyFactory extends PointerKeyFactory { + + Iterator getPointerKeysForReflectedFieldRead(InstanceKey I, InstanceKey F); + + Iterator getPointerKeysForReflectedFieldWrite(InstanceKey I, InstanceKey F); + + PointerKey getPointerKeyForObjectCatalog(InstanceKey I); + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstSSAPropagationCallGraphBuilder.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstSSAPropagationCallGraphBuilder.java new file mode 100644 index 000000000..0b949e0f8 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/AstSSAPropagationCallGraphBuilder.java @@ -0,0 +1,1155 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.ibm.wala.analysis.reflection.FactoryBypassInterpreter; +import com.ibm.wala.analysis.typeInference.TypeInference; +import com.ibm.wala.cast.analysis.typeInference.AstTypeInference; +import com.ibm.wala.cast.ipa.callgraph.AstCallGraph.AstCGNode; +import com.ibm.wala.cast.ipa.callgraph.ScopeMappingInstanceKeys.ScopeMappingInstanceKey; +import com.ibm.wala.cast.ir.ssa.*; +import com.ibm.wala.cast.ir.ssa.AstIRFactory.AstIR; +import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access; +import com.ibm.wala.cast.ir.translator.AstTranslator; +import com.ibm.wala.cast.loader.AstMethod; +import com.ibm.wala.cast.loader.AstMethod.LexicalInformation; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.fixedpoint.impl.AbstractOperator; +import com.ibm.wala.fixedpoint.impl.UnaryOperator; +import com.ibm.wala.fixpoint.IVariable; +import com.ibm.wala.fixpoint.IntSetVariable; +import com.ibm.wala.ipa.callgraph.*; +import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph; +import com.ibm.wala.ipa.callgraph.propagation.*; +import com.ibm.wala.ipa.callgraph.propagation.cfa.DefaultSSAInterpreter; +import com.ibm.wala.ipa.callgraph.propagation.cfa.DelegatingSSAContextInterpreter; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ssa.*; +import com.ibm.wala.ssa.SSACFG.BasicBlock; +import com.ibm.wala.util.Function; +import com.ibm.wala.util.collections.EmptyIterator; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.Trace; +import com.ibm.wala.util.graph.traverse.NumberedDFSDiscoverTimeIterator; +import com.ibm.wala.util.intset.IntSetAction; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.intset.MutableIntSet; +import com.ibm.wala.util.warnings.WarningSet; + +public abstract class AstSSAPropagationCallGraphBuilder + extends SSAPropagationCallGraphBuilder +{ + + public static final boolean DEBUG_TYPE_INFERENCE = false; + public static final boolean DEBUG_PROPERTIES = false; + + ///////////////////////////////////////////////////////////////////////////// + // + // language specialization interface + // + ///////////////////////////////////////////////////////////////////////////// + + protected abstract boolean useObjectCatalog(); + + + ///////////////////////////////////////////////////////////////////////////// + // + // overall control + // + ///////////////////////////////////////////////////////////////////////////// + + protected + AstSSAPropagationCallGraphBuilder(ClassHierarchy cha, + WarningSet warnings, + AnalysisOptions options, + PointerKeyFactory pointerKeyFactory) + { + super(cha, warnings, options, pointerKeyFactory, options.usePreTransitiveSolver()); + } + + public SSAContextInterpreter + makeDefaultContextInterpreters(SSAContextInterpreter appContextInterpreter, + AnalysisOptions options, + ClassHierarchy cha, + ReflectionSpecification reflect, + WarningSet warnings) + { + SSAContextInterpreter c = new DefaultSSAInterpreter(options, cha, warnings); + c = new DelegatingSSAContextInterpreter(new AstContextInsensitiveSSAContextInterpreter(options, cha), c); + + c = new DelegatingSSAContextInterpreter(new FactoryBypassInterpreter(options, cha, reflect, warnings), c); + + if (appContextInterpreter == null) + return c; + else + return new DelegatingSSAContextInterpreter(appContextInterpreter, c); + } + + public PointerKey getPointerKeyForObjectCatalog(InstanceKey I) { + return ((AstPointerKeyFactory)pointerKeyFactory) + .getPointerKeyForObjectCatalog(I); + } + + public Iterator + getPointerKeysForReflectedFieldRead(InstanceKey I, InstanceKey F) + { + return ((AstPointerKeyFactory)pointerKeyFactory) + .getPointerKeysForReflectedFieldRead(I, F); + } + + public Iterator + getPointerKeysForReflectedFieldWrite(InstanceKey I, InstanceKey F) + { + return ((AstPointerKeyFactory)pointerKeyFactory) + .getPointerKeysForReflectedFieldWrite(I, F); + } + + ///////////////////////////////////////////////////////////////////////////// + // + // specialized pointer analysis + // + ///////////////////////////////////////////////////////////////////////////// + + protected class AstPointerFlowGraph extends PointerFlowGraph { + + protected class AstPointerFlowVisitor + extends InstructionVisitor + implements AstInstructionVisitor + { + protected AstPointerFlowVisitor(CGNode node, IR ir, BasicBlock bb) { + super(node, ir, bb); + } + + public void visitAstLexicalRead(AstLexicalRead instruction) { + + } + + public void visitAstLexicalWrite(AstLexicalWrite instruction) { + + } + + public void visitAstGlobalRead(AstGlobalRead instruction) { + + } + + public void visitAstGlobalWrite(AstGlobalWrite instruction) { + + } + + public void visitNonExceptingThrow(NonExceptingThrowInstruction inst) { + + } + + public void visitAssert(AstAssertInstruction instruction) { + + } + + public void visitEachElementGet(EachElementGetInstruction inst) { + + } + + public void visitEachElementHasNext(EachElementHasNextInstruction inst) { + + } + } + + protected AstPointerFlowGraph(PointerAnalysis pa, CallGraph cg) { + super(pa,cg); + } + + protected InstructionVisitor makeInstructionVisitor(CGNode node, IR ir, BasicBlock bb) { + return new AstPointerFlowVisitor(node,ir, bb); + } + } + + public PointerFlowGraphFactory getPointerFlowGraphFactory() { + return new PointerFlowGraphFactory() { + public PointerFlowGraph make(PointerAnalysis pa, CallGraph cg) { + return new AstPointerFlowGraph(pa,cg); + } + }; + } + + ///////////////////////////////////////////////////////////////////////////// + // + // top-level node constraint generation + // + ///////////////////////////////////////////////////////////////////////////// + + + protected ExplicitCallGraph createEmptyCallGraph(ClassHierarchy cha, AnalysisOptions options) { + return new AstCallGraph(cha, options, getWarnings()); + } + + protected TypeInference makeTypeInference(IR ir, ClassHierarchy cha) { + TypeInference ti = new AstTypeInference(ir, cha, false); + ti.solve(); + + if (DEBUG_TYPE_INFERENCE) { + Trace.println("IR of " + ir.getMethod()); + Trace.println( ir ); + Trace.println("TypeInference of " + ir.getMethod()); + for(int i = 0; i < ir.getSymbolTable().getMaxValueNumber(); i++) { + if (ti.isUndefined(i)) { + Trace.println(" value " + i + " is undefined"); + } else { + Trace.println(" value " + i + " has type " + ti.getType(i)); + } + } + } + + return ti; + } + + protected class AstInterestingVisitor + extends InterestingVisitor + implements AstInstructionVisitor + { + protected AstInterestingVisitor(int vn) { + super(vn); + } + + public void visitAstLexicalRead(AstLexicalRead instruction) { + bingo = true; + } + + public void visitAstLexicalWrite(AstLexicalWrite instruction) { + bingo = true; + } + + public void visitAstGlobalRead(AstGlobalRead instruction) { + bingo = true; + } + + public void visitAstGlobalWrite(AstGlobalWrite instruction) { + bingo = true; + } + + public void visitNonExceptingThrow(NonExceptingThrowInstruction inst) { + bingo = true; + } + + public void visitAssert(AstAssertInstruction instruction) { + bingo = true; + } + + public void visitEachElementGet(EachElementGetInstruction inst) { + bingo = true; + } + + public void visitEachElementHasNext(EachElementHasNextInstruction inst) { + + } + } + + protected InterestingVisitor makeInterestingVisitor(int vn) { + return new AstInterestingVisitor(vn); + } + + ///////////////////////////////////////////////////////////////////////////// + // + // lexical scoping handling + // + ///////////////////////////////////////////////////////////////////////////// + + private abstract class LexicalOperator extends UnaryOperator { + private final AstCGNode node; + private final Access[] accesses; + private final boolean isLoad; + + private LexicalOperator(AstCGNode node, + Access[] accesses, + boolean isLoad) + { + this.node = node; + this.isLoad = isLoad; + this.accesses = accesses; + } + + private void doLexicalPointerKeys() { + for(int i = 0; i < accesses.length; i++) { + final String name = accesses[i].variableName; + final String definer = accesses[i].variableDefiner; + final int vn = accesses[i].valueNumber; + + if (AstTranslator.DEBUG_LEXICAL) + Trace.println("looking up lexical parent " + definer); + + for(Iterator DS = getLexicalDefiners(node, definer).iterator(); + DS.hasNext(); ) + { + final CGNode D = (CGNode) DS.next(); + + Iterator PS = new NumberedDFSDiscoverTimeIterator(callGraph, node) { + /** + * + */ + private static final long serialVersionUID = 4546217460630659884L; + + protected void visitEdge(Object callee, Object caller) { + CGNode from = (CGNode) caller; + CGNode to = (CGNode) callee; + + for(Iterator SS = from.getPossibleSites(to); SS.hasNext(); ) { + CallSiteReference site = (CallSiteReference)SS.next(); + + PointerKey V = + isLoad? + getLocalReadKey(from, site, name, definer, D): + getLocalWriteKey(from, site, name, definer, D); + + if (V != null) { + action(V, vn); + } + } + } + + protected Iterator getConnected(Object n) { + if (n.equals(D) ) + return EmptyIterator.instance(); + else + return G.getPredNodes(n); + } + }; + + while (PS.hasNext()) { PS.next(); } + } + } + } + + public byte evaluate(IVariable lhs, IVariable rhs) { + doLexicalPointerKeys(); + return NOT_CHANGED; + } + + abstract void action(PointerKey lexicalKey, int vn); + + public String toString() { return "lexical op"; } + + public boolean equals(Object o) { return o==this; } + + public int hashCode() { return System.identityHashCode(this); } + } + + private Set getLexicalDefiners(final CGNode opNode, final String definer) { + if (definer == null) { + return Collections.singleton(callGraph.getFakeRootNode()); + + } else { + final Set result = new HashSet(); + PointerKey F = getPointerKeyForLocal(opNode, 1); + + IR ir = getCFAContextInterpreter().getIR(opNode, getWarnings()); + SymbolTable symtab = ir.getSymbolTable(); + DefUse du = getOptions().getSSACache().findOrCreateDU(ir, opNode.getContext()); + if (contentsAreInvariant(symtab, du, 1)) { + system.recordImplicitPointsToSet(F); + final InstanceKey[] functionKeys = + getInvariantContents(symtab, du, opNode, 1, this); + for(int f = 0; f < functionKeys.length; f++) { + system.findOrCreateIndexForInstanceKey( functionKeys[f] ); + ScopeMappingInstanceKey K = (ScopeMappingInstanceKey)functionKeys[f]; + result.add( K.getDefiningNode( definer ) ); + } + } else { + PointsToSetVariable FV = system.findOrCreatePointsToSet( F ); + if (FV.getValue() != null) { + FV.getValue().foreach(new IntSetAction() { + public void act(int ptr) { + InstanceKey iKey = system.getInstanceKey(ptr); + if (iKey instanceof ScopeMappingInstanceKey) { + ScopeMappingInstanceKey K = (ScopeMappingInstanceKey) iKey; + result.add( K.getDefiningNode( definer ) ); + } else { + Assertions.UNREACHABLE("unexpected instance key " + iKey); + } + } + }); + } + } + + return result; + } + } + + private boolean isEqual(Object a, Object b) { + if (a == null) return b==null; else return a.equals(b); + } + + private Set discoveredUpwardFunargs = new HashSet(); + + private void addUpwardFunargConstraints(PointerKey lhs, + String name, + String definer, + CGNode definingNode) + { + discoveredUpwardFunargs.add( lhs ); + + LexicalInformation LI = ((AstMethod)definingNode.getMethod()).lexicalInfo; + Pair[] names = LI.getExposedNames(); + for(int i = 0; i < names.length; i++) { + if (name.equals(names[i].fst) && definer.equals(names[i].snd)) { + int vn = LI.getExitExposedUses()[ i ]; + if (vn > 0) { + IR ir = getCFAContextInterpreter().getIR(definingNode, getWarnings()); + DefUse du = getCFAContextInterpreter().getDU(definingNode, getWarnings()); + SymbolTable st = ir.getSymbolTable(); + + PointerKey rhs = getPointerKeyForLocal(definingNode, vn); + + if (contentsAreInvariant(st, du, vn)) { + system.recordImplicitPointsToSet(rhs); + final InstanceKey[] objs = getInvariantContents(st, du, definingNode, vn, this); + for(int f = 0; f < objs.length; f++) { + system.findOrCreateIndexForInstanceKey( objs[f] ); + system.newConstraint(lhs, objs[f]); + } + } else { + system.newConstraint(lhs, assignOperator, rhs); + } + } + + return; + } + } + + Assertions.UNREACHABLE(); + } + + private PointerKey handleRootLexicalReference(String name, + String definer, + final CGNode definingNode) + { + // global variable + if (definer == null) { + return new AstGlobalPointerKey(name); + + // upward funarg + } else { + class UpwardFunargPointerKey extends AstGlobalPointerKey { + UpwardFunargPointerKey(String name) { super(name); } + + public CGNode getDefiningNode() { return definingNode; } + + public boolean equals(Object x) { + return + (x instanceof UpwardFunargPointerKey) && + super.equals(x) && + definingNode.equals(((UpwardFunargPointerKey)x).getDefiningNode()); + } + + public int hashCode() { + return super.hashCode()*definingNode.hashCode(); + } + + public String toString() { + return "[upward:" + getName() + ":" + definingNode + "]"; + } + } + + PointerKey result = new UpwardFunargPointerKey(name); + + if (! discoveredUpwardFunargs.contains( result )) { + addUpwardFunargConstraints(result, name, definer, definingNode); + } + + return result; + } + } + + private PointerKey getLocalReadKey(CGNode n, + CallSiteReference callSite, + String name, + String definer, + CGNode definingNode) + { + IMethod M = n.getMethod(); + if (n == callGraph.getFakeRootNode()) { + return handleRootLexicalReference(name, definer, definingNode); + } + + else if (M instanceof AstMethod) { + AstIR ir = (AstIR)getCFAContextInterpreter().getIR(n, getWarnings()); + int pc = callSite.getProgramCounter(); + LexicalInformation L = ((AstMethod)M).lexicalInfo; + + // some people have no lexical uses at all + if (L == null) { + return null; + } + + AbstractLexicalInvoke I = + (AbstractLexicalInvoke) ir.getInstructions()[pc]; + + // find existing explicit lexical use + for(int i = I.getNumberOfParameters(); i < I.getNumberOfUses(); i++) { + Access A = I.getLexicalUse(i); + if (A.variableName.equals(name)&&isEqual(A.variableDefiner,definer)) { + return getPointerKeyForLocal(n, A.valueNumber); + } + } + + // make new lexical use + int values[] = L.getExposedUses(pc); + Pair names[] = L.getExposedNames(); + if (names != null && names.length > 0) { + for(int i = 0; i < names.length; i++) { + if (name.equals(names[i].fst) && isEqual(definer,names[i].snd)) { + if (values[i] == -1) return null; + + I.addLexicalUse(new Access(name, definer, values[i])); + + if (SSAConversion.DEBUG_UNDO) + Trace.println("copy use #" + (-i - 1) + " to use #" + (I.getNumberOfUses()-1) + " at inst " + pc); + + SSAConversion.copyUse(ir, pc, -i - 1, pc, I.getNumberOfUses()-1); + + return getPointerKeyForLocal(n, values[i]); + } + } + } + + return null; + + } else { + return null; + } + } + + private PointerKey getLocalWriteKey(CGNode n, + CallSiteReference callSite, + String name, + String definer, + CGNode definingNode) + { + IMethod M = n.getMethod(); + if (n == callGraph.getFakeRootNode()) { + return handleRootLexicalReference(name, definer, definingNode); + } + + else if (M instanceof AstMethod) { + AstMethod AstM = (AstMethod)M; + LexicalInformation L = AstM.lexicalInfo; + + // some people have no lexical uses at all + if (L == null) return null; + + AstIR ir = (AstIR)getCFAContextInterpreter().getIR(n, getWarnings()); + int pc = callSite.getProgramCounter(); + AbstractLexicalInvoke I = + (AbstractLexicalInvoke) ir.getInstructions()[pc]; + + // find existing explicit lexical def + for(int i = 2; i < I.getNumberOfDefs(); i++) { + Access A = I.getLexicalDef(i); + if (A.variableName.equals(name)&&isEqual(A.variableDefiner,definer)) { + return getPointerKeyForLocal(n, A.valueNumber); + } + } + + // make new lexical def + int values[] = L.getExposedUses(pc); + Pair names[] = L.getExposedNames(); + if (names != null && names.length > 0) { + for(int i = 0; i < names.length; i++) { + if (name.equals(names[i].fst) && isEqual(definer,names[i].snd)) { + if (values[i] == -1) return null; + + // if values[i] was altered by copy propagation, we must undo + // that to ensure we do not bash the wrong value number in the + // the next steps. + SSAConversion.undoCopyPropagation(ir, pc, -i - 1); + // possibly new instruction due to renames, so get it again + I = (AbstractLexicalInvoke) ir.getInstructions()[pc]; + + I.addLexicalDef(new Access(name, definer, values[i])); + + if (SSAConversion.DEBUG_UNDO) + Trace.println("new def of " + values[i] + " at inst " + pc + ": " + I); + + // new def has broken SSA form for values[i], so fix for that value + MutableIntSet vs = IntSetUtil.make(); + vs.add( values[i] ); + SSAConversion.convert(AstM, ir, getOptions().getSSAOptions()); + + // now redo analysis + // TODO: only values[i] uses need to be re-done. + getOptions().getSSACache().invalidateDU(M, n.getContext()); + // addConstraintsFromChangedNode(n); + markChanged( n ); + + // get SSA-renamed def from call site instruction + return getLocalWriteKey(n, callSite, name, definer, definingNode); + } + } + } + + return null; + } else { + return null; + } + } + + ///////////////////////////////////////////////////////////////////////////// + // + // property manipulation handling + // + ///////////////////////////////////////////////////////////////////////////// + + private interface ReflectedFieldAction { + void action(PointerKey fieldKey); + void dump(PointerKey fieldKey, boolean constObj, boolean constProp); + } + + private void newFieldOperation(CGNode opNode, final int objVn, final int fieldsVn, final boolean isLoadOperation, final ReflectedFieldAction action) { + IR ir = getCFAContextInterpreter().getIR(opNode, getWarnings()); + SymbolTable symtab = ir.getSymbolTable(); + DefUse du = getCFAContextInterpreter().getDU(opNode, getWarnings()); + PointerKey objKey = getPointerKeyForLocal(opNode, objVn); + final PointerKey fieldKey = getPointerKeyForLocal(opNode, fieldsVn); + + // log field access + if (DEBUG_PROPERTIES) { + if (isLoadOperation) + Trace.print("adding read of " + objKey + "." + fieldKey + ":"); + else + Trace.print("adding write of " + objKey + "." + fieldKey + ":"); + + if (contentsAreInvariant(symtab, du, objVn)) { + Trace.print(" constant obj:"); + InstanceKey[] x=getInvariantContents(symtab, du, opNode, objVn, this); + for(int i = 0 ; i < x.length; i++) { + Trace.print( x[i].toString() + " " ); + } + } else { + Trace.print(" obj:" + system.findOrCreatePointsToSet(objKey)); + } + + if (contentsAreInvariant(symtab, du, fieldsVn)) { + Trace.print(" constant prop:"); + InstanceKey[] x=getInvariantContents(symtab, du, opNode, fieldsVn, this); + for(int i = 0 ; i < x.length; i++) { + Trace.print( x[i].toString() + " " ); + } + } else { + Trace.print(" props:" + system.findOrCreatePointsToSet(fieldKey)); + } + + Trace.print("\n"); + } + + // make sure instance keys get mapped for PointerAnalysisImpl + if (contentsAreInvariant(symtab, du, objVn)) { + InstanceKey[] x=getInvariantContents(symtab, du, opNode, objVn, this); + for(int i = 0; i < x.length; i++) { + system.findOrCreateIndexForInstanceKey(x[i]); + } + } + if (contentsAreInvariant(symtab, du, fieldsVn)) { + InstanceKey[] x=getInvariantContents(symtab, du, opNode, fieldsVn, this); + for(int i = 0; i < x.length; i++) { + system.findOrCreateIndexForInstanceKey(x[i]); + } + } + + // process field access + if (contentsAreInvariant(symtab, du, objVn)) { + system.recordImplicitPointsToSet(objKey); + final InstanceKey[] objKeys = getInvariantContents(symtab, du, opNode, objVn, this); + + if (contentsAreInvariant(symtab, du, fieldsVn)) { + system.recordImplicitPointsToSet(fieldKey); + InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn, this); + + for(int o = 0; o < objKeys.length; o++) { + PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]); + for(int f = 0; f < fieldsKeys.length; f++) { + if (isLoadOperation) { + for(Iterator keys = + getPointerKeysForReflectedFieldRead(objKeys[o], fieldsKeys[f]); + keys.hasNext(); ) + { + PointerKey key = (PointerKey)keys.next(); + if (DEBUG_PROPERTIES) action.dump( key, true, true ); + action.action( key ); + } + } else { + system.newConstraint(objCatalog, fieldsKeys[f]); + for(Iterator keys = + getPointerKeysForReflectedFieldWrite(objKeys[o],fieldsKeys[f]); + keys.hasNext(); ) + { + PointerKey key = (PointerKey)keys.next(); + if (DEBUG_PROPERTIES) action.dump( key, true, true ); + action.action( key ); + } + } + } + } + + } else { + if (! isLoadOperation) { + for(int o = 0; o < objKeys.length; o++) { + PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[o]); + system.newConstraint(objCatalog, assignOperator, fieldKey); + } + } + + system.newSideEffect( + new UnaryOperator() { + public byte evaluate(IVariable lhs, IVariable rhs) { + final IntSetVariable fields = (IntSetVariable) rhs; + if (fields.getValue() != null) { + fields.getValue().foreach( + new IntSetAction() { + public void act(int fptr) { + InstanceKey field = system.getInstanceKey(fptr); + for(int o = 0; o < objKeys.length; o++) { + for(Iterator keys = + isLoadOperation? + getPointerKeysForReflectedFieldRead(objKeys[o],field): + getPointerKeysForReflectedFieldWrite(objKeys[o],field); + keys.hasNext(); ) + { + PointerKey key = (PointerKey)keys.next(); + if (DEBUG_PROPERTIES) action.dump(key, false, true); + action.action( key ); + } + } + } + } + ); + } + return NOT_CHANGED; + } + public int hashCode() { + return System.identityHashCode(this); + } + public boolean equals(Object o) { + return o==this; + } + public String toString() { + return "field op" + objVn + ", " + fieldsVn; + } + }, + fieldKey); + } + + } else { + if (contentsAreInvariant(symtab, du, fieldsVn)) { + system.recordImplicitPointsToSet(fieldKey); + final InstanceKey[] fieldsKeys = getInvariantContents(symtab, du, opNode, fieldsVn, this); + + system.newSideEffect( + new UnaryOperator() { + public byte evaluate(IVariable lhs, IVariable rhs) { + final IntSetVariable objects = (IntSetVariable) rhs; + if (objects.getValue() != null) { + objects.getValue().foreach( + new IntSetAction() { + public void act(int optr) { + InstanceKey object = system.getInstanceKey(optr); + PointerKey objCatalog = + getPointerKeyForObjectCatalog(object); + for(int f = 0; f < fieldsKeys.length; f++) { + if (isLoadOperation) { + for(Iterator keys = + getPointerKeysForReflectedFieldRead(object, fieldsKeys[f]); + keys.hasNext(); ) + { + PointerKey key = (PointerKey)keys.next(); + if (DEBUG_PROPERTIES) action.dump(key, true, false); + action.action( key ); + } + } else { + system.newConstraint(objCatalog, fieldsKeys[f]); + for(Iterator keys = + getPointerKeysForReflectedFieldWrite(object,fieldsKeys[f]); + keys.hasNext(); ) + { + PointerKey key = (PointerKey)keys.next(); + if (DEBUG_PROPERTIES) action.dump(key, true, false); + action.action( key ); + } + } + } + } + } + ); + } + return NOT_CHANGED; + } + public int hashCode() { + return System.identityHashCode(this); + } + public boolean equals(Object o) { + return o==this; + } + public String toString() { + return "field op" + objVn + ", " + fieldsVn; + } + }, + objKey); + + } else { + system.newSideEffect( + new AbstractOperator() { + public byte evaluate(IVariable lhs, final IVariable[] rhs) { + final IntSetVariable receivers = (IntSetVariable) rhs[0]; + final IntSetVariable fields = (IntSetVariable) rhs[1]; + if (receivers.getValue() != null && fields.getValue() != null) { + receivers.getValue().foreach( + new IntSetAction() { + public void act(int rptr) { + final InstanceKey receiver = system.getInstanceKey(rptr); + + if (! isLoadOperation) { + PointerKey cat = + getPointerKeyForObjectCatalog(receiver); + system.newConstraint(cat, assignOperator, fieldKey); + } + + fields.getValue().foreach( + new IntSetAction() { + public void act(int fptr) { + InstanceKey field = system.getInstanceKey(fptr); + for(Iterator keys = + isLoadOperation? + getPointerKeysForReflectedFieldRead(receiver, field): + getPointerKeysForReflectedFieldWrite(receiver, field); + keys.hasNext(); ) + { + PointerKey key = (PointerKey)keys.next(); + if (DEBUG_PROPERTIES) + action.dump(key, false, false); + action.action( key ); + } + } + } + ); + } + } + ); + } + + return NOT_CHANGED; + } + + public String toString() { return "field op"; } + + public boolean equals(Object o) { return o==this; } + + public int hashCode() { return System.identityHashCode(this); } + }, + objKey, + fieldKey); + } + } + + if (DEBUG_PROPERTIES) { + Trace.println("finished\n"); + } + } + + protected void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, int rhsVn) { + IR ir = getCFAContextInterpreter().getIR(opNode, getWarnings()); + SymbolTable symtab = ir.getSymbolTable(); + DefUse du = getCFAContextInterpreter().getDU(opNode, getWarnings()); + PointerKey rhsKey = getPointerKeyForLocal(opNode, rhsVn); + if (contentsAreInvariant(symtab, du, rhsVn)) { + system.recordImplicitPointsToSet(rhsKey); + newFieldWrite(opNode, objVn, fieldsVn, getInvariantContents(symtab, du, opNode, rhsVn, this)); + } else { + newFieldWrite(opNode, objVn, fieldsVn, rhsKey); + } + } + + protected void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final InstanceKey[] rhsFixedValues) { + try { + + newFieldOperation(opNode, objVn, fieldsVn, false, new ReflectedFieldAction() { + public void dump(PointerKey fieldKey, boolean constObj, boolean constProp) { + Trace.println("writing fixed rvals to " + fieldKey + " " + constObj + ", " + constProp); + for(int i = 0; i < rhsFixedValues.length; i++) { + Trace.println("writing " + rhsFixedValues[i]); + } + } + public void action(PointerKey fieldKey) { + for(int i = 0; i < rhsFixedValues.length; i++) { + system.findOrCreateIndexForInstanceKey(rhsFixedValues[i]); + system.newConstraint(fieldKey, rhsFixedValues[i]); + } + } + }); + + } catch (RuntimeException e) { + System.err.println("error: " + e); + System.err.println( getCFAContextInterpreter().getIR(opNode, getWarnings()) ); + throw e; + } + } + + protected void newFieldWrite(CGNode opNode, int objVn, int fieldsVn, final PointerKey rhs) { + newFieldOperation(opNode, objVn, fieldsVn, false, new ReflectedFieldAction() { + public void dump(PointerKey fieldKey, boolean constObj, boolean constProp) { + Trace.println("write " + rhs + " to " + fieldKey + " " + constObj + ", " + constProp); + } + public void action(PointerKey fieldKey) { + system.newConstraint(fieldKey, assignOperator, rhs); + } + }); + } + + protected void newFieldRead(CGNode opNode, int objVn, int fieldsVn, int lhsVn) { + newFieldRead(opNode, objVn, fieldsVn, getPointerKeyForLocal(opNode, lhsVn)); + } + + protected void newFieldRead(CGNode opNode, int objVn, int fieldsVn, final PointerKey lhs) { + newFieldOperation(opNode, objVn, fieldsVn, true, new ReflectedFieldAction() { + public void dump(PointerKey fieldKey, boolean constObj, boolean constProp) { + Trace.println("read " + lhs + " from " + fieldKey + " " + constObj + ", " + constProp); + } + public void action(PointerKey fieldKey) { + system.newConstraint(lhs, assignOperator, fieldKey); + } + }); + } + + + ///////////////////////////////////////////////////////////////////////////// + // + // IR visitor specialization for Ast-specific IR types + // + ///////////////////////////////////////////////////////////////////////////// + + protected class AstConstraintVisitor + extends ConstraintVisitor + implements AstInstructionVisitor + { + + public AstConstraintVisitor(ExplicitCallGraph.ExplicitNode node, IR ir, ExplicitCallGraph callGraph, DefUse du) { + super(node, ir, callGraph, du); + } + + public void visitNonExceptingThrow(NonExceptingThrowInstruction inst) { + // no-op: exceptions handled elsewhere + // (see comment in SSAPropagationCallGraphBuilder) + } + + private void visitLexical(final LexicalOperator op) { + final PointerKey function = getPointerKeyForLocal(node, 1); + if (contentsAreInvariant(symbolTable, du, 1)) { + op.doLexicalPointerKeys(); + } else { + system.newSideEffect(op, function); + } + + ((AstCGNode)node).addCallback(new Function() { + public Object apply(Object ignore) { + op.doLexicalPointerKeys(); + return null; + } + }); + } + + public void visitAstLexicalRead(AstLexicalRead instruction) { + visitLexical(new LexicalOperator((AstCGNode)node, instruction.getAccesses(), true) { + void action(PointerKey lexicalKey, int vn) { + PointerKey lval = getPointerKeyForLocal(node, vn); + if (lexicalKey instanceof LocalPointerKey) { + CGNode lnode = ((LocalPointerKey)lexicalKey).getNode(); + int lvn = ((LocalPointerKey)lexicalKey).getValueNumber(); + IR lir = getCFAContextInterpreter().getIR(lnode, getWarnings()); + SymbolTable lsymtab = lir.getSymbolTable(); + DefUse ldu = getOptions().getSSACache().findOrCreateDU(lir, lnode.getContext()); + if (contentsAreInvariant(lsymtab, ldu, lvn)) { + InstanceKey[] ik = getInvariantContents(lsymtab, ldu, lnode, lvn, AstSSAPropagationCallGraphBuilder.this); + system.recordImplicitPointsToSet(lexicalKey); + for(int i = 0; i < ik.length; i++) { + system.findOrCreateIndexForInstanceKey(ik[i]); + system.newConstraint(lval, ik[i]); + } + + return; + } + } + + system.newConstraint(lval, assignOperator, lexicalKey); + } + }); + } + + public void visitAstLexicalWrite(AstLexicalWrite instruction) { + visitLexical(new LexicalOperator((AstCGNode)node, instruction.getAccesses(), false) { + void action(PointerKey lexicalKey, int vn) { + PointerKey rval = getPointerKeyForLocal(node,vn); + if (contentsAreInvariant(symbolTable, du, vn)) { + InstanceKey[] ik = getInvariantContents(symbolTable, du, node, vn, AstSSAPropagationCallGraphBuilder.this); + system.recordImplicitPointsToSet(rval); + for(int i = 0; i < ik.length; i++) { + system.findOrCreateIndexForInstanceKey(ik[i]); + system.newConstraint(lexicalKey, ik[i]); + } + } else { + system.newConstraint(lexicalKey, assignOperator, rval); + } + } + }); + } + + public void visitAstGlobalRead(AstGlobalRead instruction) { + visitGetInternal(instruction.getDef(), + -1, + true, + instruction.getDeclaredField()); + } + + public void visitAstGlobalWrite(AstGlobalWrite instruction) { + visitPutInternal(instruction.getVal(), + -1, + true, + instruction.getDeclaredField()); + } + + public void visitPut(SSAPutInstruction inst) { + super.visitPut(inst); + + if (inst.isStatic() || !useObjectCatalog()) return; + + SymbolTable symtab = ir.getSymbolTable(); + + int objVn = inst.getRef(); + String fieldName = inst.getDeclaredField().getName().toString(); + int fieldNameVn = symtab.getConstant( fieldName ); + + final PointerKey objKey = getPointerKeyForLocal(node, objVn); + + final InstanceKey[] fieldNameKeys = + getInvariantContents(symtab, du, node, fieldNameVn, AstSSAPropagationCallGraphBuilder.this); + Assertions._assert( fieldNameKeys.length == 1 ); + + if (contentsAreInvariant(symtab, du, objVn)) { + system.recordImplicitPointsToSet(objKey); + final InstanceKey[] objKeys = + getInvariantContents(symtab, du, node, objVn, AstSSAPropagationCallGraphBuilder.this); + + for(int i = 0; i < objKeys.length; i++) { + PointerKey objCatalog = getPointerKeyForObjectCatalog(objKeys[i]); + system.newConstraint(objCatalog, fieldNameKeys[0]); + } + + } else { + system.newSideEffect( + new UnaryOperator() { + public byte evaluate(IVariable lhs, IVariable rhs) { + final IntSetVariable objects = (IntSetVariable) rhs; + if (objects.getValue() != null) { + objects.getValue().foreach( + new IntSetAction() { + public void act(int optr) { + InstanceKey object = system.getInstanceKey(optr); + PointerKey cat = getPointerKeyForObjectCatalog(object); + system.newConstraint(cat, fieldNameKeys[0]); + } + } + ); + } + return NOT_CHANGED; + } + public int hashCode() { + return System.identityHashCode(this); + } + public boolean equals(Object o) { + return o==this; + } + public String toString() { + return "field name record: " + objKey; + } + }, + objKey); + } + } + + public void visitAssert(AstAssertInstruction instruction) { + + } + + public void visitEachElementHasNext(EachElementHasNextInstruction inst) { + + } + + public void visitEachElementGet(EachElementGetInstruction inst) { + int lval = inst.getDef(0); + final PointerKey lk = getPointerKeyForLocal(node, lval); + + int rval = inst.getUse(0); + final PointerKey rk = getPointerKeyForLocal(node, rval); + + if (contentsAreInvariant(symbolTable, du, rval)) { + InstanceKey objects[] = getInvariantContents(symbolTable, du, node, rval, AstSSAPropagationCallGraphBuilder.this); + for(int i = 0; i < objects.length; i++) { + PointerKey catalog = getPointerKeyForObjectCatalog(objects[i]); + system.newConstraint(lk, assignOperator, catalog); + } + } + + else { + system.newSideEffect( + new UnaryOperator() { + public byte evaluate(IVariable lhs, IVariable rhs) { + final IntSetVariable objects = (IntSetVariable) rhs; + if (objects.getValue() != null) { + objects.getValue().foreach( + new IntSetAction() { + public void act(int optr) { + InstanceKey object = system.getInstanceKey(optr); + PointerKey objCatalog = + getPointerKeyForObjectCatalog(object); + system.newConstraint(lk, assignOperator, objCatalog); + } + } + ); + } + return NOT_CHANGED; + } + public int hashCode() { + return System.identityHashCode(this); + } + public boolean equals(Object o) { + return o==this; + } + public String toString() { + return "get catalog op" + rk; + } + }, + rk); + } + } + + + } + + protected ConstraintVisitor makeVisitor(ExplicitCallGraph.ExplicitNode node, + IR ir, + DefUse du, + ExplicitCallGraph callGraph) + { + return new AstConstraintVisitor(node, ir, callGraph, du); + } +} + diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/CAstAnalysisScope.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/CAstAnalysisScope.java new file mode 100644 index 000000000..9339f7a48 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/CAstAnalysisScope.java @@ -0,0 +1,144 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +// Licensed Materials - Property of IBM +// 5724-D15 +// (C) Copyright IBM Corporation 2004. All Rights Reserved. +// Note to U.S. Government Users Restricted Rights: Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. +// +// --------------------------------------------------------------------------- + +package com.ibm.wala.cast.ipa.callgraph; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Iterator; + +import com.ibm.wala.cast.loader.*; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.util.Atom; +import com.ibm.wala.util.collections.NonNullSingletonIterator; +import com.ibm.wala.util.debug.Assertions; + +public class CAstAnalysisScope extends AnalysisScope { + private final ClassLoaderReference theLoader; + + public CAstAnalysisScope(SingleClassLoaderFactory loaders) { + this.theLoader = loaders.getTheReference(); + } + + public CAstAnalysisScope(String[] sourceFileNames, SingleClassLoaderFactory loaders) throws IOException { + this(loaders); + for(int i = 0; i < sourceFileNames.length; i++) { + File F = new File( sourceFileNames[i] ); + addSourceFileToScope(theLoader, F, F.getParent()); + } + } + + public CAstAnalysisScope(URL[] sources, SingleClassLoaderFactory loaders) throws IOException { + this(loaders); + for(int i = 0; i < sources.length; i++) { + addToScope(theLoader, new SourceURLModule(sources[i])); + } + } + + public CAstAnalysisScope(SourceFileModule[] sources, SingleClassLoaderFactory loaders) throws IOException { + this(loaders); + for(int i = 0; i < sources.length; i++) { + addToScope(theLoader, sources[i]); + } + } + + /** + * Return the information regarding the primordial loader. + * + * @return ClassLoaderReference + */ + public ClassLoaderReference getPrimordialLoader() { + Assertions.UNREACHABLE(); + return null; + } + + /** + * Return the information regarding the extension loader. + * + * @return ClassLoaderReference + */ + public ClassLoaderReference getExtensionLoader() { + Assertions.UNREACHABLE(); + return null; + } + + /** + * Return the information regarding the application loader. + * + * @return ClassLoaderReference + */ + public ClassLoaderReference getApplicationLoader() { + Assertions.UNREACHABLE(); + return null; + } + + /** + * @return Returns the arrayClassLoader. + */ + public ArrayClassLoader getArrayClassLoader() { + Assertions.UNREACHABLE(); + return null; + } + + /** + * Return the information regarding the application loader. + * + * @return ClassLoaderReference + */ + public ClassLoaderReference getSyntheticLoader() { + Assertions.UNREACHABLE(); + return null; + } + + /** + * Add a class file to the scope for a loader + * + * @param loader + * @param file + */ + public void addClassFileToScope(ClassLoaderReference loader, File file) { + Assertions.UNREACHABLE(); + } + + /** + * @return the ClassLoaderReference specified by name. + */ + public ClassLoaderReference getLoader(Atom name) { + if (Assertions.verifyAssertions) { + Assertions._assert(name.equals(theLoader.getName())); + } + return theLoader; + } + + /** + * @return an Iterator over the loaders. + */ + public Iterator getLoaders() { + return new NonNullSingletonIterator( theLoader ); + } + + /** + * @return the number of loaders. + */ + public int getNumberOfLoaders() { + return 1; + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/DelegatingAstPointerKeys.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/DelegatingAstPointerKeys.java new file mode 100644 index 000000000..1fa2f2995 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/DelegatingAstPointerKeys.java @@ -0,0 +1,105 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.callgraph.*; +import com.ibm.wala.ipa.callgraph.propagation.*; +import com.ibm.wala.util.*; +import com.ibm.wala.util.collections.*; + +import java.util.*; + +public class DelegatingAstPointerKeys implements AstPointerKeyFactory { + private final PointerKeyFactory base; + + public DelegatingAstPointerKeys(PointerKeyFactory base) { + this.base = base; + } + + public PointerKey getPointerKeyForLocal(CGNode node, int valueNumber) { + return base.getPointerKeyForLocal(node, valueNumber); + } + + public FilteredPointerKey getFilteredPointerKeyForLocal(CGNode node, int valueNumber, IClass filter) { + return base.getFilteredPointerKeyForLocal(node, valueNumber, filter); + } + + public InstanceFilteredPointerKey getFilteredPointerKeyForLocal(CGNode node, int valueNumber, InstanceKey filter) { + return base.getFilteredPointerKeyForLocal(node, valueNumber, filter); + } + + public PointerKey getPointerKeyForReturnValue(CGNode node){ + return base.getPointerKeyForReturnValue(node); + } + + public PointerKey getPointerKeyForExceptionalReturnValue(CGNode node) { + return base.getPointerKeyForExceptionalReturnValue(node); + } + + public PointerKey getPointerKeyForStaticField(IField f) { + return base.getPointerKeyForStaticField(f); + } + + public PointerKey getPointerKeyForObjectCatalog(InstanceKey I) { + return new ObjectPropertyCatalogKey(I); + } + + private final Map specificStringKeys = new HashMap(); + private final Map specificIndexKeys = new HashMap(); + + public PointerKey getPointerKeyForInstanceField(InstanceKey I, IField f) { + PointerKey fk = base.getPointerKeyForInstanceField(I, f); + if (! specificStringKeys.containsKey(f)) { + specificStringKeys.put(f, new HashSet()); + } + + ((Set)specificStringKeys.get(f)).add(fk); + + return fk; + } + + public PointerKey getPointerKeyForArrayContents(InstanceKey I) { + return base.getPointerKeyForArrayContents(I); + } + + public Iterator getPointerKeysForReflectedFieldRead(InstanceKey I, InstanceKey F) { + List result = new LinkedList(); + + // FIXME: current only constant string are handled + if (F instanceof ConstantKey) { + Object v = ((ConstantKey)F).getValue(); + if (v instanceof String) { + IField f = + I.getConcreteType().getField(Atom.findOrCreateUnicodeAtom((String)v)); + result.add( getPointerKeyForInstanceField(I, f) ); + } + } + + result.add(ReflectedFieldPointerKey.mapped(new ConcreteTypeKey(F.getConcreteType()), I)); + + return result.iterator(); + } + + public Iterator getPointerKeysForReflectedFieldWrite(InstanceKey I, InstanceKey F) { + // FIXME: current only constant string are handled + if (F instanceof ConstantKey) { + Object v = ((ConstantKey)F).getValue(); + if (v instanceof String) { + IField f = + I.getConcreteType().getField(Atom.findOrCreateUnicodeAtom((String)v)); + return new NonNullSingletonIterator(getPointerKeyForInstanceField(I, f)); + } + } + + return new NonNullSingletonIterator(ReflectedFieldPointerKey.mapped(new ConcreteTypeKey(F.getConcreteType()), I)); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/MiscellaneousHacksContextSelector.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/MiscellaneousHacksContextSelector.java new file mode 100644 index 000000000..dbb2b1578 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/MiscellaneousHacksContextSelector.java @@ -0,0 +1,147 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.Context; +import com.ibm.wala.ipa.callgraph.ContextSelector; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.types.*; +import com.ibm.wala.util.Atom; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.warnings.WarningSet; + +public class MiscellaneousHacksContextSelector implements ContextSelector +{ + + private final Set methodsToSpecialize; + + private final ContextSelector specialPolicy; + private final ContextSelector basePolicy; + + public MiscellaneousHacksContextSelector(ContextSelector special, + ContextSelector base, + ClassHierarchy cha, + String[][] descriptors) + { + basePolicy = base; + specialPolicy = special; + methodsToSpecialize = new HashSet(); + for(int i = 0; i < descriptors.length; i++) { + String[] descr = descriptors[i]; + switch (descr.length) { + + // loader name, classname, method name, method descr + case 4: { + MethodReference ref = + MethodReference.findOrCreate( + TypeReference.findOrCreate( + new ClassLoaderReference( + Atom.findOrCreateUnicodeAtom( descr[0] )), + TypeName.string2TypeName( descr[1] ) ), + Atom.findOrCreateUnicodeAtom( descr[2] ), + Descriptor.findOrCreateUTF8( descr[3] )); + + methodsToSpecialize.add( cha.resolveMethod( ref ).getReference() ); + break; + } + + // classname, method name, method descr + case 3: { + MethodReference ref = + MethodReference.findOrCreate( + TypeReference.findOrCreate( + new ClassLoaderReference( + Atom.findOrCreateUnicodeAtom("Application")), + TypeName.string2TypeName( descr[0] ) ), + Atom.findOrCreateUnicodeAtom( descr[1] ), + Descriptor.findOrCreateUTF8( descr[2] )); + + methodsToSpecialize.add( cha.resolveMethod( ref ).getReference() ); + break; + } + + // loader name, classname, meaning all methods of that class + case 2: { + IClass klass = + cha.lookupClass( + TypeReference.findOrCreate( + new ClassLoaderReference( + Atom.findOrCreateUnicodeAtom( descr[0] )), + TypeName.string2TypeName( descr[1] ) ) ); + + for(Iterator M = klass.getDeclaredMethods().iterator(); M.hasNext(); ) { + methodsToSpecialize.add( ((IMethod)M.next()).getReference() ); + } + + break; + } + + // classname, meaning all methods of that class + case 1: { + IClass klass = + cha.lookupClass( + TypeReference.findOrCreate( + new ClassLoaderReference( + Atom.findOrCreateUnicodeAtom("Application")), + TypeName.string2TypeName( descr[0] ) ) ); + + for(Iterator M = klass.getDeclaredMethods().iterator(); M.hasNext(); ) { + methodsToSpecialize.add( ((IMethod)M.next()).getReference() ); + } + + break; + } + + default: + Assertions.UNREACHABLE(); + } + } + } + + public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) { + if (methodsToSpecialize.contains( callee.getReference() )) + return specialPolicy.getCalleeTarget(caller, site, callee, receiver); + else + return basePolicy.getCalleeTarget(caller, site, callee, receiver); + } + + /* (non-Javadoc) + * @see com.ibm.wala.ipa.callgraph.ContextSelector#contextIsIrrelevant(com.ibm.wala.ipa.callgraph.CGNode, com.ibm.wala.classLoader.CallSiteReference) + */ + public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) { + return basePolicy.contextIsIrrelevant(node,site); + } + + public int getBoundOnNumberOfTargets(CGNode caller, CallSiteReference reference, IMethod targetMethod) { + return -1; + } + + public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) { + return true; + } + + public void setWarnings(WarningSet newWarnings) { + // no-op, not bound to warnings + } + + public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) { + return false; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ObjectPropertyCatalogKey.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ObjectPropertyCatalogKey.java new file mode 100644 index 000000000..96f0d7ad5 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ObjectPropertyCatalogKey.java @@ -0,0 +1,39 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import com.ibm.wala.ipa.callgraph.propagation.AbstractPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; + +public class ObjectPropertyCatalogKey extends AbstractPointerKey { + private final InstanceKey object; + + public String getName() { + return "catalog of "+object.toString(); + } + + public ObjectPropertyCatalogKey(InstanceKey object) { + this.object = object; + } + + public boolean equals(Object x) { + return (x instanceof ObjectPropertyCatalogKey) && + ((ObjectPropertyCatalogKey)x).object.equals(object); + } + + public int hashCode() { + return object.hashCode(); + } + + public String toString() { + return "[" + getName() + "]"; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ReflectedFieldPointerKey.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ReflectedFieldPointerKey.java new file mode 100644 index 000000000..9c156eeee --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ReflectedFieldPointerKey.java @@ -0,0 +1,69 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import com.ibm.wala.ipa.callgraph.propagation.AbstractFieldPointerKey; +import com.ibm.wala.ipa.callgraph.propagation.InstanceKey; + +public abstract class ReflectedFieldPointerKey extends AbstractFieldPointerKey { + + ReflectedFieldPointerKey(InstanceKey container) { + super(container); + } + + public abstract Object getFieldIdentifier(); + + private static final Object arrayStateKey = new Object() { + public String toString() { return "ArrayStateKey"; } + }; + + public boolean equals(Object obj) { + if (obj instanceof ReflectedFieldPointerKey) { + ReflectedFieldPointerKey other = (ReflectedFieldPointerKey) obj; + return + getFieldIdentifier().equals(other.getFieldIdentifier()) && + getInstanceKey().equals(other.getInstanceKey()); + } else { + return false; + } + } + + public int hashCode() { + return getFieldIdentifier().hashCode(); + } + + public String toString() { return "field:" + getFieldIdentifier(); } + + public static ReflectedFieldPointerKey literal(final String lit, InstanceKey instance) { + return new ReflectedFieldPointerKey(instance) { + public Object getFieldIdentifier() { + return lit; + } + }; + } + + public static ReflectedFieldPointerKey mapped(final InstanceKey mapFrom, InstanceKey instance) { + return new ReflectedFieldPointerKey(instance) { + public Object getFieldIdentifier() { + return mapFrom; + } + }; + } + + public static ReflectedFieldPointerKey index(InstanceKey instance) { + return new ReflectedFieldPointerKey(instance) { + public Object getFieldIdentifier() { + return arrayStateKey; + } + }; + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScopeMappingInstanceKeys.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScopeMappingInstanceKeys.java new file mode 100644 index 000000000..a6d2b2d99 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScopeMappingInstanceKeys.java @@ -0,0 +1,172 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + + +import com.ibm.wala.cast.ir.translator.*; +import com.ibm.wala.cast.loader.AstMethod.*; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.callgraph.*; +import com.ibm.wala.ipa.callgraph.propagation.*; +import com.ibm.wala.types.*; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.Trace; + +import java.util.*; + +abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory { + + protected abstract LexicalParent[] getParents(InstanceKey base); + + protected abstract boolean needsScopeMappingKey(InstanceKey base); + + private final PropagationCallGraphBuilder builder; + private final InstanceKeyFactory basic; + + public class ScopeMappingInstanceKey implements InstanceKey { + private final InstanceKey base; + private final CGNode creator; + private final ScopeMap map; + + private class ScopeMap extends HashMap { + + private static final long serialVersionUID = 3645910671551712906L; + + private void scan(int level, int toDo, LexicalParent parents[], CGNode node, Set parentNodes) { + if (toDo > 0) { + int restoreIndex = -1; + LexicalParent restoreParent = null; + + if (AstTranslator.DEBUG_LEXICAL) + Trace.println(level + ": searching " + node + " for parents"); + + for(int i = 0; i < parents.length; i++) { + + if (parents[i] == null) continue; + + if (AstTranslator.DEBUG_LEXICAL) + Trace.println(level + ": searching " + parents[i]); + + if (node.getMethod() == parents[i].getMethod()) { + if (containsKey(parents[i].getName())) + Assertions._assert(get(parents[i].getName()) == node); + else { + put( parents[i].getName(), node ); + if (AstTranslator.DEBUG_LEXICAL) + Trace.println(level + ": Adding lexical parent " + parents[i].getName() + " for " + base + " at " + creator + "(toDo is now " + toDo +")"); + } + + toDo--; + restoreIndex = i; + restoreParent = parents[i]; + parents[i] = null; + } + } + + CallGraph CG = builder.getCallGraph(); + + Assertions._assert(CG.getPredNodes(node).hasNext() || toDo==0); + + for(Iterator PS = CG.getPredNodes(node); PS.hasNext(); ) { + CGNode pred = (CGNode) PS.next(); + if (pred != creator && !parentNodes.contains(pred)) { + parentNodes.add( pred ); + scan(level+1, toDo, parents, pred, parentNodes); + parentNodes.remove(pred); + } + } + + if (restoreIndex != -1) { + parents[restoreIndex] = restoreParent; + } + } + } + + private ScopeMap() { + LexicalParent[] parents = getParents(base); + + if (AstTranslator.DEBUG_LEXICAL) + Trace.println("starting search for parents at " + creator); + + scan( 0, parents.length, parents, creator, new HashSet(5)); + } + + CGNode getDefiningNode(String definer) { + return (CGNode) get(definer); + } + } + + private ScopeMappingInstanceKey(CGNode creator, InstanceKey base) { + this.creator = creator; + this.base = base; + this.map = new ScopeMap(); + } + + public IClass getConcreteType() { + return base.getConcreteType(); + } + + CGNode getDefiningNode(String definer) { + return map.getDefiningNode( definer ); + } + + public int hashCode() { + return base.hashCode()*creator.hashCode(); + } + + public boolean equals(Object o) { + return (o instanceof ScopeMappingInstanceKey) && + ((ScopeMappingInstanceKey)o).base.equals(base) && + ((ScopeMappingInstanceKey)o).creator.equals(creator); + } + + public String toString() { + return "SMIK:"+base+"@"+creator; + } + } + + public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { + InstanceKey base = basic.getInstanceKeyForAllocation(node, allocation); + if (base != null && needsScopeMappingKey(base)) { + return new ScopeMappingInstanceKey(node, base); + } else { + return base; + } + } + + public InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim) { + return basic.getInstanceKeyForMultiNewArray(node, allocation, dim); + } + + public InstanceKey getInstanceKeyForConstant(Object S) { + return basic.getInstanceKeyForConstant(S); + } + + public String getStringConstantForInstanceKey(InstanceKey I) { + return basic.getStringConstantForInstanceKey(I); + } + + public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter instr, TypeReference type) { + return basic.getInstanceKeyForPEI(node, instr, type); + } + + public InstanceKey getInstanceKeyForClassObject(TypeReference type) { + return basic.getInstanceKeyForClassObject(type); + } + + public ScopeMappingInstanceKeys( + PropagationCallGraphBuilder builder, + InstanceKeyFactory basic) + { + this.basic = basic; + this.builder = builder; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScriptEntryPoints.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScriptEntryPoints.java new file mode 100644 index 000000000..3fb113d5d --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScriptEntryPoints.java @@ -0,0 +1,85 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import com.ibm.wala.cast.ipa.callgraph.AstCallGraph.*; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.callgraph.*; +import com.ibm.wala.ipa.callgraph.impl.*; +import com.ibm.wala.ipa.cha.*; +import com.ibm.wala.ssa.*; +import com.ibm.wala.types.*; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.warnings.WarningSet; + +import java.util.*; + +public abstract class ScriptEntryPoints implements Entrypoints { + + private final ClassHierarchy cha; + private final IClass scriptType; + + private class ScriptEntryPoint extends Entrypoint { + ScriptEntryPoint(IMethod scriptCodeBody) { + super( scriptCodeBody ); + } + + public TypeReference[] getParameterTypes(int i) { + Assertions._assert(i == 0); + return + new TypeReference[]{ getMethod().getDeclaringClass().getReference() }; + } + + public int getNumberOfParameters() { + return 1; + } + + public SSAAbstractInvokeInstruction addCall(FakeRootMethod m, + WarningSet warnings) + { + CallSiteReference site = makeSite(0); + + if (site == null) { + return null; + } + + int functionVn = makeArgument(m, 0, warnings); + int paramVns[] = new int[getNumberOfParameters() - 1]; + for (int j = 0; j < paramVns.length; j++) { + paramVns[j] = makeArgument(m, j+1, warnings); + } + + return ((ScriptFakeRoot)m).addDirectCall(functionVn, paramVns, site); + } + } + + public ScriptEntryPoints(ClassHierarchy cha, IClass scriptType) { + this.cha = cha; + this.scriptType = scriptType; + } + + public Iterator iterator() { + Set ES = new HashSet(); + Iterator classes = scriptType.getClassLoader().iterateAllClasses(); + while ( classes.hasNext() ) { + IClass cls = (IClass)classes.next(); + if (cha.isSubclassOf(cls, scriptType)) { + for (Iterator methods = cls.getDeclaredMethods().iterator(); methods.hasNext();) { + ES.add(new ScriptEntryPoint(((IMethod)methods.next()))); + } + } + } + + return ES.iterator(); + } + +} + diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/StandardFunctionTargetSelector.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/StandardFunctionTargetSelector.java new file mode 100644 index 000000000..05c80b066 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/StandardFunctionTargetSelector.java @@ -0,0 +1,49 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + +import com.ibm.wala.cast.types.*; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.callgraph.*; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.types.*; + +public class StandardFunctionTargetSelector implements MethodTargetSelector { + private final ClassHierarchy cha; + private final MethodTargetSelector base; + + public StandardFunctionTargetSelector(ClassHierarchy cha, MethodTargetSelector base) { + this.cha = cha; + this.base = base; + } + + public IMethod getCalleeTarget(CGNode caller, CallSiteReference site, IClass receiver) { + if (receiver != null) { + ClassLoaderReference loader = receiver.getClassLoader().getReference(); + TypeReference functionTypeRef = + TypeReference.findOrCreate(loader, AstTypeReference.functionTypeName); + + if (cha.isSubclassOf(receiver, cha.lookupClass(functionTypeRef))) { + return receiver.getMethod(AstMethodReference.fnSelector); + } + } + + return base.getCalleeTarget(caller, site, receiver); + } + + public boolean mightReturnSyntheticMethod(CGNode caller, CallSiteReference site) { + return true; + } + + public boolean mightReturnSyntheticMethod(MethodReference declaredTarget) { + return true; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/Util.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/Util.java new file mode 100644 index 000000000..9f44c264a --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/Util.java @@ -0,0 +1,68 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ipa.callgraph; + + +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.callgraph.*; +import com.ibm.wala.ipa.callgraph.propagation.*; +import com.ibm.wala.ssa.*; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.Trace; + +import java.io.*; +import java.net.*; +import java.util.*; + +public class Util { + + public static SourceFileModule makeSourceModule(URL script, String dir, String name) { + // DO NOT use File.separator here, since this name is matched against + // URLs. It seems that, in DOS, URL.getFile() does not return a + // \-separated file name, but rather one with /'s. Rather makes one + // wonder why the function is called get_File_ :( + return makeSourceModule(script, dir + "/" + name); + } + + public static SourceFileModule makeSourceModule(URL script, String scriptName) { + String hackedName = + script.getFile().replaceAll("%5c", "/").replaceAll("%20", " "); + + File scriptFile = new File( hackedName ); + + Assertions._assert( hackedName.endsWith( scriptName ), + scriptName + " does not match file " + script.getFile()); + + return new SourceFileModule( scriptFile, scriptName ); + } + + public static void dumpCG(PropagationCallGraphBuilder builder, CallGraph CG) { + Trace.println( CG ); + + for(Iterator x = CG.iterateNodes(); x.hasNext(); ) { + CGNode N = (CGNode) x.next(); + Trace.println("\nIR of node " + N); + IR ir = ((SSAContextInterpreter)CG.getInterpreter(N)).getIR(N, builder.getWarnings()); + if (ir != null) { + Trace.println( ir ); + } else { + Trace.println( "no IR!" ); + } + } + + PointerAnalysis PA = builder.getPointerAnalysis(); + for(Iterator x = PA.getPointerKeys().iterator(); x.hasNext(); ) { + PointerKey n = (PointerKey)x.next(); + Trace.println(n + " --> " + PA.getPointsToSet(n)); + } + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/cfg/AstInducedCFG.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/cfg/AstInducedCFG.java new file mode 100644 index 000000000..20f648bf1 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/cfg/AstInducedCFG.java @@ -0,0 +1,100 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.cfg; + +import com.ibm.wala.cast.ir.ssa.*; +import com.ibm.wala.cfg.*; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.callgraph.*; +import com.ibm.wala.ssa.*; + +public class AstInducedCFG extends InducedCFG { + + public AstInducedCFG(SSAInstruction[] instructions, IMethod method, Context context) { + super(instructions, method, context); + } + + protected class AstPEIVisitor extends PEIVisitor implements AstInstructionVisitor { + + protected AstPEIVisitor(boolean[] r) { + super(r); + } + + public void visitAstLexicalRead(AstLexicalRead inst) { + } + + public void visitAstLexicalWrite(AstLexicalWrite inst) { + } + + public void visitAstGlobalRead(AstGlobalRead instruction) { + } + + public void visitAstGlobalWrite(AstGlobalWrite instruction) { + } + + public void visitNonExceptingThrow(NonExceptingThrowInstruction inst) { + breakBasicBlock(); + } + + public void visitAssert(AstAssertInstruction instruction) { + + } + + public void visitEachElementHasNext(EachElementHasNextInstruction inst) { + + } + + public void visitEachElementGet(EachElementGetInstruction inst) { + + } + } + + protected class AstBranchVisitor extends BranchVisitor implements AstInstructionVisitor { + + protected AstBranchVisitor(boolean[] r) { + super(r); + } + + public void visitAstLexicalRead(AstLexicalRead inst) { + } + + public void visitAstLexicalWrite(AstLexicalWrite inst) { + } + + public void visitAstGlobalRead(AstGlobalRead instruction) { + } + + public void visitAstGlobalWrite(AstGlobalWrite instruction) { + } + + public void visitNonExceptingThrow(NonExceptingThrowInstruction inst) { + } + + public void visitAssert(AstAssertInstruction instruction) { + } + + public void visitEachElementHasNext(EachElementHasNextInstruction inst) { + } + + public void visitEachElementGet(EachElementGetInstruction inst) { + } + + } + + protected BranchVisitor makeBranchVisitor(boolean[] r) { + return new AstBranchVisitor(r); + } + + protected PEIVisitor makePEIVisitor(boolean[] r) { + return new AstPEIVisitor(r); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/cfg/DelegatingCFG.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/cfg/DelegatingCFG.java new file mode 100644 index 000000000..75fa8c2c8 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/cfg/DelegatingCFG.java @@ -0,0 +1,73 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.cfg; + +import com.ibm.wala.cfg.*; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.shrikeBT.IInstruction; +import com.ibm.wala.util.graph.*; +import com.ibm.wala.util.intset.BitVector; + +import java.util.*; + +public class DelegatingCFG extends AbstractNumberedGraph + implements ControlFlowGraph +{ + + protected final ControlFlowGraph parent; + + public DelegatingCFG(ControlFlowGraph parent) { + this.parent = parent; + } + + protected NodeManager getNodeManager() { + return parent; + } + + protected EdgeManager getEdgeManager() { + return parent; + } + + public IBasicBlock entry() { return parent.entry(); } + + public IBasicBlock exit() { return parent.exit(); } + + public BitVector getCatchBlocks() { return parent.getCatchBlocks(); } + + public IBasicBlock getBlockForInstruction(int index) { + return parent.getBlockForInstruction( index ); + } + + public IInstruction[] getInstructions() { return parent.getInstructions(); } + + public int getProgramCounter(int index) { + return parent.getProgramCounter( index ); + } + + public IMethod getMethod() { return parent.getMethod(); } + + public Collection getExceptionalSuccessors(IBasicBlock b) { + return parent.getExceptionalSuccessors( b ); + } + + public Collection getNormalSuccessors(IBasicBlock b) { + return parent.getNormalSuccessors( b ); + } + + public Collection getExceptionalPredecessors(IBasicBlock b) { + return parent.getExceptionalPredecessors( b ); + } + + public Collection getNormalPredecessors(IBasicBlock b) { + return parent.getNormalPredecessors( b ); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/cfg/PrunedCFG.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/cfg/PrunedCFG.java new file mode 100644 index 000000000..86626937f --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/cfg/PrunedCFG.java @@ -0,0 +1,319 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.cfg; + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Set; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.cfg.IBasicBlock; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.shrikeBT.IInstruction; +import com.ibm.wala.util.CompoundIterator; +import com.ibm.wala.util.collections.Filter; +import com.ibm.wala.util.collections.FilterIterator; +import com.ibm.wala.util.collections.Iterator2Collection; +import com.ibm.wala.util.graph.AbstractNumberedGraph; +import com.ibm.wala.util.graph.EdgeManager; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.NodeManager; +import com.ibm.wala.util.graph.NumberedEdgeManager; +import com.ibm.wala.util.graph.NumberedNodeManager; +import com.ibm.wala.util.graph.impl.GraphInverter; +import com.ibm.wala.util.graph.traverse.DFS; +import com.ibm.wala.util.intset.BitVector; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.IntSetUtil; +import com.ibm.wala.util.intset.MutableIntSet; + +public class PrunedCFG extends AbstractNumberedGraph implements ControlFlowGraph { + + public interface EdgeFilter { + + boolean hasNormalEdge(IBasicBlock src, IBasicBlock dst); + + boolean hasExceptionalEdge(IBasicBlock src, IBasicBlock dst); + + } + + private static class FilteredCFGEdges implements NumberedEdgeManager { + private final ControlFlowGraph cfg; + + private final NumberedNodeManager currentCFGNodes; + + private final EdgeFilter filter; + + FilteredCFGEdges(ControlFlowGraph cfg, NumberedNodeManager currentCFGNodes, EdgeFilter filter) { + this.cfg = cfg; + this.filter = filter; + this.currentCFGNodes = currentCFGNodes; + } + + public Iterator getExceptionalSuccessors(final IBasicBlock N) { + return new FilterIterator(cfg.getExceptionalSuccessors(N).iterator(), new Filter() { + public boolean accepts(Object o) { + return currentCFGNodes.containsNode(o) && filter.hasExceptionalEdge((IBasicBlock) N, (IBasicBlock) o); + } + }); + } + + public Iterator getNormalSuccessors(final IBasicBlock N) { + return new FilterIterator(cfg.getNormalSuccessors(N).iterator(), new Filter() { + public boolean accepts(Object o) { + return currentCFGNodes.containsNode(o) && filter.hasNormalEdge((IBasicBlock) N, (IBasicBlock) o); + } + }); + } + + public Iterator getExceptionalPredecessors(final IBasicBlock N) { + return new FilterIterator(cfg.getExceptionalPredecessors(N).iterator(), new Filter() { + public boolean accepts(Object o) { + return currentCFGNodes.containsNode(o) && filter.hasExceptionalEdge((IBasicBlock) o, (IBasicBlock) N); + } + }); + } + + public Iterator getNormalPredecessors(final IBasicBlock N) { + return new FilterIterator(cfg.getNormalPredecessors(N).iterator(), new Filter() { + public boolean accepts(Object o) { + return currentCFGNodes.containsNode(o) && filter.hasNormalEdge((IBasicBlock) o, (IBasicBlock) N); + } + }); + } + + public Iterator getSuccNodes(Object N) { + return new CompoundIterator(getNormalSuccessors((IBasicBlock) N), getExceptionalSuccessors((IBasicBlock) N)); + } + + public int getSuccNodeCount(Object N) { + return new Iterator2Collection(getSuccNodes(N)).size(); + } + + public IntSet getSuccNodeNumbers(Object N) { + MutableIntSet bits = IntSetUtil.make(); + for (Iterator EE = getSuccNodes(N); EE.hasNext();) { + bits.add(((IBasicBlock) EE.next()).getNumber()); + } + + return bits; + } + + public Iterator getPredNodes(Object N) { + return new CompoundIterator(getNormalPredecessors((IBasicBlock) N), getExceptionalPredecessors((IBasicBlock) N)); + } + + public int getPredNodeCount(Object N) { + return new Iterator2Collection(getPredNodes(N)).size(); + } + + public IntSet getPredNodeNumbers(Object N) { + MutableIntSet bits = IntSetUtil.make(); + for (Iterator EE = getPredNodes(N); EE.hasNext();) { + bits.add(((IBasicBlock) EE.next()).getNumber()); + } + + return bits; + } + + public boolean hasEdge(Object src, Object dst) { + for (Iterator EE = getSuccNodes(src); EE.hasNext();) { + if (EE.next().equals(dst)) { + return true; + } + } + + return false; + } + + public void addEdge(Object src, Object dst) { + throw new UnsupportedOperationException(); + } + + public void removeEdge(Object src, Object dst) { + throw new UnsupportedOperationException(); + } + + public void removeAllIncidentEdges(Object node) { + throw new UnsupportedOperationException(); + } + + public void removeIncomingEdges(Object node) { + throw new UnsupportedOperationException(); + } + + public void removeOutgoingEdges(Object node) { + throw new UnsupportedOperationException(); + } + } + + private static class FilteredNodes implements NumberedNodeManager { + private final NumberedNodeManager nodes; + + private final Set subset; + + FilteredNodes(NumberedNodeManager nodes, Set subset) { + this.nodes = nodes; + this.subset = subset; + } + + public int getNumber(Object N) { + if (subset.contains(N)) + return nodes.getNumber(N); + else + return -1; + } + + public Object getNode(int number) { + Object N = nodes.getNode(number); + if (subset.contains(N)) + return N; + else + throw new NoSuchElementException(); + } + + public int getMaxNumber() { + int max = -1; + for (Iterator NS = nodes.iterateNodes(); NS.hasNext();) { + Object N = NS.next(); + if (subset.contains(N) && getNumber(N) > max) { + max = getNumber(N); + } + } + + return max; + } + + private Iterator filterNodes(Iterator nodeIterator) { + return new FilterIterator(nodeIterator, new Filter() { + public boolean accepts(Object o) { + return subset.contains(o); + } + }); + } + + public Iterator iterateNodes(IntSet s) { + return filterNodes(nodes.iterateNodes(s)); + } + + public Iterator iterateNodes() { + return filterNodes(nodes.iterateNodes()); + } + + public int getNumberOfNodes() { + return subset.size(); + } + + public void addNode(Object n) { + throw new UnsupportedOperationException(); + } + + public void removeNode(Object n) { + throw new UnsupportedOperationException(); + } + + public boolean containsNode(Object N) { + return subset.contains(N); + } + } + + private final ControlFlowGraph cfg; + + private final FilteredNodes nodes; + + private final FilteredCFGEdges edges; + + public PrunedCFG(final ControlFlowGraph cfg, final EdgeFilter filter) { + this.cfg = cfg; + Graph temp = new AbstractNumberedGraph() { + private final EdgeManager edges = new FilteredCFGEdges(cfg, cfg, filter); + + protected NodeManager getNodeManager() { + return cfg; + } + + protected EdgeManager getEdgeManager() { + return edges; + } + }; + + Set reachable = DFS.getReachableNodes(temp, Collections.singleton(cfg.entry())); + Set back = DFS.getReachableNodes(GraphInverter.invert(temp), Collections.singleton(cfg.exit())); + reachable.retainAll(back); + + this.nodes = new FilteredNodes(cfg, reachable); + this.edges = new FilteredCFGEdges(cfg, nodes, filter); + } + + protected NodeManager getNodeManager() { + return nodes; + } + + protected EdgeManager getEdgeManager() { + return edges; + } + + public Collection getExceptionalSuccessors(final IBasicBlock N) { + return new Iterator2Collection(edges.getExceptionalSuccessors(N)); + } + + public Collection getNormalSuccessors(final IBasicBlock N) { + return new Iterator2Collection(edges.getNormalSuccessors(N)); + } + + public Collection getExceptionalPredecessors(final IBasicBlock N) { + return new Iterator2Collection(edges.getExceptionalPredecessors(N)); + } + + public Collection getNormalPredecessors(final IBasicBlock N) { + return new Iterator2Collection(edges.getNormalPredecessors(N)); + } + + public IBasicBlock entry() { + return cfg.entry(); + } + + public IBasicBlock exit() { + return cfg.exit(); + } + + public IBasicBlock getBlockForInstruction(int index) { + return cfg.getBlockForInstruction(index); + } + + public IInstruction[] getInstructions() { + return cfg.getInstructions(); + } + + public int getProgramCounter(int index) { + return cfg.getProgramCounter(index); + } + + public IMethod getMethod() { + return cfg.getMethod(); + } + + public BitVector getCatchBlocks() { + BitVector result = new BitVector(); + BitVector blocks = cfg.getCatchBlocks(); + int i = 0; + while ((i = blocks.nextSetBit(i)) != -1) { + if (nodes.containsNode(getNode(i))) { + result.set(i); + } + } + + return result; + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/cfg/Util.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/cfg/Util.java new file mode 100644 index 000000000..6ea3eb31b --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/cfg/Util.java @@ -0,0 +1,34 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.cfg; + +import com.ibm.wala.cfg.*; +import com.ibm.wala.util.debug.Assertions; + +import java.util.*; + +public class Util { + + public static int whichPred(ControlFlowGraph CFG, + IBasicBlock Y, + IBasicBlock X) + { + int i = 0; + for (Iterator N = CFG.getPredNodes(Y); N.hasNext(); i++) + if (N.next() == X) + return i; + + Assertions.UNREACHABLE(); + return -1; + } + +} + diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractLexicalInvoke.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractLexicalInvoke.java new file mode 100644 index 000000000..bf75d1e88 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractLexicalInvoke.java @@ -0,0 +1,142 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + + +import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access; +import com.ibm.wala.classLoader.CallSiteReference; +import com.ibm.wala.ssa.*; +import com.ibm.wala.util.debug.Assertions; + +public abstract class AbstractLexicalInvoke + extends SSAAbstractInvokeInstruction +{ + + protected Access[] lexicalReads = null; + + protected Access[] lexicalWrites = null; + + protected AbstractLexicalInvoke(int result, + int exception, + CallSiteReference site) + { + super(result, exception, site); + } + + protected AbstractLexicalInvoke(int result, + int exception, + CallSiteReference site, + Access[] lexicalReads, + Access[] lexicalWrites) + { + this(result, exception, site); + this.lexicalReads = lexicalReads; + this.lexicalWrites = lexicalWrites; + } + + public int getNumberOfUses() { + if (lexicalReads == null) + return getNumberOfParameters(); + else + return getNumberOfParameters() + lexicalReads.length; + } + + public int getUse(int j) { + Assertions._assert(j >= getNumberOfParameters()); + Assertions._assert(lexicalReads != null); + Assertions._assert(lexicalReads[j - getNumberOfParameters()] != null); + return lexicalReads[j - getNumberOfParameters()].valueNumber; + } + + public int getNumberOfDefs() { + if (lexicalWrites == null) + return super.getNumberOfDefs(); + else + return super.getNumberOfDefs() + lexicalWrites.length; + } + + public int getDef(int j) { + if (j < super.getNumberOfDefs()) + return super.getDef(j); + else + return lexicalWrites[j-super.getNumberOfDefs()].valueNumber; + } + + private Access[] addAccess(Access[] array, Access access) { + if (array == null) + return new Access[]{ access }; + else { + Access[] result = new Access[ array.length + 1 ]; + System.arraycopy(array, 0, result, 0, array.length); + result[ array.length ] = access; + return result; + } + } + + public boolean isLexicalUse(int use) { + return use >= super.getNumberOfUses(); + } + + public void addLexicalUse(Access use) { + lexicalReads = addAccess(lexicalReads, use); + } + + public Access getLexicalUse(int i) { + return lexicalReads[i-getNumberOfParameters()]; + } + + public boolean isLexicalDef(int def) { + return def >= super.getNumberOfDefs(); + } + + public void addLexicalDef(Access def) { + lexicalWrites = addAccess(lexicalWrites, def); + } + + public Access getLexicalDef(int i) { + return lexicalWrites[i-super.getNumberOfDefs()]; + } + + public int hashCode() { + return site.hashCode() * 7529; + } + + public boolean equals(Object obj) { + if (obj != null && getClass().equals(obj.getClass())) { + SSAAbstractInvokeInstruction other = (SSAAbstractInvokeInstruction)obj; + return site.equals(other.getCallSite()); + } else { + return false; + } + } + + public String toString(SymbolTable symbolTable, ValueDecorator d) { + StringBuffer s = new StringBuffer(super.toString(symbolTable, d)); + + if (lexicalReads != null) { + s.append(" (reads:"); + for(int i = 0; i < lexicalReads.length; i++) { + s.append(" ").append(lexicalReads[i].variableName).append(":").append( getValueString(symbolTable, d, lexicalReads[i].valueNumber) ); + } + s.append(")"); + } + + if (lexicalWrites != null) { + s.append(" (writes:"); + for(int i = 0; i < lexicalWrites.length; i++) { + s.append(" ").append(lexicalWrites[i].variableName).append(":").append( getValueString(symbolTable, d, lexicalWrites[i].valueNumber) ); + } + s.append(")"); + } + + return s.toString(); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractReflectiveGet.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractReflectiveGet.java new file mode 100644 index 000000000..3cee43212 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractReflectiveGet.java @@ -0,0 +1,56 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import com.ibm.wala.ssa.*; +import com.ibm.wala.util.debug.Assertions; + +public abstract class AbstractReflectiveGet extends ReflectiveMemberAccess { + private final int result; + + public AbstractReflectiveGet(int result, int objectRef, int memberRef) { + super(objectRef, memberRef); + this.result = result; + } + + public String toString(SymbolTable symbolTable, ValueDecorator d) { + return getValueString(symbolTable, d, result) + + " = " + + super.toString(symbolTable, d); + } + + /** + * @see com.ibm.wala.ssa.Instruction#getDef() + */ + public boolean hasDef() { + return true; + } + + public int getDef() { + return result; + } + + public int getDef(int i) { + return result; + } + + /** + * @see com.ibm.wala.ssa.Instruction#getNumberOfUses() + */ + public int getNumberOfUses() { + return 2; + } + + public int getNumberOfDefs() { + return 1; + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractReflectivePut.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractReflectivePut.java new file mode 100644 index 000000000..d0b6c9368 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractReflectivePut.java @@ -0,0 +1,56 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + + +import com.ibm.wala.ssa.*; +import com.ibm.wala.util.debug.Assertions; + +public abstract class AbstractReflectivePut extends ReflectiveMemberAccess { + private final int value; + + public AbstractReflectivePut(int objectRef, int memberRef, int value) { + super(objectRef, memberRef); + this.value = value; + } + + public String toString(SymbolTable symbolTable, ValueDecorator d) { + return super.toString(symbolTable, d) + + " = " + + getValueString(symbolTable, d, value); + } + + /** + * @see com.ibm.wala.ssa.Instruction#getDef() + */ + public int getDef() { + return -1; + } + + /** + * @see com.ibm.wala.ssa.Instruction#getNumberOfUses() + */ + public int getNumberOfUses() { + return 3; + } + + public int getValue() { + return getUse(2); + } + + public int getUse(int index) { + if (index == 2) + return value; + else + return super.getUse(index); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractSSAConversion.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractSSAConversion.java new file mode 100644 index 000000000..d2d119e30 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AbstractSSAConversion.java @@ -0,0 +1,399 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import com.ibm.wala.cast.loader.*; +import com.ibm.wala.cfg.*; +import com.ibm.wala.ssa.*; +import com.ibm.wala.ssa.SSAOptions.*; +import com.ibm.wala.util.collections.IntStack; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.DominanceFrontiers; +import com.ibm.wala.util.graph.Graph; + +import java.util.*; + + +/** + * Abstract core of traditional SSA conversion (Cytron et al.). + * + * This implementation is abstract in the sense that it is designed + * to work over the instrutions and CFG of a Domo IR, but it is + * abstract with respect to several integral portions of the + * traditional algorithm: + *
    + *
  • The notion of uses and defs of a given instruction. + *
  • Assignments ( := ) that are be copy-propagated away + *
  • Which values are constants---i.e. have no definition. + *
  • Any value numbers to be skipped during SSA construction + *
  • Special initialization and exit block processing. + *
+ * + * @author Julian dolby (dolby@us.ibm.com) + * + */ +public abstract class AbstractSSAConversion { + + protected abstract int getNumberOfDefs(SSAInstruction inst); + + protected abstract int getDef(SSAInstruction inst, int index); + + protected abstract int getNumberOfUses(SSAInstruction inst); + + protected abstract int getUse(SSAInstruction inst, int index); + + + protected abstract boolean isAssignInstruction(SSAInstruction inst); + + + protected abstract int getMaxValueNumber(); + + protected abstract boolean isLive(SSACFG.BasicBlock Y, int V); + + protected abstract boolean skip(int vn); + + protected abstract boolean isConstant(int valueNumber); + + + protected abstract int getNextNewValueNumber(); + + + protected abstract void initializeVariables(); + + protected abstract void repairExit(); + + + protected abstract void placeNewPhiAt(int value, SSACFG.BasicBlock Y); + + protected abstract SSAPhiInstruction getPhi(SSACFG.BasicBlock B, int index); + + protected abstract void setPhi(SSACFG.BasicBlock B, int index, SSAPhiInstruction inst); + + protected abstract SSAPhiInstruction repairPhiDefs(SSAPhiInstruction phi, int[] newDefs); + + protected abstract void repairPhiUse(SSACFG.BasicBlock BB, int phiIndex, int rvalIndex, int newRval); + + + protected abstract void repairInstructionUses(SSAInstruction inst, int index, int[] newUses); + + protected abstract void repairInstructionDefs(SSAInstruction inst, int index, int[] newDefs, int[] newUses); + + + protected abstract void pushAssignment(SSAInstruction inst, int index, int newRhs); + + protected abstract void popAssignment(SSAInstruction inst, int index); + + + protected final SSACFG CFG; + protected final DominanceFrontiers DF; + private final Graph dominatorTree; + protected final int[] phiCounts; + protected final SSAInstruction[] instructions; + private final int flags[]; + protected final SymbolTable symbolTable; + protected final DefaultValues defaultValues; + + protected IntStack S[]; + protected int C[]; + protected int valueMap[]; + private Set[] assignmentMap; + + protected AbstractSSAConversion(IR ir, SSAOptions options) { + this.CFG = ir.getControlFlowGraph(); + this.DF = new DominanceFrontiers(ir.getControlFlowGraph(), ir.getControlFlowGraph().entry()); + this.dominatorTree = DF.dominatorTree(); + this.flags = new int[2 * ir.getControlFlowGraph().getNumberOfNodes()]; + this.instructions = ir.getInstructions(); + this.phiCounts = new int[CFG.getNumberOfNodes()]; + this.symbolTable = ir.getSymbolTable(); + this.defaultValues = options.getDefaultValues(); + } + + + // + // top-level control + // + protected void perform() { + init(); + placePhiNodes(); + renameVariables(); + } + + + // + // initialization + // + protected void init() { + this.S = new IntStack[getMaxValueNumber() + 1]; + this.C = new int[getMaxValueNumber() + 1]; + this.valueMap = new int[getMaxValueNumber() + 1]; + makeAssignmentMap(); + } + + private void makeAssignmentMap() { + this.assignmentMap = new Set[getMaxValueNumber() + 1]; + for (Iterator BBs = CFG.iterateNodes(); BBs.hasNext();) { + SSACFG.BasicBlock BB = (SSACFG.BasicBlock) BBs.next(); + if (BB.getFirstInstructionIndex() >= 0) { + for(Iterator IS = BB.iterateAllInstructions(); IS.hasNext(); ) { + SSAInstruction inst = (SSAInstruction)IS.next(); + if (inst != null) { + for (int j = 0; j < getNumberOfDefs(inst); j++) { + addDefiningBlock(assignmentMap, BB, getDef(inst, j)); + } + } + } + } + } + } + + private void addDefiningBlock(Set[] A, SSACFG.BasicBlock BB, int i) { + if (! skip(i)) { + if (A[i] == null) { + A[i] = new LinkedHashSet(2); + } + A[i].add(BB); + } + } + + // + // place phi nodes phase of traditional algorithm + // + protected void placePhiNodes() { + int IterCount = 0; + + for (Iterator Xs = CFG.iterateNodes(); Xs.hasNext();) { + SSACFG.BasicBlock X = (SSACFG.BasicBlock) Xs.next(); + setHasAlready(X, 0); + setWork(X, 0); + } + + Set W = new LinkedHashSet(); + for (int V = 0; V < assignmentMap.length; V++) { + + // some things (e.g. constants) have no defs at all + if (assignmentMap[V] == null) + continue; + + // ignore values as requested + if (skip(V)) + continue; + + IterCount++; + + for (Iterator XS = assignmentMap[V].iterator(); XS.hasNext();) { + SSACFG.BasicBlock X = (SSACFG.BasicBlock) XS.next(); + setWork(X, IterCount); + W.add(X); + } + + while (!W.isEmpty()) { + SSACFG.BasicBlock X = (SSACFG.BasicBlock) W.iterator().next(); + W.remove(X); + for (Iterator YS = DF.getDominanceFrontier(X); YS.hasNext();) { + SSACFG.BasicBlock Y = (SSACFG.BasicBlock) YS.next(); + if (getHasAlready(Y) < IterCount) { + if (isLive(Y, V)) { + placeNewPhiAt(V, Y); + phiCounts[Y.getGraphNodeId()]++; + } + setHasAlready(Y, IterCount); + if (getWork(Y) < IterCount) { + setWork(Y, IterCount); + W.add(Y); + } + } + } + } + } + } + + private int getWork(SSACFG.BasicBlock BB) { + return flags[BB.getGraphNodeId() * 2 + 1]; + } + + private void setWork(SSACFG.BasicBlock BB, int v) { + flags[BB.getGraphNodeId() * 2 + 1] = v; + } + + private int getHasAlready(SSACFG.BasicBlock BB) { + return flags[BB.getGraphNodeId() * 2]; + } + + private void setHasAlready(SSACFG.BasicBlock BB, int v) { + flags[BB.getGraphNodeId() * 2] = v; + } + + + // + // rename variables phase of traditional algorithm + // + private void renameVariables() { + for (int V = 1; V <= getMaxValueNumber(); V++) { + if (! skip(V)) { + C[V] = 0; + S[V] = new IntStack(); + } + } + + initializeVariables(); + + SEARCH((SSACFG.BasicBlock) CFG.entry()); + } + + private void SEARCH(SSACFG.BasicBlock X) { + int id = X.getGraphNodeId(); + int Xf = X.getFirstInstructionIndex(); + + // first loop + for (int i = 0; i < phiCounts[id]; i++) { + SSAPhiInstruction phi = getPhi(X, i); + if (! skipRepair(phi, -1)) { + setPhi(X, i, repairPhiDefs(phi, makeNewDefs(phi))); + } + } + for (int i = Xf; i <= X.getLastInstructionIndex(); i++) { + SSAInstruction inst = instructions[i]; + if (isAssignInstruction(inst)) { + int lhs = getDef(inst, 0); + int rhs = getUse(inst, 0); + int newRhs = skip(rhs)? rhs: top(rhs); + S[lhs].push( newRhs ); + + pushAssignment(inst, i, newRhs); + + } else { + if (! skipRepair(inst, i)) { + int[] newUses = makeNewUses(inst); + repairInstructionUses(inst, i, newUses); + int[] newDefs = makeNewDefs(inst); + repairInstructionDefs(inst, i, newDefs, newUses); + } + } + } + + if (X.isExitBlock()) { + repairExit(); + } + + for (Iterator YS = CFG.getSuccNodes(X); YS.hasNext();) { + SSACFG.BasicBlock Y = (SSACFG.BasicBlock) YS.next(); + int Y_id = Y.getGraphNodeId(); + int j = com.ibm.wala.cast.ir.cfg.Util.whichPred(CFG, Y, X); + for (int i = 0; i < phiCounts[Y_id]; i++) { + SSAPhiInstruction phi = getPhi(Y, i); + int oldUse = getUse(phi, j); + int newUse = skip(oldUse) ? oldUse: top(oldUse); + repairPhiUse(Y, i, j, newUse); + } + } + + for (Iterator YS = dominatorTree.getSuccNodes(X); YS.hasNext();) { + SEARCH((SSACFG.BasicBlock) YS.next()); + } + + for (int i = 0; i < phiCounts[id]; i++) { + SSAInstruction A = getPhi(X, i); + for (int j = 0; j < getNumberOfDefs(A); j++) { + if (! skip(getDef(A, j))) { + S[valueMap[getDef(A, j)]].pop(); + } + } + } + for (int i = Xf; i <= X.getLastInstructionIndex(); i++) { + SSAInstruction A = instructions[i]; + if (isAssignInstruction(A)) { + S[ getDef(A, 0) ].pop(); + popAssignment(A, i); + } else if (A != null) { + for (int j = 0; j < getNumberOfDefs(A); j++) { + if (! skip(getDef(A, j))) { + S[valueMap[getDef(A, j)]].pop(); + } + } + } + } + } + + private int[] makeNewUses(SSAInstruction inst) { + int[] newUses = new int[getNumberOfUses(inst)]; + for (int j = 0; j < getNumberOfUses(inst); j++) { + newUses[j] = + skip(getUse(inst, j))? getUse(inst, j): top(getUse(inst, j)); + } + + return newUses; + } + + private int[] makeNewDefs(SSAInstruction inst) { + int[] newDefs = new int[getNumberOfDefs(inst)]; + + for (int j = 0; j < getNumberOfDefs(inst); j++) { + if (skip(getDef(inst, j))) { + newDefs[j] = getDef(inst, j); + } else { + int ii = getNextNewValueNumber(); + + if (valueMap.length <= ii) { + int[] nvm = new int[valueMap.length * 2 + ii + 1]; + System.arraycopy(valueMap, 0, nvm, 0, valueMap.length); + valueMap = nvm; + } + + valueMap[ii] = getDef(inst, j); + S[getDef(inst, j)].push(ii); + newDefs[j] = ii; + } + } + + return newDefs; + } + + protected boolean skipRepair(SSAInstruction inst, int index) { + if (inst == null) + return true; + for(int i = 0; i < getNumberOfDefs(inst); i++) + if (! skip(getDef(inst, i))) return false; + for(int i = 0; i < getNumberOfUses(inst); i++) + if (! skip(getUse(inst, i))) return false; + return true; + } + + protected void fail(int v) { + Assertions._assert( + isConstant(v) || !S[v].isEmpty(), + "bad stack for " + v + " while SSA converting"); + } + + protected boolean hasDefaultValue(int valueNumber) { + return + (defaultValues != null) + && + (defaultValues.getDefaultValue(symbolTable, valueNumber) != -1); + } + + protected int getDefaultValue(int valueNumber) { + return defaultValues.getDefaultValue(symbolTable, valueNumber); + } + + protected int top(int v) { + if (! (isConstant(v) || !S[v].isEmpty())) { + if (hasDefaultValue(v)) { + return getDefaultValue(v); + } else { + fail(v); + } + } + + return (isConstant(v)) ? v : S[v].peek(); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AssignInstruction.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AssignInstruction.java new file mode 100644 index 000000000..ca305f574 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AssignInstruction.java @@ -0,0 +1,69 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + + +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAUnaryOpInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.ssa.ValueDecorator; +import com.ibm.wala.util.debug.Assertions; + +/** + * @author Julian Dolby + * + * A simple assignment statement. Only appears in the IR before SSA conversion + * + */ +public class AssignInstruction extends SSAUnaryOpInstruction { + + /** + * create the assignment v_result := v_val + * @param result + * @param val + */ + public AssignInstruction(int result, int val) { + super(null, result, val); + if (Assertions.verifyAssertions) { + Assertions._assert(result != val); + Assertions._assert(result != -1); + Assertions._assert(val != -1); + } + } + + /* (non-Javadoc) + * @see com.ibm.wala.ssa.SSAInstruction#copyForSSA(int[], int[]) + */ + public SSAInstruction copyForSSA(int[] defs, int[] uses) { + return new AssignInstruction(defs == null ? getDef(0) : defs[0], uses == null ? getUse(0) : uses[0]); + } + + /* (non-Javadoc) + * @see com.ibm.wala.ssa.SSAInstruction#toString(com.ibm.wala.ssa.SymbolTable, com.ibm.wala.ssa.ValueDecorator) + */ + public String toString(SymbolTable symbolTable, ValueDecorator d) { + return getValueString(symbolTable, d, result) + " := " + getValueString(symbolTable, d, val); + } + + /* (non-Javadoc) + * @see com.ibm.wala.ssa.SSAInstruction#visit(com.ibm.wala.ssa.SSAInstruction.Visitor) + */ + public void visit(IVisitor v) { + ((AstPreInstructionVisitor) v).visitAssign(this); + } + + /** + * @return + */ + public int getVal() { + return getUse(0); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstAbstractInstructionVisitor.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstAbstractInstructionVisitor.java new file mode 100644 index 000000000..09175cfb8 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstAbstractInstructionVisitor.java @@ -0,0 +1,53 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import com.ibm.wala.ssa.SSAInstruction; + +public abstract class AstAbstractInstructionVisitor + extends SSAInstruction.Visitor + implements AstInstructionVisitor +{ + + public void visitAstLexicalRead(AstLexicalRead instruction) { + + } + + public void visitAstLexicalWrite(AstLexicalWrite instruction) { + + } + + public void visitAstGlobalRead(AstGlobalRead instruction) { + + } + + public void visitAstGlobalWrite(AstGlobalWrite instruction) { + + } + + public void visitNonExceptingThrow(NonExceptingThrowInstruction inst) { + + } + + public void visitAssert(AstAssertInstruction instruction) { + + } + + public void visitEachElementGet(EachElementGetInstruction inst) { + + } + + public void visitEachElementHasNext(EachElementHasNextInstruction inst) { + + } + +} + diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstAssertInstruction.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstAssertInstruction.java new file mode 100644 index 000000000..febc5f7ff --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstAssertInstruction.java @@ -0,0 +1,66 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import java.util.Collection; + +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.ssa.ValueDecorator; +import com.ibm.wala.util.debug.Assertions; + +public class AstAssertInstruction extends SSAInstruction { + private final int value; + private final boolean fromSpecification; + + public AstAssertInstruction(int value, boolean fromSpecification) { + this.value = value; + this.fromSpecification = fromSpecification; + } + + public int getNumberOfUses() { + return 1; + } + + public int getUse(int i) { + Assertions._assert(i == 0); + return value; + } + + public SSAInstruction copyForSSA(int[] defs, int[] uses) { + return new AstAssertInstruction(uses==null? value: uses[0], fromSpecification); + } + + public String toString(SymbolTable symbolTable, ValueDecorator d) { + return "assert " + getValueString(symbolTable, d, value) + + " (fromSpec: " + fromSpecification + ")"; + } + + public void visit(IVisitor v) { + ((AstInstructionVisitor)v).visitAssert(this); + } + + public int hashCode() { + return 2177*value; + } + + public Collection getExceptionTypes() { + return null; + } + + public boolean isFallThrough() { + return true; + } + + public boolean isFromSpecification() { + return fromSpecification; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstConstants.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstConstants.java new file mode 100644 index 000000000..638067862 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstConstants.java @@ -0,0 +1,33 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import com.ibm.wala.shrikeBT.BinaryOpInstruction; +import com.ibm.wala.shrikeBT.UnaryOpInstruction; + +public interface AstConstants { + + public enum BinaryOp implements BinaryOpInstruction.IOperator { + CONCAT, EQ, NE, LT, GE, GT, LE; + + public String toString() { + return super.toString().toLowerCase(); + } + } + + public enum UnaryOp implements UnaryOpInstruction.IOperator { + MINUS; + + public String toString() { + return super.toString().toLowerCase(); + } + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstGlobalRead.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstGlobalRead.java new file mode 100644 index 000000000..5f05f50cc --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstGlobalRead.java @@ -0,0 +1,48 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import java.util.Collection; + +import com.ibm.wala.ssa.*; +import com.ibm.wala.types.*; + +public class AstGlobalRead extends SSAGetInstruction { + + public AstGlobalRead(int lhs, FieldReference global) { + super(lhs, global); + } + + public SSAInstruction copyForSSA(int[] defs, int[] uses) { + return new AstGlobalRead((defs==null)? getDef(): defs[0], getDeclaredField()); + } + + public String toString(SymbolTable symbolTable, ValueDecorator d) { + return getValueString(symbolTable, d, getDef()) + " = global:" + getGlobalName(); + } + + public void visit(IVisitor v) { + if (v instanceof AstInstructionVisitor) + ((AstInstructionVisitor)v).visitAstGlobalRead(this); + } + + public boolean isFallThrough() { + return true; + } + + public Collection getExceptionTypes() { + return null; + } + + public String getGlobalName() { + return getDeclaredField().getName().toString(); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstGlobalWrite.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstGlobalWrite.java new file mode 100644 index 000000000..1d248979c --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstGlobalWrite.java @@ -0,0 +1,48 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import java.util.Collection; + +import com.ibm.wala.ssa.*; +import com.ibm.wala.types.*; + +public class AstGlobalWrite extends SSAPutInstruction { + + public AstGlobalWrite(FieldReference global, int rhs) { + super(rhs, global); + } + + public SSAInstruction copyForSSA(int[] defs, int[] uses) { + return new AstGlobalWrite(getDeclaredField(), (uses==null)? getVal(): uses[0]); + } + + public String toString(SymbolTable symbolTable, ValueDecorator d) { + return "global:" + getGlobalName() + " = " + getValueString(symbolTable, d, getVal()); + } + + public void visit(IVisitor v) { + if (v instanceof AstInstructionVisitor) + ((AstInstructionVisitor)v).visitAstGlobalWrite(this); + } + + public boolean isFallThrough() { + return true; + } + + public Collection getExceptionTypes() { + return null; + } + + public String getGlobalName() { + return getDeclaredField().getName().toString(); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstIRFactory.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstIRFactory.java new file mode 100644 index 000000000..2157688ce --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstIRFactory.java @@ -0,0 +1,162 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + + +import com.ibm.wala.cast.loader.*; +import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; +import com.ibm.wala.cfg.*; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.callgraph.*; +import com.ibm.wala.ipa.cha.*; +import com.ibm.wala.ssa.*; +import com.ibm.wala.ssa.SSACFG.*; +import com.ibm.wala.types.*; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.warnings.*; + +import java.util.*; + +public class AstIRFactory implements IRFactory { + private final boolean keepIR; + private final Map keptIRs; + + AstIRFactory(boolean keepIR) { + this.keepIR = keepIR; + this.keptIRs = (keepIR)? new HashMap(): null; + } + + public ControlFlowGraph makeCFG(final IMethod method, + final Context context, + final ClassHierarchy cha, + final WarningSet warnings) + { + return ((AstMethod)method).getControlFlowGraph(); + } + + public class AstIR extends IR { + private final SSA2LocalMap localMap; + + private void setCatchInstructions(SSACFG ssacfg, AbstractCFG oldcfg) { + for (int i = 0; i < oldcfg.getNumberOfNodes(); i++) + if (oldcfg.isCatchBlock(i)) { + ExceptionHandlerBasicBlock B = + (ExceptionHandlerBasicBlock) ssacfg.getNode(i); + B.setCatchInstruction((SSAGetCaughtExceptionInstruction) + getInstructions()[B.getFirstInstructionIndex()]); + } + } + + private void setupCatchTypes(SSACFG cfg, TypeReference[][] catchTypes) { + for (int i = 0; i < catchTypes.length; i++) { + if (catchTypes[i] != null) { + ExceptionHandlerBasicBlock bb = + (ExceptionHandlerBasicBlock) cfg.getNode(i); + for (int j = 0; j < catchTypes[i].length; j++) { + bb.addCaughtExceptionType(catchTypes[i][j]); + } + } + } + } + + protected SSA2LocalMap getLocalMap() { + return localMap; + } + + protected String instructionPosition(int instructionIndex) { + Position pos = + ((AstMethod)getMethod()).getSourcePosition(instructionIndex); + if (pos == null) { + return ""; + } else { + return pos.toString(); + } + } + + private AstIR(AstMethod method, + SSAInstruction[] instructions, + SymbolTable symbolTable, + SSACFG cfg, + SSAOptions options) + { + super(method, instructions, symbolTable, cfg, options); + + setCatchInstructions(getControlFlowGraph(), method.cfg); + + localMap = SSAConversion.convert(method, this, options); + + setupCatchTypes(getControlFlowGraph(), method.catchTypes); + + setupLocationMap(); + } + } + + public IR makeIR(final IMethod method, + final Context context, + final ClassHierarchy cha, + final SSAOptions options, + final WarningSet warnings) + { + Assertions._assert(method instanceof AstMethod, method.toString()); + if (keepIR) { + if (keptIRs.containsKey(method)) { + return (IR) keptIRs.get(method); + } + } + + AbstractCFG oldCfg = ((AstMethod)method).cfg; + SSAInstruction[] instrs = (SSAInstruction[])oldCfg.getInstructions(); + + IR newIR = + new AstIR((AstMethod)method, + instrs, + ((AstMethod)method).symtab, + new SSACFG(method, oldCfg, instrs, warnings), + options); + + if (keepIR) { + keptIRs.put(method, newIR); + } + + return newIR; + } + + public static IRFactory makeDefaultFactory(final boolean keepAstIRs) { + return new DefaultIRFactory() { + private final AstIRFactory astFactory = new AstIRFactory(keepAstIRs); + + public IR makeIR(IMethod method, + Context context, + ClassHierarchy cha, + SSAOptions options, + WarningSet warnings) + { + if (method instanceof AstMethod) { + return astFactory.makeIR(method, context, cha, options, warnings); + } else { + return super.makeIR(method, context, cha, options, warnings); + } + } + + public ControlFlowGraph makeCFG(IMethod method, + Context context, + ClassHierarchy cha, + WarningSet warnings) + { + if (method instanceof AstMethod) { + return astFactory.makeCFG(method, context, cha, warnings); + } else { + return super.makeCFG(method, context, cha, warnings); + } + } + }; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstInstructionVisitor.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstInstructionVisitor.java new file mode 100644 index 000000000..1f3410e45 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstInstructionVisitor.java @@ -0,0 +1,34 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import com.ibm.wala.ssa.*; + +public interface AstInstructionVisitor extends SSAInstruction.IVisitor { + + public void visitAstLexicalRead(AstLexicalRead instruction); + + public void visitAstLexicalWrite(AstLexicalWrite instruction); + + public void visitAstGlobalRead(AstGlobalRead instruction); + + public void visitAstGlobalWrite(AstGlobalWrite instruction); + + public void visitNonExceptingThrow(NonExceptingThrowInstruction inst); + + public void visitAssert(AstAssertInstruction instruction); + + public void visitEachElementGet(EachElementGetInstruction inst); + + public void visitEachElementHasNext(EachElementHasNextInstruction inst); + +} + diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstLexicalAccess.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstLexicalAccess.java new file mode 100644 index 000000000..bd59e8341 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstLexicalAccess.java @@ -0,0 +1,86 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import java.util.Collection; + +import com.ibm.wala.ssa.SSAInstruction; + +public abstract class AstLexicalAccess extends SSAInstruction { + + public static class Access { + public final String variableName; + public final String variableDefiner; + public final int valueNumber; + + public Access(String name, String definer, int lhsOrRhs) { + variableName = name; + variableDefiner = definer; + valueNumber = lhsOrRhs; + } + + public int hashCode() { + return variableName.hashCode() * valueNumber; + } + + public boolean equals(Object other) { + return (other instanceof Access) && + variableName.equals( ((Access)other).variableName ) && + valueNumber == ((Access)other).valueNumber && + ( variableDefiner == null? + ((Access)other).variableDefiner == null: + variableDefiner.equals(((Access)other).variableDefiner) ); + } + + public String toString() { + return "Access(" + variableName + "@" + variableDefiner + ":" + valueNumber + ")"; + } + } + + private Access[] accesses; + + AstLexicalAccess(Access[] accesses) { + setAccesses( accesses ); + } + + public void setAccesses(Access[] accesses) { + this.accesses = accesses; + } + + public Access[] getAccesses() { + return accesses; + } + + public Access getAccess(int i) { + return accesses[i]; + } + + public int getAccessCount() { + return accesses.length; + } + + public boolean isFallThrough() { + return true; + } + + public Collection getExceptionTypes() { + return null; + } + + public int hashCode() { + int v = 1; + for(int i = 0; i < accesses.length; i++) + v *= accesses[i].variableName.hashCode(); + + return v; + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstLexicalRead.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstLexicalRead.java new file mode 100644 index 000000000..cad576ccd --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstLexicalRead.java @@ -0,0 +1,72 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + + +import com.ibm.wala.ssa.*; +import com.ibm.wala.util.debug.Assertions; + +public class AstLexicalRead extends AstLexicalAccess { + + public AstLexicalRead(Access[] accesses) { + super(accesses); + } + + public AstLexicalRead(Access access) { + this(new Access[]{ access }); + } + + public AstLexicalRead(int lhs, String definer, String globalName) { + this(new Access(globalName, definer, lhs)); + } + + public SSAInstruction copyForSSA(int[] defs, int[] uses) { + if (defs==null) { + return new AstLexicalRead( getAccesses() ); + } else { + Access[] accesses = new Access[ getAccessCount() ]; + for(int i = 0; i < accesses.length; i++) { + Access oldAccess = getAccess(i); + accesses[i] = new Access(oldAccess.variableName, oldAccess.variableDefiner, defs[i]); + } + + return new AstLexicalRead(accesses); + } + } + + public int getNumberOfDefs() { return getAccessCount(); } + + public int getDef(int i) { return getAccess(i).valueNumber; } + + public int getNumberOfUses() { return 0; } + + public int getUse(int i) { throw new UnsupportedOperationException(); } + + public String toString(SymbolTable symbolTable, ValueDecorator d) { + StringBuffer sb = new StringBuffer(); + for(int i = 0; i < getAccessCount(); i++) { + Access A = getAccess(i); + if (i != 0) sb.append(", "); + sb.append(getValueString(symbolTable, d, A.valueNumber)); + sb.append(" = lexical:"); + sb.append(A.variableName); + sb.append("@"); + sb.append(A.variableDefiner); + } + + return sb.toString(); + } + + public void visit(IVisitor v) { + Assertions._assert(v instanceof AstInstructionVisitor); + ((AstInstructionVisitor)v).visitAstLexicalRead(this); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstLexicalWrite.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstLexicalWrite.java new file mode 100644 index 000000000..104e5c2d7 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstLexicalWrite.java @@ -0,0 +1,73 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + + +import com.ibm.wala.ssa.*; +import com.ibm.wala.util.debug.Assertions; + +public class AstLexicalWrite extends AstLexicalAccess { + + public AstLexicalWrite(String definer, String globalName, int rhs) { + this(new Access(globalName, definer, rhs)); + } + + public AstLexicalWrite(Access access) { + this(new Access[]{access}); + } + + public AstLexicalWrite(Access[] accesses) { + super(accesses); + } + + public SSAInstruction copyForSSA(int[] defs, int[] uses) { + if (uses==null) { + return new AstLexicalWrite( getAccesses() ); + } else { + Access[] accesses = new Access[ getAccessCount() ]; + for(int i = 0; i < accesses.length; i++) { + Access oldAccess = getAccess(i); + accesses[i] = new Access(oldAccess.variableName, oldAccess.variableDefiner, uses[i]); + } + + return new AstLexicalWrite(accesses); + } + } + + public int getNumberOfUses() { return getAccessCount(); } + + public int getUse(int i) { return getAccess(i).valueNumber; } + + public int getNumberOfDefs() { return 0; } + + public int getDef(int i) { throw new UnsupportedOperationException(); } + + public String toString(SymbolTable symbolTable, ValueDecorator d) { + StringBuffer sb = new StringBuffer(); + for(int i = 0; i < getAccessCount(); i++) { + Access A = getAccess(i); + if (i != 0) sb.append(", "); + sb.append("lexical:"); + sb.append(A.variableName); + sb.append("@"); + sb.append(A.variableDefiner); + sb.append(" = "); + sb.append(getValueString(symbolTable, d, A.valueNumber)); + } + + return sb.toString(); + } + + public void visit(IVisitor v) { + Assertions._assert(v instanceof AstInstructionVisitor); + ((AstInstructionVisitor)v).visitAstLexicalWrite(this); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstPreInstructionVisitor.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstPreInstructionVisitor.java new file mode 100644 index 000000000..7371480aa --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/AstPreInstructionVisitor.java @@ -0,0 +1,18 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +public interface AstPreInstructionVisitor extends AstInstructionVisitor { + + public void visitAssign(AssignInstruction inst); + +} + diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/EachElementGetInstruction.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/EachElementGetInstruction.java new file mode 100644 index 000000000..40e4d8030 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/EachElementGetInstruction.java @@ -0,0 +1,40 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import com.ibm.wala.ssa.*; + +import java.util.*; + +public class EachElementGetInstruction extends SSAAbstractUnaryInstruction { + + public EachElementGetInstruction(int lValue, int objectRef) { + super(lValue, objectRef); + } + + public SSAInstruction copyForSSA(int[] defs, int[] uses) { + return new EachElementGetInstruction( + (defs==null)? getDef(0): defs[0], + (uses == null)? getUse(0): uses[0]); + } + + public String toString(SymbolTable symbolTable, ValueDecorator d) { + return getValueString(symbolTable, d, getDef(0)) + " = a property name of " + getValueString(symbolTable, d, getUse(0)); + } + + public void visit(IVisitor v) { + ((AstInstructionVisitor) v).visitEachElementGet(this); + } + + public Collection getExceptionTypes() { + return Collections.EMPTY_SET; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/EachElementHasNextInstruction.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/EachElementHasNextInstruction.java new file mode 100644 index 000000000..ffce95e3b --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/EachElementHasNextInstruction.java @@ -0,0 +1,40 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import com.ibm.wala.ssa.*; + +import java.util.*; + +public class EachElementHasNextInstruction extends SSAAbstractUnaryInstruction { + + public EachElementHasNextInstruction(int lValue, int objectRef) { + super(lValue, objectRef); + } + + public SSAInstruction copyForSSA(int[] defs, int[] uses) { + return new EachElementHasNextInstruction( + (defs==null)? getDef(0): defs[0], + (uses == null)? getUse(0): uses[0]); + } + + public String toString(SymbolTable symbolTable, ValueDecorator d) { + return getValueString(symbolTable, d, getDef(0)) + " = has next property: " + getValueString(symbolTable, d, getUse(0)); + } + + public void visit(IVisitor v) { + ((AstInstructionVisitor) v).visitEachElementHasNext(this); + } + + public Collection getExceptionTypes() { + return Collections.EMPTY_SET; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/FixedParametersLexicalInvokeInstruction.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/FixedParametersLexicalInvokeInstruction.java new file mode 100644 index 000000000..0d49c5eef --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/FixedParametersLexicalInvokeInstruction.java @@ -0,0 +1,105 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ssa.*; + +public abstract class FixedParametersLexicalInvokeInstruction + extends AbstractLexicalInvoke +{ + + /** + * The value numbers of the arguments passed to the call. For non-static methods, + * params[0] == this. If params == null, this should be a static method with + * no parameters. + */ + private final int[] params; + + public FixedParametersLexicalInvokeInstruction(int result, int[] params, int exception, CallSiteReference site) { + super(result, exception, site); + this.params = params; + } + + /** + * Constructor InvokeInstruction. This case for void return values + * @param i + * @param params + */ + public FixedParametersLexicalInvokeInstruction(int[] params, int exception, CallSiteReference site) { + this(-1, params, exception, site); + } + + protected FixedParametersLexicalInvokeInstruction(int result, int[] params, int exception, CallSiteReference site, Access[] lexicalReads, Access[] lexicalWrites) { + super(result, exception, site, lexicalReads, lexicalWrites); + this.params = params; + } + + protected abstract SSAInstruction copyInstruction(int result, int[] params, int exception, Access[] lexicalReads, Access[] lexicalWrites); + + public SSAInstruction copyForSSA(int[] defs, int[] uses) { + int newParams[] = params; + Access[] reads = lexicalReads; + + if (uses != null) { + int i = 0; + + newParams = new int[ params.length ]; + for(int j = 0; j < newParams.length; j++) + newParams[j] = uses[i++]; + + if (lexicalReads != null) { + reads = new Access[ lexicalReads.length ]; + for(int j = 0; j < reads.length; j++) + reads[j] = new Access(lexicalReads[j].variableName, lexicalReads[j].variableDefiner, uses[i++]); + } + } + + int newLval = result; + int newExp = exception; + Access[] writes = lexicalWrites; + + if (defs != null) { + int i = 0; + if (result != -1) newLval = defs[i++]; + newExp = defs[i++]; + + if (lexicalWrites != null) { + writes = new Access[ lexicalWrites.length ]; + for(int j = 0; j < writes.length; j++) + writes[j] = new Access(lexicalWrites[j].variableName, lexicalWrites[j].variableDefiner, defs[i++]); + } + } + + return copyInstruction(newLval, newParams, newExp, reads, writes); + } + + public int getNumberOfParameters() { + if (params == null) { + return 0; + } else { + return params.length; + } + } + + /** + * @see com.ibm.wala.ssa.Instruction#getUse(int) + */ + public int getUse(int j) { + if (j < getNumberOfParameters()) + return params[j]; + else { + return super.getUse(j); + } + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/NonExceptingThrowInstruction.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/NonExceptingThrowInstruction.java new file mode 100644 index 000000000..98a28f4c8 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/NonExceptingThrowInstruction.java @@ -0,0 +1,38 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import com.ibm.wala.ssa.*; + +import java.util.*; + +public class NonExceptingThrowInstruction extends SSAAbstractThrowInstruction { + + public NonExceptingThrowInstruction(int exception) { + super( exception); + } + + public SSAInstruction copyForSSA(int[] defs, int[] uses) { + return new NonExceptingThrowInstruction(uses==null? getException(): uses[0]); + } + + /** + * @see com.ibm.wala.ssa.SSAInstruction#visit(Visitor) + */ + public void visit(IVisitor v) { + ((AstInstructionVisitor)v).visitNonExceptingThrow(this); + } + + public Collection getExceptionTypes() { + return Collections.EMPTY_SET; + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/SSAConversion.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/SSAConversion.java new file mode 100644 index 000000000..8d93b14ed --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/SSAConversion.java @@ -0,0 +1,602 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa; + +import com.ibm.wala.cast.ir.ssa.AstIRFactory.AstIR; +import com.ibm.wala.cast.ir.ssa.analysis.LiveAnalysis; +import com.ibm.wala.cast.loader.*; +import com.ibm.wala.cast.loader.AstMethod.*; +import com.ibm.wala.shrikeBT.IInstruction; +import com.ibm.wala.ssa.*; +import com.ibm.wala.ssa.IR.SSA2LocalMap; +import com.ibm.wala.util.collections.IntStack; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.Trace; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.intset.*; + +import java.util.*; + +/** + * @author Julian Dolby + * + * Standard SSA conversion for local value numbers. + */ +public class SSAConversion extends AbstractSSAConversion { + + public static boolean DEBUG = false; + public static boolean DEBUG_UNDO = true; + public static boolean DEBUG_NAMES = true; + public static boolean DUMP = false; + + private final AstIR ir; + + private int nextSSAValue; + + private final DebuggingInformation debugInfo; + + private final LexicalInformation lexicalInfo; + + private final SymbolTable symtab; + + private final LiveAnalysis.Result liveness; + + private SSA2LocalMap computedLocalMap; + + // + // Copy propagation history + // + + private final Map copyPropagationMap; + private final Stack R[]; + + private static class UseRecord { + final int instructionIndex; + final int useNumber; + + private UseRecord(int instructionIndex, int useNumber) { + this.useNumber = useNumber; + this.instructionIndex = instructionIndex; + } + + public int hashCode() { + return useNumber*instructionIndex; + } + + public boolean equals(Object o) { + return (o instanceof UseRecord) && + instructionIndex==((UseRecord)o).instructionIndex && + useNumber==((UseRecord)o).useNumber; + } + } + + private class PhiUseRecord { + final int BBnumber; + final int phiNumber; + final int useNumber; + + private PhiUseRecord(int BBnumber, int phiNumber, int useNumber) { + this.BBnumber = BBnumber; + this.phiNumber = phiNumber; + this.useNumber = useNumber; + } + + public int hashCode() { + return phiNumber*BBnumber*useNumber; + } + + public boolean equals(Object o) { + return (o instanceof PhiUseRecord) && + BBnumber==((PhiUseRecord)o).BBnumber && + phiNumber==((PhiUseRecord)o).phiNumber && + useNumber==((PhiUseRecord)o).useNumber; + } + } + + private class CopyPropagationRecord { + final int lhs; + final int rhs; + final int instructionIndex; + final Set renamedUses = new HashSet(2); + private final Set childRecords = new HashSet(1); + + public int hashCode() { + return instructionIndex; + } + + public boolean equals(Object o) { + return (o instanceof CopyPropagationRecord) && + instructionIndex==((CopyPropagationRecord)o).instructionIndex; + } + + private CopyPropagationRecord(int instructionIndex, int lhs, int rhs) { + if (DEBUG_UNDO) Trace.println("new copy record for instruction #" + instructionIndex + ", rhs value is " + rhs); + this.lhs = lhs; + this.rhs = rhs; + this.instructionIndex = instructionIndex; + } + + private void addChild(CopyPropagationRecord rec) { + if (DEBUG_UNDO) Trace.println("("+rec.instructionIndex+","+rec.rhs+") is a child of ("+instructionIndex+","+rhs+")"); + childRecords.add(rec); + } + + private void addUse(int instructionIndex, int use) { + if (DEBUG_UNDO) Trace.println("propagated use of (" + this.instructionIndex + "," + this.rhs + ") at use #" + use + " of instruction #" + instructionIndex); + UseRecord rec = new UseRecord(instructionIndex, use); + copyPropagationMap.put(rec, this); + renamedUses.add( rec ); + } + + private void addUse(int BB, int phiNumber, int use) { + PhiUseRecord rec = new PhiUseRecord(BB, phiNumber, use); + copyPropagationMap.put(rec, this); + renamedUses.add( rec ); + } + + private SSAInstruction undo(SSAInstruction inst, int use, int val) { + int c = getNumberOfUses(inst); + int[] newUses = new int[ c ]; + for(int i = 0; i < c; i++) { + if (i == use) + newUses[i] = val; + else + newUses[i] = getUse(inst, i); + } + + return inst.copyForSSA(null, newUses); + } + + private void undo(int rhs) { + int lhs = symtab.newSymbol(); + + instructions[ instructionIndex ] = new AssignInstruction(lhs, rhs); + + if (DEBUG_UNDO) Trace.println("recreating assignment at " + instructionIndex + " as " + lhs + " = " + rhs); + + for(Iterator uses = renamedUses.iterator(); uses.hasNext(); ) { + Object x = uses.next(); + if (x instanceof UseRecord) { + UseRecord use = (UseRecord)x; + int idx = use.instructionIndex; + SSAInstruction inst = instructions[ idx ]; + + if (DEBUG_UNDO) Trace.println("Changing use #" + use.useNumber + " of inst #" + idx + " to val " + lhs); + + if (use.useNumber >= 0) { + instructions[idx] = undo(inst, use.useNumber, lhs); + } else { + lexicalInfo.getExposedUses(idx)[-use.useNumber - 1] = lhs; + } + copyPropagationMap.remove( use ); + } else { + PhiUseRecord use = (PhiUseRecord)x; + int bb = use.BBnumber; + int phi = use.phiNumber; + SSACFG.BasicBlock BB = (SSACFG.BasicBlock)CFG.getNode(bb); + BB.addPhiForLocal(phi, (SSAPhiInstruction)undo(BB.getPhiForLocal(phi), use.useNumber, lhs)); + copyPropagationMap.remove( use ); + } + } + + for(Iterator cs = childRecords.iterator(); cs.hasNext(); ) { + ((CopyPropagationRecord)cs.next()).undo( lhs ); + } + } + + public void undo() { + undo( this.rhs ); + copyPropagationMap.remove( new UseRecord(instructionIndex, rhs) ); + } + } + + public static void undoCopyPropagation(AstIR ir, int instruction, int use) { + SSAInformation info = (SSAInformation) ir.getLocalMap(); + info.undoCopyPropagation(instruction, use); + } + + public static void copyUse(AstIR ir, int fromInst, int fromUse, int toInst, int toUse) { + SSAInformation info = (SSAInformation) ir.getLocalMap(); + info.copyUse(fromInst, fromUse, toInst, toUse); + } + + + // + // SSA2LocalMap implementation for SSAConversion + // + private class SSAInformation implements com.ibm.wala.ssa.IR.SSA2LocalMap { + + public String[] getLocalNames(int pc, int vn) { + int v = skip(vn)||vn>=valueMap.length? vn: valueMap[vn]; + String[][] namesData = debugInfo.getSourceNamesForValues(); + if (namesData == null || namesData.length <= v) + return new String[0]; + else + return namesData[v]; + } + + private void undoCopyPropagation(int instructionIndex, int useNumber) { + + if (DEBUG_UNDO) + Trace.println("undoing for use #" + useNumber + " of inst #" + instructionIndex); + + UseRecord use = new UseRecord(instructionIndex, useNumber); + if (copyPropagationMap.containsKey(use)) { + ((CopyPropagationRecord)copyPropagationMap.get(use)).undo(); + } + } + + private void copyUse(int fromInst, int fromUse, int toInst, int toUse) { + UseRecord use = new UseRecord(fromInst, fromUse); + if (copyPropagationMap.containsKey(use)) { + ((CopyPropagationRecord)copyPropagationMap.get(use)).addUse(toInst, toUse); + } + } + + private Map getCopyHistory() { + return copyPropagationMap; + } + } + + private CopyPropagationRecord topR(int v) { + if (R[v] != null && !R[v].isEmpty()) { + CopyPropagationRecord rec = (CopyPropagationRecord)R[v].peek(); + if (top(v) == rec.rhs) { + return rec; + } + } + + return null; + } + + + // + // implementation of AbstractSSAConversion hooks + // + + protected int getNumberOfDefs(SSAInstruction inst) { + return inst.getNumberOfDefs(); + } + + protected int getDef(SSAInstruction inst, int index) { + return inst.getDef(index); + } + + protected int getNumberOfUses(SSAInstruction inst) { + return inst.getNumberOfUses(); + } + + protected int getUse(SSAInstruction inst, int index) { + return inst.getUse(index); + } + + protected boolean isAssignInstruction(SSAInstruction inst) { + return inst instanceof AssignInstruction; + } + + protected int getMaxValueNumber() { + return symtab.getMaxValueNumber(); + } + + protected boolean skip(int vn) { + return false; + } + + protected boolean isLive(SSACFG.BasicBlock Y, int V) { + return (liveness.isLiveEntry(Y, V)); + } + + private void addPhi(SSACFG.BasicBlock BB, SSAPhiInstruction phi) { + BB.addPhiForLocal(phiCounts[BB.getGraphNodeId()], phi); + } + + protected void placeNewPhiAt(int value, SSACFG.BasicBlock Y) { + int[] params = new int[CFG.getPredNodeCount(Y)]; + for (int i = 0; i < params.length; i++) + params[i] = value; + + SSAPhiInstruction phi = new SSAPhiInstruction(value, params); + + if (DEBUG) + Trace.println("Placing " + phi + " at " + Y); + + addPhi(Y, phi); + } + + protected SSAPhiInstruction getPhi(SSACFG.BasicBlock B, int index) { + return B.getPhiForLocal(index); + } + + protected void setPhi(SSACFG.BasicBlock B, int index, SSAPhiInstruction inst) { + B.addPhiForLocal(index, inst); + } + + protected SSAPhiInstruction repairPhiDefs(SSAPhiInstruction phi, int[] newDefs) { + return (SSAPhiInstruction)phi.copyForSSA(newDefs, null); + } + + protected void repairPhiUse(SSACFG.BasicBlock BB, int phiIndex, int rvalIndex, int newRval) { + SSAPhiInstruction phi = getPhi(BB, phiIndex); + + int[] newUses = new int[getNumberOfUses(phi)]; + for (int v = 0; v < newUses.length; v++) { + int oldUse = getUse(phi, v); + int newUse = (v==rvalIndex)? newRval: oldUse; + newUses[v] = newUse; + + if (v==rvalIndex && topR(oldUse) != null) { + topR(oldUse).addUse(BB.getGraphNodeId(), phiIndex, v); + } + } + + phi.setValues(newUses); + } + + protected void pushAssignment(SSAInstruction inst, int index, int newRhs) { + int lhs = getDef(inst, 0); + int rhs = getUse(inst, 0); + + copyNames(rhs, lhs); + + CopyPropagationRecord rec = new CopyPropagationRecord(index, lhs, newRhs); + R[lhs].push( rec ); + if (topR(rhs) != null) { + topR(rhs).addChild( rec ); + } + } + + protected void repairInstructionUses(SSAInstruction inst, int index, int[] newUses){ + for (int j = 0; j < getNumberOfUses(inst); j++) { + if (topR(getUse(inst, j)) != null) { + topR(getUse(inst, j)).addUse(index, j); + } + } + + int[] lexicalUses = lexicalInfo.getExposedUses(index); + if (lexicalUses != null) { + for(int j = 0; j < lexicalUses.length; j++) { + int lexicalUse = lexicalUses[j]; + if (lexicalUse != -1 && !skip(lexicalUse)) { + if (S[lexicalUse].isEmpty()) { + lexicalUses[j] = -1; + } else { + int newUse = top(lexicalUse); + + lexicalUses[j] = newUse; + + if (topR(lexicalUse) != null) { + topR(lexicalUse).addUse(index, -j - 1); + } + } + } + } + } + } + + protected void repairInstructionDefs(SSAInstruction inst, int index, int[] newDefs, int[] newUses) { + instructions[index] = inst.copyForSSA(newDefs, newUses); + } + + protected void popAssignment(SSAInstruction inst, int index) { + instructions[index] = null; + } + + protected boolean isConstant(int valueNumber) { + return symtab.isConstant(valueNumber); + } + + protected boolean skipRepair(SSAInstruction inst, int index) { + if (! super.skipRepair(inst, index)) { + return false; + } + + if (index == -1) return true; + + int[] lexicalUses = lexicalInfo.getExposedUses(index); + if (lexicalUses != null) { + for(int j = 0; j < lexicalUses.length; j++) { + if (! skip(lexicalUses[j])) { + return false; + } + } + } + + return true; + } + + /** + * @param ir + * @param options + */ + private SSAConversion(AstMethod M, AstIR ir, SSAOptions options) { + super(ir, options); + this.copyPropagationMap = + (ir.getLocalMap() instanceof SSAInformation)? + ((SSAInformation)ir.getLocalMap()).getCopyHistory(): + new HashMap(); + + this.ir = ir; + this.debugInfo = M.debugInfo; + this.lexicalInfo = M.lexicalInfo; + this.symtab = ir.getSymbolTable(); + this.R = new Stack[ir.getSymbolTable().getMaxValueNumber() + 1]; + + for(int i = 0; i < CFG.getNumberOfNodes(); i++) { + SSACFG.BasicBlock bb = (SSACFG.BasicBlock) CFG.getNode(i); + if (bb.hasPhi()) { + int n = 0; + for(Iterator X = bb.iteratePhis(); X.hasNext(); n++) X.next(); + phiCounts[i] = n; + } + } + + this.nextSSAValue = ir.getNumberOfParameters()+1; + + int[] exitLive = lexicalInfo.getExitExposedUses(); + BitVector v = new BitVector(); + if (exitLive != null) + for(int i = 0; i < exitLive.length; i++) + v.set( exitLive[i] ); + this.liveness = LiveAnalysis.perform(CFG, symtab, v); + + if (DEBUG) { + Trace.println(liveness); + } + } + + protected int getNextNewValueNumber() { + while (symtab.isConstant(nextSSAValue) || skip(nextSSAValue)) + ++nextSSAValue; + symtab.ensureSymbol( nextSSAValue ); + return nextSSAValue++; + } + + private void copyNames(int to, int from) { + String[][] namesData = debugInfo.getSourceNamesForValues(); + if (namesData != null && + namesData.length > from && + namesData[from] != null) + { + if (namesData[to] == null) { + namesData[to] = namesData[from]; + } else { + String[] newNames = new String[ namesData[from].length+namesData[to].length ]; + System.arraycopy(namesData[from], 0, newNames, 0, namesData[from].length); + System.arraycopy(namesData[to], 0, newNames, namesData[from].length, namesData[to].length); + namesData[to] = newNames; + } + } + } + + protected void initializeVariables() { + for (int V = 1; V <= getMaxValueNumber(); V++) { + if (! skip(V)) { + R[V] = new Stack(); + } + } + + int[] params = symtab.getParameterValueNumbers(); + for (int i = 0; i < params.length; i++) { + if (! skip( params[i] )) { + S[params[i]].push( params[i] ); + valueMap[ params[i] ] = params[i]; + } + } + + } + + protected void repairExit() { + int[] exitLives = lexicalInfo.getExitExposedUses(); + if (exitLives != null) { + for(int i = 0; i < exitLives.length; i++) { + if (! skip(exitLives[i])) { + Assertions._assert(! S[exitLives[i]].isEmpty()); + exitLives[i] = top(exitLives[i]); + } + } + } + } + + // + // Global control. + // + + protected void fail(int v) { + System.err.println( "during SSA conversion of the following IR:" ); + System.err.println( ir ); + super.fail(v); + } + + public SSA2LocalMap getComputedLocalMap() { + return computedLocalMap; + } + + public void perform() { + super.perform(); + + if (DUMP) { + Trace.println( ir ); + if (lexicalInfo != null) { + for(int i = 0; i < instructions.length; i++) { + int[] lexicalUses = lexicalInfo.getExposedUses(i); + if (lexicalUses != null) { + Trace.print("extra uses for " + instructions[i] + ": "); + for(int j = 0; j < lexicalUses.length; j++) { + Trace.print( new Integer(lexicalUses[j]).toString() + " " ); + } + Trace.println(""); + } + } + } + } + + computedLocalMap = new SSAInformation(); + } + + private static IntSet valuesToConvert(AstIR ir) { + IInstruction[] insts = ir.getInstructions(); + MutableIntSet foundOne = new BitVectorIntSet(); + MutableIntSet foundTwo = new BitVectorIntSet(); + for(int i = 0; i < insts.length; i++) { + SSAInstruction inst = (SSAInstruction) insts[i]; + if (inst != null) { + for(int j = 0; j < inst.getNumberOfDefs(); j++) { + int def = inst.getDef(j); + if (def != -1) { + if (foundOne.contains(def) || + ir.getSymbolTable().isConstant(def) || + def <= ir.getNumberOfParameters() || + inst instanceof AssignInstruction) + { + foundTwo.add(def); + } else { + foundOne.add(def); + } + } + } + } + } + + return foundTwo; + } + + public static SSA2LocalMap convert(AstMethod M, AstIR ir, SSAOptions options) { + return convert(M, ir, options, valuesToConvert(ir)); + } + + public static SSA2LocalMap convert(AstMethod M, + final AstIR ir, + SSAOptions options, + final IntSet values) + { + try { + if (DEBUG) { + Trace.println("starting conversion for " + values); + Trace.println( ir ); + } + if (DEBUG_UNDO) Trace.println(">>> starting " + ir.getMethod()); + SSAConversion ssa = new SSAConversion(M, ir, options) { + final int limit = ir.getSymbolTable().getMaxValueNumber(); + protected boolean skip(int i) { + return (i >= 0) && (i <= limit) && (!values.contains(i)); + } + }; + ssa.perform(); + if (DEBUG_UNDO) Trace.println("<<< done " + ir.getMethod()); + return ssa.getComputedLocalMap(); + } catch (RuntimeException e) { + Trace.println("exception " + e + " while converting:"); + Trace.println(ir); + throw e; + } + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/analysis/LiveAnalysis.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/analysis/LiveAnalysis.java new file mode 100644 index 000000000..55564adcb --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/ssa/analysis/LiveAnalysis.java @@ -0,0 +1,247 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.ssa.analysis; + +import java.util.Iterator; + +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.dataflow.graph.AbstractMeetOperator; +import com.ibm.wala.dataflow.graph.BitVectorSolver; +import com.ibm.wala.dataflow.graph.BitVectorUnion; +import com.ibm.wala.dataflow.graph.IKilldallFramework; +import com.ibm.wala.dataflow.graph.ITransferFunctionProvider; +import com.ibm.wala.fixedpoint.impl.UnaryOperator; +import com.ibm.wala.fixpoint.BitVectorVariable; +import com.ibm.wala.fixpoint.IVariable; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSACFG; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAPhiInstruction; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.graph.Graph; +import com.ibm.wala.util.graph.impl.GraphInverter; +import com.ibm.wala.util.intset.BitVector; +import com.ibm.wala.util.intset.BitVectorIntSet; +import com.ibm.wala.util.intset.IntSet; + +/** + * @author Julian Dolby + * + * live-value analysis TODO: document me! + */ +public class LiveAnalysis { + + public interface Result { + boolean isLiveEntry(SSACFG.BasicBlock bb, int valueNumber); + + boolean isLiveExit(SSACFG.BasicBlock bb, int valueNumber); + + BitVector getLiveBefore(int instr); + } + + public static LiveAnalysis.Result perform(final ControlFlowGraph cfg, final SymbolTable symtab) { + return perform(cfg, symtab, new BitVector()); + } + + public static LiveAnalysis.Result perform(final ControlFlowGraph cfg, final SymbolTable symtab, final BitVector considerLiveAtExit) { + final BitVectorIntSet liveAtExit = new BitVectorIntSet(considerLiveAtExit); + final SSAInstruction[] instructions = (SSAInstruction[]) cfg.getInstructions(); + + final class ExitBlockGenKillOperator extends UnaryOperator { + public String toString() { + return "ExitGenKill"; + } + + public boolean equals(Object o) { + return o == this; + } + + public int hashCode() { + return 37721; + } + + public byte evaluate(IVariable lhs, IVariable rhs) { + BitVectorVariable L = (BitVectorVariable) lhs; + boolean changed = L.getValue() == null ? !considerLiveAtExit.isZero() : !L.getValue().sameValue(liveAtExit); + + L.addAll(considerLiveAtExit); + + return changed ? CHANGED : NOT_CHANGED; + } + } + + final class BlockValueGenKillOperator extends UnaryOperator { + private final SSACFG.BasicBlock block; + + BlockValueGenKillOperator(SSACFG.BasicBlock block) { + this.block = block; + } + + public String toString() { + return "GenKill:" + block; + } + + public boolean equals(Object o) { + return (o instanceof BlockValueGenKillOperator) && ((BlockValueGenKillOperator) o).block.equals(block); + } + + public int hashCode() { + return block.hashCode() * 17; + } + + private void processDefs(SSAInstruction inst, BitVector bits) { + for (int j = 0; j < inst.getNumberOfDefs(); j++) { + bits.clear(inst.getDef(j)); + } + } + + private void processUses(SSAInstruction inst, BitVector bits) { + for (int j = 0; j < inst.getNumberOfUses(); j++) { + Assertions._assert(inst.getUse(j) != -1, inst.toString()); + if (!symtab.isConstant(inst.getUse(j))) { + bits.set(inst.getUse(j)); + } + } + } + + public byte evaluate(IVariable lhs, IVariable rhs) { + BitVectorVariable L = (BitVectorVariable) lhs; + IntSet s = ((BitVectorVariable) rhs).getValue(); + BitVectorIntSet bits = new BitVectorIntSet(); + if (s != null) { + bits.addAll(s); + } + + for (Iterator sBBs = cfg.getSuccNodes(block); sBBs.hasNext();) { + SSACFG.BasicBlock sBB = (SSACFG.BasicBlock) sBBs.next(); + int rval = com.ibm.wala.cast.ir.cfg.Util.whichPred(cfg, sBB, block); + for (Iterator sphis = sBB.iteratePhis(); sphis.hasNext();) { + SSAPhiInstruction sphi = (SSAPhiInstruction) sphis.next(); + bits.add(sphi.getUse(rval)); + } + } + for (int i = block.getLastInstructionIndex(); i >= block.getFirstInstructionIndex(); i--) { + SSAInstruction inst = instructions[i]; + if (inst != null) { + processDefs(inst, bits.getBitVector()); + processUses(inst, bits.getBitVector()); + } + } + for (Iterator SS = block.iteratePhis(); SS.hasNext();) { + processDefs((SSAInstruction) SS.next(), bits.getBitVector()); + } + + BitVectorVariable U = new BitVectorVariable(); + U.addAll(bits.getBitVector()); + + if (!L.sameValue(U)) { + L.copyState(U); + return CHANGED; + } else { + return NOT_CHANGED; + } + } + } + + final BitVectorSolver S = new BitVectorSolver(new IKilldallFramework() { + private final Graph G = GraphInverter.invert(cfg); + + public Graph getFlowGraph() { + return G; + } + + public ITransferFunctionProvider getTransferFunctionProvider() { + return new ITransferFunctionProvider() { + + public boolean hasNodeTransferFunctions() { + return true; + } + + public boolean hasEdgeTransferFunctions() { + return false; + } + + public UnaryOperator getNodeTransferFunction(Object node) { + if (((SSACFG.BasicBlock) node).isExitBlock()) { + return new ExitBlockGenKillOperator(); + } else { + return new BlockValueGenKillOperator((SSACFG.BasicBlock) node); + } + } + + public UnaryOperator getEdgeTransferFunction(Object s, Object d) { + Assertions.UNREACHABLE(); + return null; + } + + public AbstractMeetOperator getMeetOperator() { + return BitVectorUnion.instance(); + } + }; + } + }); + + S.solve(); + + return new Result() { + + public String toString() { + StringBuffer s = new StringBuffer(); + for (int i = 0; i < cfg.getNumberOfNodes(); i++) { + SSACFG.BasicBlock bb = (SSACFG.BasicBlock) cfg.getNode(i); + s.append("live entering " + bb + ":" + S.getOut(bb) + "\n"); + s.append("live exiting " + bb + ":" + S.getIn(bb) + "\n"); + } + + return s.toString(); + } + + public boolean isLiveEntry(SSACFG.BasicBlock bb, int valueNumber) { + return ((BitVectorVariable) S.getOut(bb)).get(valueNumber); + } + + public boolean isLiveExit(SSACFG.BasicBlock bb, int valueNumber) { + return ((BitVectorVariable) S.getIn(bb)).get(valueNumber); + } + + public BitVector getLiveBefore(int instr) { + SSACFG.BasicBlock bb = (SSACFG.BasicBlock) cfg.getBlockForInstruction(instr); + IntSet s = ((BitVectorVariable) S.getIn(bb)).getValue(); + BitVectorIntSet bits = new BitVectorIntSet(); + if (s != null) { + bits.addAll(s); + } + + for (int i = bb.getLastInstructionIndex(); i >= instr; i--) { + SSAInstruction inst = instructions[i]; + if (inst != null) { + for (int j = 0; j < inst.getNumberOfDefs(); j++) { + bits.remove(inst.getDef(j)); + } + for (int j = 0; j < inst.getNumberOfUses(); j++) { + if (!symtab.isConstant(inst.getUse(j))) { + bits.add(inst.getUse(j)); + } + } + } + } + + return bits.getBitVector(); + } + }; + } + + public static LiveAnalysis.Result perform(IR ir) { + return perform(ir.getControlFlowGraph(), ir.getSymbolTable()); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/AstTranslator.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/AstTranslator.java new file mode 100644 index 000000000..75819a37b --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/AstTranslator.java @@ -0,0 +1,3165 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.translator; + +import java.util.*; + +import com.ibm.wala.cast.ir.ssa.AssignInstruction; +import com.ibm.wala.cast.ir.ssa.AstAssertInstruction; +import com.ibm.wala.cast.ir.ssa.AstConstants; +import com.ibm.wala.cast.ir.ssa.AstGlobalRead; +import com.ibm.wala.cast.ir.ssa.AstGlobalWrite; +import com.ibm.wala.cast.ir.ssa.AstLexicalAccess; +import com.ibm.wala.cast.ir.ssa.AstLexicalRead; +import com.ibm.wala.cast.ir.ssa.AstLexicalWrite; +import com.ibm.wala.cast.ir.ssa.EachElementGetInstruction; +import com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction; +import com.ibm.wala.cast.ir.ssa.AstLexicalAccess.Access; +import com.ibm.wala.cast.loader.AstMethod.DebuggingInformation; +import com.ibm.wala.cast.loader.AstMethod.LexicalInformation; +import com.ibm.wala.cast.tree.CAstControlFlowMap; +import com.ibm.wala.cast.tree.CAstEntity; +import com.ibm.wala.cast.tree.CAstNode; +import com.ibm.wala.cast.tree.CAstSourcePositionMap; +import com.ibm.wala.cast.tree.CAstType; +import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; +import com.ibm.wala.cast.tree.impl.CAstCloner; +import com.ibm.wala.cast.tree.impl.CAstImpl; +import com.ibm.wala.cast.tree.impl.CAstOperator; +import com.ibm.wala.cast.tree.visit.CAstVisitor; +import com.ibm.wala.cast.types.AstTypeReference; +import com.ibm.wala.cast.util.CAstPrinter; +import com.ibm.wala.cfg.AbstractCFG; +import com.ibm.wala.cfg.IBasicBlock; +import com.ibm.wala.classLoader.IClassLoader; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.shrikeBT.BinaryOpInstruction; +import com.ibm.wala.shrikeBT.ConditionalBranchInstruction; +import com.ibm.wala.shrikeBT.IInstruction; +import com.ibm.wala.shrikeBT.ShiftInstruction; +import com.ibm.wala.shrikeBT.UnaryOpInstruction; +import com.ibm.wala.ssa.*; +import com.ibm.wala.types.*; +import com.ibm.wala.util.Atom; +import com.ibm.wala.util.collections.*; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.Trace; +import com.ibm.wala.util.graph.INodeWithNumber; +import com.ibm.wala.util.graph.impl.SparseNumberedGraph; +import com.ibm.wala.util.graph.traverse.*; + +/** + * @author Julian Dolby TODO: document me. + */ +public abstract class AstTranslator extends CAstVisitor { + + protected abstract boolean treatGlobalsAsLexicallyScoped(); + + protected abstract boolean useLocalValuesForLexicalVars(); + + protected abstract TypeReference defaultCatchType(); + + protected abstract TypeReference makeType(CAstType type); + + protected abstract void defineType(CAstEntity type, WalkContext wc); + + protected abstract void declareFunction(CAstEntity N, WalkContext context); + + protected abstract void defineFunction(CAstEntity N, WalkContext definingContext, AbstractCFG cfg, SymbolTable symtab, + boolean hasCatchBlock, TypeReference[][] caughtTypes, LexicalInformation lexicalInfo, DebuggingInformation debugInfo); + + protected abstract void defineField(CAstEntity topEntity, WalkContext context, CAstEntity n); + + protected abstract String composeEntityName(WalkContext parent, CAstEntity f); + + protected abstract void doThrow(WalkContext context, int exception); + + protected abstract void doArrayRead(WalkContext context, int result, int arrayValue, CAstNode arrayRef, int[] dimValues); + + protected abstract void doArrayWrite(WalkContext context, int arrayValue, CAstNode arrayRef, int[] dimValues, int rval); + + protected abstract void doFieldRead(WalkContext context, int result, int receiver, CAstNode elt, CAstNode parent); + + protected abstract void doFieldWrite(WalkContext context, int receiver, CAstNode elt, CAstNode parent, int rval); + + protected abstract void doMaterializeFunction(WalkContext context, int result, int exception, CAstEntity fn); + + protected abstract void doNewObject(WalkContext context, CAstNode newNode, int result, Object type, int[] arguments); + + protected abstract void doCall(WalkContext context, CAstNode call, int result, int exception, CAstNode name, int receiver, + int[] arguments); + + /** + * If this returns true, new global declarations get created for any attempt + * to access a non-existent variable (believe it or not, JavaScript actually + * does this!) + */ + protected boolean hasImplicitGlobals() { + return false; + } + + /** + * If this returns true, then attempts to lookup non-existent names return + * `null' rather than tripping an assertion. This can be used when special + * handling is needed for built-in names. (PHP does this) + */ + protected boolean hasSpecialUndeclaredVariables() { + return false; + } + + protected void handleUnspecifiedLiteralKey(WalkContext context, CAstNode objectLiteralNode, int unspecifiedLiteralIndex, + CAstVisitor visitor) { + Assertions.UNREACHABLE(); + } + + protected void doPrologue(WalkContext context) { + if (useLocalValuesForLexicalVars()) { + context.cfg().addInstruction(new AstLexicalRead(new Access[0])); + } + } + + protected abstract void doPrimitive(int resultVal, WalkContext context, CAstNode primitiveCall); + + protected int doLocalRead(WalkContext context, String name) { + return context.currentScope().lookup(name).valueNumber(); + } + + protected void doLocalWrite(WalkContext context, String nm, int rval) { + int lval = context.currentScope().lookup(nm).valueNumber(); + if (lval != rval) { + context.cfg().addInstruction(new AssignInstruction(lval, rval)); + } + } + + protected int doLexicallyScopedRead(WalkContext context, String name) { + Symbol S = context.currentScope().lookup(name); + int vn = S.valueNumber(); + CAstEntity E = S.getDefiningScope().getEntity(); + addExposedName(E, E, name, S.getDefiningScope().lookup(name).valueNumber()); + + // lexically-scoped variables can be given a single vn in a method, or + if (useLocalValuesForLexicalVars()) { + Access A = new Access(name, getEntityName(E), vn); + + addExposedName(context.top(), E, name, vn); + addAccess(context.top(), A); + + return vn; + + // lexically-scoped variables can be read from their scope each time + } else { + int result = context.currentScope().allocateTempValue(); + Access A = new Access(name, getEntityName(E), result); + context.cfg().addInstruction(new AstLexicalRead(A)); + return result; + } + } + + protected void doLexicallyScopedWrite(WalkContext context, String name, int rval) { + Symbol S = context.currentScope().lookup(name); + CAstEntity E = S.getDefiningScope().getEntity(); + addExposedName(E, E, name, S.getDefiningScope().lookup(name).valueNumber()); + + // lexically-scoped variables can be given a single vn in a method, or + if (useLocalValuesForLexicalVars()) { + int vn = S.valueNumber(); + Access A = new Access(name, getEntityName(E), vn); + + addExposedName(context.top(), E, name, vn); + addAccess(context.top(), A); + + context.cfg().addInstruction(new AssignInstruction(vn, rval)); + context.cfg().addInstruction(new AstLexicalWrite(A)); + + // lexically-scoped variables can be read from their scope each time + } else { + Access A = new Access(name, getEntityName(E), rval); + context.cfg().addInstruction(new AstLexicalWrite(A)); + } + } + + protected int doGlobalRead(WalkContext context, String name) { + Symbol S = context.currentScope().lookup(name); + + // Global variables can be treated as lexicals defined in the CG root, or + if (treatGlobalsAsLexicallyScoped()) { + + // lexically-scoped variables can be given a single vn in a method, or + if (useLocalValuesForLexicalVars()) { + int vn = S.valueNumber(); + Access A = new Access(name, null, vn); + + addExposedName(context.top(), null, name, vn); + addAccess(context.top(), A); + + return vn; + + // lexically-scoped variables can be read from their scope each time + } else { + int result = context.currentScope().allocateTempValue(); + Access A = new Access(name, null, result); + context.cfg().addInstruction(new AstLexicalRead(A)); + return result; + } + + // globals can be treated as a single static location + } else { + int result = context.currentScope().allocateTempValue(); + FieldReference global = makeGlobalRef(name); + context.cfg().addInstruction(new AstGlobalRead(result, global)); + return result; + } + } + + protected void doGlobalWrite(WalkContext context, String name, int rval) { + Symbol S = context.currentScope().lookup(name); + + // Global variables can be treated as lexicals defined in the CG root, or + if (treatGlobalsAsLexicallyScoped()) { + + // lexically-scoped variables can be given a single vn in a method, or + if (useLocalValuesForLexicalVars()) { + int vn = S.valueNumber(); + Access A = new Access(name, null, vn); + + addExposedName(context.top(), null, name, vn); + addAccess(context.top(), A); + + context.cfg().addInstruction(new AssignInstruction(vn, rval)); + context.cfg().addInstruction(new AstLexicalWrite(A)); + + // lexically-scoped variables can be read from their scope each time + } else { + Access A = new Access(name, null, rval); + context.cfg().addInstruction(new AstLexicalWrite(A)); + } + + // globals can be treated as a single static location + } else { + FieldReference global = makeGlobalRef(name); + context.cfg().addInstruction(new AstGlobalWrite(global, rval)); + } + } + + protected FieldReference makeGlobalRef(String globalName) { + return FieldReference.findOrCreate(TypeReference.findOrCreate(loader.getReference(), AstTypeReference.rootTypeName), Atom + .findOrCreateUnicodeAtom("global " + globalName), TypeReference.findOrCreate(loader.getReference(), + AstTypeReference.rootTypeName)); + } + + protected final IClassLoader loader; + + protected AstTranslator(IClassLoader loader) { + this.loader = loader; + } + + private static class AstDebuggingInformation implements DebuggingInformation { + private String[][] valueNumberNames; + + private Position[] instructionPositions; + + AstDebuggingInformation(Position[] instructionPositions, String[] names) { + this.instructionPositions = instructionPositions; + + valueNumberNames = new String[names.length][]; + for (int i = 0; i < names.length; i++) { + if (names[i] != null) { + valueNumberNames[i] = new String[] { names[i] }; + } else { + valueNumberNames[i] = new String[0]; + } + } + } + + public Position getInstructionPosition(int instructionOffset) { + return instructionPositions[instructionOffset]; + } + + public String[][] getSourceNamesForValues() { + return valueNumberNames; + } + } + + public static final boolean DEBUG_ALL = false; + + public static final boolean DEBUG_TOP = DEBUG_ALL || false; + + public static final boolean DEBUG_CFG = DEBUG_ALL || false; + + public static final boolean DEBUG_NAMES = DEBUG_ALL || true; + + public static final boolean DEBUG_LEXICAL = DEBUG_ALL || false; + + protected final static class PreBasicBlock implements INodeWithNumber, IBasicBlock { + private static final int NORMAL = 0; + + private static final int HANDLER = 1; + + private static final int ENTRY = 2; + + private static final int EXIT = 3; + + private int kind = NORMAL; + + private int number = -1; + + private int firstIndex = -1; + + private int lastIndex = -2; + + private final List instructions = new ArrayList(); + + public int getNumber() { + return getGraphNodeId(); + } + + public int getGraphNodeId() { + return number; + } + + public void setGraphNodeId(int number) { + this.number = number; + } + + public int getFirstInstructionIndex() { + return firstIndex; + } + + void setFirstIndex(int firstIndex) { + this.firstIndex = firstIndex; + } + + public int getLastInstructionIndex() { + return lastIndex; + } + + void setLastIndex(int lastIndex) { + this.lastIndex = lastIndex; + } + + void makeExitBlock() { + kind = EXIT; + } + + void makeEntryBlock() { + kind = ENTRY; + } + + void makeHandlerBlock() { + kind = HANDLER; + } + + public boolean isEntryBlock() { + return kind == ENTRY; + } + + public boolean isExitBlock() { + return kind == EXIT; + } + + public boolean isHandlerBlock() { + return kind == HANDLER; + } + + public String toString() { + return "PreBB" + number + ":" + firstIndex + ".." + lastIndex; + } + + List instructions() { + return instructions; + } + + public boolean isCatchBlock() { + return (lastIndex > -1) && (instructions.get(0) instanceof SSAGetCaughtExceptionInstruction); + } + + public IMethod getMethod() { + return null; + } + + public Iterator iterateAllInstructions() { + return instructions.iterator(); + } + } + + protected final class UnwindState { + final CAstNode unwindAst; + + final WalkContext astContext; + + final CAstVisitor astVisitor; + + UnwindState(CAstNode unwindAst, WalkContext astContext, CAstVisitor astVisitor) { + this.unwindAst = unwindAst; + this.astContext = astContext; + this.astVisitor = astVisitor; + } + + public UnwindState getParent() { + return astContext.getUnwindState(); + } + + public int hashCode() { + return astContext.hashCode() * unwindAst.hashCode() * astVisitor.hashCode(); + } + + public boolean equals(Object o) { + if (o instanceof UnwindState) { + if (((UnwindState) o).unwindAst != unwindAst) + return false; + if (((UnwindState) o).astVisitor != astVisitor) + return false; + if (getParent() == null) { + return ((UnwindState) o).getParent() == null; + } else { + return getParent().equals(((UnwindState) o).getParent()); + } + } + + return false; + } + + boolean covers(UnwindState other) { + if (equals(other)) + return true; + if (getParent() != null) + return getParent().covers(other); + return false; + } + } + + public final class IncipientCFG extends SparseNumberedGraph { + + protected class Unwind { + private final Map unwindData = new LinkedHashMap(); + + private final Map code = new LinkedHashMap(); + + void setUnwindState(PreBasicBlock block, UnwindState context) { + unwindData.put(block, context); + } + + void setUnwindState(CAstNode node, UnwindState context) { + unwindData.put(nodeToBlock.get(node), context); + } + + public PreBasicBlock findOrCreateCode(PreBasicBlock source, PreBasicBlock target, boolean exception) { + UnwindState sourceContext = (UnwindState) unwindData.get(source); + + // no unwinding is needed, so jump to target block directly + if (sourceContext == null) + return target; + + WalkContext astContext = sourceContext.astContext; + UnwindState targetContext = null; + if (target != null) + targetContext = (UnwindState) unwindData.get(target); + + // in unwind context, but catch in same (or inner) unwind context + if (targetContext != null && targetContext.covers(sourceContext)) + return target; + + Pair key = new Pair(sourceContext, new Pair(target, exception ? Boolean.TRUE : Boolean.FALSE)); + + if (code.containsKey(key)) { + return (PreBasicBlock) code.get(key); + + } else { + int e = -1; + PreBasicBlock currentBlock = getCurrentBlock(); + if (!isDeadBlock(currentBlock)) { + addInstruction(SSAInstructionFactory.GotoInstruction()); + newBlock(false); + } + PreBasicBlock startBlock = getCurrentBlock(); + if (exception) { + setCurrentBlockAsHandler(); + e = sourceContext.astContext.currentScope().allocateTempValue(); + addInstruction(SSAInstructionFactory.GetCaughtExceptionInstruction(startBlock.getNumber(), e)); + sourceContext.astContext.setCatchType(startBlock.getNumber(), defaultCatchType()); + } + + while (sourceContext != null && (targetContext == null || !targetContext.covers(sourceContext))) { + final CAstCloner.Clone ast = (new CAstCloner(new CAstImpl())).copy(sourceContext.unwindAst, sourceContext.astContext + .getControlFlow(), sourceContext.astContext.getSourceMap()); + sourceContext.astVisitor.visit(ast.newRoot(), new DelegatingContext(sourceContext.astContext) { + public CAstSourcePositionMap getSourceMap() { + return ast.newPos(); + } + + public CAstControlFlowMap getControlFlow() { + return ast.newCfg(); + } + }, sourceContext.astVisitor); + + sourceContext = sourceContext.getParent(); + } + + PreBasicBlock endBlock = getCurrentBlock(); + if (exception) { + doThrow(astContext, e); + } else { + addInstruction(SSAInstructionFactory.GotoInstruction()); + } + newBlock(false); + + addEdge(currentBlock, getCurrentBlock()); + if (target != null) { + addEdge(endBlock, target); + + // `null' target is idiom for branch/throw to exit + } else { + addDelayedEdge(endBlock, exitMarker, exception); + } + + code.put(key, startBlock); + return startBlock; + } + } + } + + private Unwind unwind = null; + + private final List blocks = new ArrayList(); + + private final Map nodeToBlock = new LinkedHashMap(); + + private final Map delayedEdges = new LinkedHashMap(); + + private final Object exitMarker = new Object(); + + private final Set deadBlocks = new LinkedHashSet(); + + private final Set normalToExit = new LinkedHashSet(); + + private final Set exceptionalToExit = new LinkedHashSet(); + + private Position[] linePositions = new Position[10]; + + private boolean hasCatchBlock = false; + + private int currentInstruction = 0; + + private Position currentPosition = null; + + private PreBasicBlock currentBlock; + + public int getCurrentInstruction() { + return currentInstruction; + } + + public PreBasicBlock getCurrentBlock() { + return currentBlock; + } + + boolean hasCatchBlock() { + return hasCatchBlock; + } + + void noteCatchBlock() { + hasCatchBlock = true; + } + + void setCurrentPosition(Position pos) { + currentPosition = pos; + } + + Position getCurrentPosition() { + return currentPosition; + } + + Position[] getLinePositionMap() { + return linePositions; + } + + public PreBasicBlock newBlock(boolean fallThruFromPrior) { + if (fallThruFromPrior && !currentBlock.isEntryBlock() && currentBlock.instructions().size() == 0) { + return currentBlock; + } + + PreBasicBlock previous = currentBlock; + currentBlock = new PreBasicBlock(); + addNode(currentBlock); + blocks.add(currentBlock); + + if (DEBUG_CFG) + Trace.println("adding new block (node) " + currentBlock); + if (fallThruFromPrior) { + if (DEBUG_CFG) + Trace.println("adding fall-thru edge " + previous + " --> " + currentBlock); + addEdge(previous, currentBlock); + } else { + deadBlocks.add(currentBlock); + } + + return currentBlock; + } + + private void addDelayedEdge(PreBasicBlock src, Object dst, boolean exception) { + Pair v = new Pair(src, exception ? Boolean.TRUE : Boolean.FALSE); + if (delayedEdges.containsKey(dst)) + ((Set) delayedEdges.get(dst)).add(v); + else { + Set s = new LinkedHashSet(); + s.add(v); + delayedEdges.put(dst, s); + } + } + + void makeEntryBlock(PreBasicBlock bb) { + bb.makeEntryBlock(); + } + + void makeExitBlock(PreBasicBlock bb) { + bb.makeExitBlock(); + + for (Iterator ps = getPredNodes(bb); ps.hasNext();) + normalToExit.add(ps.next()); + + checkForRealizedExitEdges(bb); + } + + void setCurrentBlockAsHandler() { + currentBlock.makeHandlerBlock(); + } + + private void checkForRealizedEdges(CAstNode n) { + if (delayedEdges.containsKey(n)) { + for (Iterator ss = ((Set) delayedEdges.get(n)).iterator(); ss.hasNext();) { + Pair s = (Pair) ss.next(); + PreBasicBlock that = (PreBasicBlock) s.fst; + boolean exception = ((Boolean) s.snd).booleanValue(); + if (unwind == null) { + addEdge(that, nodeToBlock.get(n)); + } else { + PreBasicBlock target = (PreBasicBlock) nodeToBlock.get(n); + addEdge(that, unwind.findOrCreateCode(that, target, exception)); + } + } + + delayedEdges.remove(n); + } + } + + private void checkForRealizedExitEdges(PreBasicBlock n) { + if (delayedEdges.containsKey(exitMarker)) { + for (Iterator ss = ((Set) delayedEdges.get(exitMarker)).iterator(); ss.hasNext();) { + Pair s = (Pair) ss.next(); + PreBasicBlock that = (PreBasicBlock) s.fst; + boolean exception = ((Boolean) s.snd).booleanValue(); + addEdge(that, n); + if (exception) + exceptionalToExit.add(that); + else + normalToExit.add(that); + } + + delayedEdges.remove(exitMarker); + } + } + + private void setUnwindState(CAstNode node, UnwindState context) { + if (unwind == null) + unwind = new Unwind(); + unwind.setUnwindState(node, context); + } + + public void addPreNode(CAstNode n) { + addPreNode(n, null); + } + + public void addPreNode(CAstNode n, UnwindState context) { + if (DEBUG_CFG) + Trace.println("adding pre-node " + n); + nodeToBlock.put(n, currentBlock); + deadBlocks.remove(currentBlock); + if (context != null) + setUnwindState(n, context); + checkForRealizedEdges(n); + } + + public void addPreEdge(CAstNode src, CAstNode dst, boolean exception) { + Assertions._assert(nodeToBlock.containsKey(src)); + addPreEdge((PreBasicBlock) nodeToBlock.get(src), dst, exception); + } + + public void addPreEdge(PreBasicBlock src, CAstNode dst, boolean exception) { + if (nodeToBlock.containsKey(dst)) { + PreBasicBlock target = (PreBasicBlock) nodeToBlock.get(dst); + if (DEBUG_CFG) + Trace.println("adding pre-edge " + src + " --> " + dst); + if (unwind == null) { + addEdge(src, target); + } else { + addEdge(src, unwind.findOrCreateCode(src, target, exception)); + } + } else { + if (DEBUG_CFG) + Trace.println("adding delayed pre-edge " + src + " --> " + dst); + addDelayedEdge(src, dst, exception); + } + } + + public void addPreEdgeToExit(CAstNode src, boolean exception) { + Assertions._assert(nodeToBlock.containsKey(src)); + addPreEdgeToExit((PreBasicBlock) nodeToBlock.get(src), exception); + } + + public void addPreEdgeToExit(PreBasicBlock src, boolean exception) { + if (unwind != null) { + PreBasicBlock handlers = unwind.findOrCreateCode(src, null, exception); + if (handlers != null) { + addEdge(src, handlers); + return; + } + } + + addDelayedEdge(src, exitMarker, exception); + } + + public void addEdge(Object src, Object dst) { + super.addEdge(src, dst); + deadBlocks.remove(dst); + } + + boolean isDeadBlock(PreBasicBlock block) { + return deadBlocks.contains(block); + } + + public PreBasicBlock getBlock(CAstNode n) { + return (PreBasicBlock) nodeToBlock.get(n); + } + + private void noteLinePosition(int instruction) { + if (linePositions.length < (instruction + 1)) { + Position[] newData = new Position[instruction * 2 + 1]; + System.arraycopy(linePositions, 0, newData, 0, linePositions.length); + linePositions = newData; + } + + linePositions[instruction] = currentPosition; + } + + public void addInstruction(SSAInstruction n) { + deadBlocks.remove(currentBlock); + + int inst = currentInstruction++; + + noteLinePosition(inst); + + if (currentBlock.instructions().size() == 0) { + currentBlock.setFirstIndex(inst); + } else { + Assertions._assert(!(n instanceof SSAGetCaughtExceptionInstruction)); + } + + if (DEBUG_CFG) { + Trace.println("adding " + n + " at " + inst + " to " + currentBlock); + } + + currentBlock.instructions().add(n); + + currentBlock.setLastIndex(inst); + } + } + + protected final static class AstCFG extends AbstractCFG { + private final IInstruction[] instructions; + + private final int[] instructionToBlockMap; + + private final String functionName; + + private final SymbolTable symtab; + + AstCFG(CAstEntity n, IncipientCFG icfg, SymbolTable symtab) { + super(null); + List blocks = icfg.blocks; + + this.symtab = symtab; + functionName = n.getName(); + instructionToBlockMap = new int[blocks.size()]; + + for (int i = 0; i < blocks.size(); i++) + instructionToBlockMap[i] = ((PreBasicBlock) blocks.get(i)).getLastInstructionIndex(); + + for (int i = 0; i < blocks.size(); i++) { + PreBasicBlock block = (PreBasicBlock) blocks.get(i); + this.addNode(block); + if (block.isCatchBlock()) { + setCatchBlock(i); + } + + if (DEBUG_CFG) + Trace.println("added " + blocks.get(i) + " to final CFG as " + getNumber((IBasicBlock) blocks.get(i))); + } + if (DEBUG_CFG) + Trace.println(getMaxNumber() + " blocks total"); + + init(); + + for (int i = 0; i < blocks.size(); i++) { + PreBasicBlock src = (PreBasicBlock) blocks.get(i); + for (Iterator j = icfg.getSuccNodes(src); j.hasNext();) { + PreBasicBlock dst = (PreBasicBlock) j.next(); + if (isCatchBlock(dst.getNumber()) || (dst.isExitBlock() && icfg.exceptionalToExit.contains(src))) { + if (DEBUG_CFG) + Trace.println("exceptonal edge " + src + " -> " + dst); + addExceptionalEdge(src, dst); + } + + if (dst.isExitBlock() ? icfg.normalToExit.contains(src) : !isCatchBlock(dst.getNumber())) { + if (DEBUG_CFG) + Trace.println("normal edge " + src + " -> " + dst); + addNormalEdge(src, dst); + } + } + } + + int x = 0; + instructions = new SSAInstruction[icfg.currentInstruction]; + for (int i = 0; i < blocks.size(); i++) { + List bi = ((PreBasicBlock) blocks.get(i)).instructions(); + for (int j = 0; j < bi.size(); j++) { + instructions[x++] = (SSAInstruction) bi.get(j); + } + } + } + + public int hashCode() { + return functionName.hashCode(); + } + + public boolean equals(Object o) { + return (o instanceof AstCFG) && functionName.equals(((AstCFG) o).functionName); + } + + public IBasicBlock getBlockForInstruction(int index) { + for (int i = 1; i < getNumberOfNodes() - 1; i++) + if (index <= instructionToBlockMap[i]) + return (IBasicBlock) getNode(i); + + return null; + } + + public IInstruction[] getInstructions() { + return instructions; + } + + public int getProgramCounter(int index) { + return index; + } + + public String toString() { + SSAInstruction[] insts = (SSAInstruction[]) getInstructions(); + StringBuffer s = new StringBuffer("CAst CFG of " + functionName); + int params[] = symtab.getParameterValueNumbers(); + for (int i = 0; i < params.length; i++) + s.append(" ").append(params[i]); + s.append("\n"); + + for (int i = 0; i < getNumberOfNodes(); i++) { + PreBasicBlock bb = (PreBasicBlock) getNode(i); + s.append(bb).append("\n"); + + for (Iterator ss = getSuccNodes(bb); ss.hasNext();) + s.append(" -->" + ss.next() + "\n"); + + for (int j = bb.getFirstInstructionIndex(); j <= bb.getLastInstructionIndex(); j++) + if (insts[j] != null) + s.append(" " + insts[j].toString(symtab, null) + "\n"); + } + + s.append("-- END --"); + return s.toString(); + } + } + + private final static int TYPE_LOCAL = 1; + + private final static int TYPE_GLOBAL = 2; + + private final static int TYPE_SCRIPT = 3; + + private final static int TYPE_FUNCTION = 4; + + private final static int TYPE_TYPE = 5; + + protected interface Symbol { + int valueNumber(); + + Scope getDefiningScope(); + + boolean isParameter(); + + Object constant(); + + void setConstant(Object s); + + boolean isFinal(); + } + + public interface Scope { + int type(); + + int allocateTempValue(); + + int getConstantValue(Object c); + + boolean isConstant(int valueNumber); + + Object getConstantObject(int valueNumber); + + void declare(String name, boolean isFinal, boolean isCaseInsensitive); + + void declare(String name, boolean isFinal, boolean isCaseInsensitive, int valueNumber); + + boolean isCaseInsensitive(String name); + + boolean contains(String name); + + Symbol lookup(String name); + + Iterator getAllNames(); + + int size(); + + boolean isGlobal(Symbol s); + + boolean isLexicallyScoped(Symbol s); + + CAstEntity getEntity(); + } + + private static abstract class AbstractSymbol implements Symbol { + private Object constantValue; + + private boolean isFinalValue; + + private final Scope definingScope; + + AbstractSymbol(Scope definingScope, boolean isFinalValue) { + this.definingScope = definingScope; + this.isFinalValue = isFinalValue; + } + + public boolean isFinal() { + return isFinalValue; + } + + public Object constant() { + return constantValue; + } + + public void setConstant(Object cv) { + constantValue = cv; + } + + public Scope getDefiningScope() { + return definingScope; + } + }; + + private abstract class AbstractScope implements Scope { + private final Scope parent; + + private final Map values = new LinkedHashMap(); + + private final Map caseInsensitiveNames = new LinkedHashMap(); + + protected abstract SymbolTable getUnderlyingSymtab(); + + public int size() { + return getUnderlyingSymtab().getMaxValueNumber() + 1; + } + + public Iterator getAllNames() { + return values.keySet().iterator(); + } + + public int allocateTempValue() { + return getUnderlyingSymtab().newSymbol(); + } + + public int getConstantValue(Object o) { + if (o instanceof Integer) { + return getUnderlyingSymtab().getConstant(((Integer) o).intValue()); + } else if (o instanceof Float) { + return getUnderlyingSymtab().getConstant(((Float) o).floatValue()); + } else if (o instanceof Double) { + return getUnderlyingSymtab().getConstant(((Double) o).doubleValue()); + } else if (o instanceof Long) { + return getUnderlyingSymtab().getConstant(((Long) o).longValue()); + } else if (o instanceof String) { + return getUnderlyingSymtab().getConstant((String) o); + } else if (o instanceof Boolean) { + return getUnderlyingSymtab().getConstant(o == Boolean.TRUE ? 1 : 0); + } else if (o instanceof Character) { + return getUnderlyingSymtab().getConstant(((Character) o).charValue()); + } else if (o == null) { + return getUnderlyingSymtab().getNullConstant(); + } else if (o == CAstControlFlowMap.SWITCH_DEFAULT) { + return getUnderlyingSymtab().getConstant("__default label"); + } else { + Trace.println("cannot handle constant " + o); + Assertions.UNREACHABLE(); + return -1; + } + } + + public boolean isConstant(int valueNumber) { + return getUnderlyingSymtab().isConstant(valueNumber); + } + + public Object getConstantObject(int valueNumber) { + return getUnderlyingSymtab().getConstantValue(valueNumber); + } + + public void declare(String nm, boolean isFinal, boolean isCaseInsensitive, int vn) { + Assertions._assert(!contains(nm), nm); + if (isCaseInsensitive) + caseInsensitiveNames.put(nm.toLowerCase(), nm); + values.put(nm, makeSymbol(nm, isFinal, vn)); + } + + public void declare(String nm, boolean isFinal, boolean isCaseInsensitive) { + if (!contains(nm) || lookup(nm).getDefiningScope() != this) { + if (isCaseInsensitive) + caseInsensitiveNames.put(nm.toLowerCase(), nm); + values.put(nm, makeSymbol(nm, isFinal)); + } else { + Assertions._assert(!isFinal, "trying to redeclare " + nm); + } + } + + AbstractScope(Scope parent) { + this.parent = parent; + } + + private final String mapName(String nm) { + String mappedName = (String) caseInsensitiveNames.get(nm.toLowerCase()); + return (mappedName == null) ? nm : mappedName; + } + + protected Symbol makeSymbol(String nm, boolean isFinal) { + return makeSymbol(nm, isFinal, -1, this); + } + + protected Symbol makeSymbol(String nm, boolean isFinal, int vn) { + return makeSymbol(nm, isFinal, vn, this); + } + + abstract protected Symbol makeSymbol(String nm, boolean isFinal, int vn, Scope parent); + + public boolean isCaseInsensitive(String nm) { + return caseInsensitiveNames.containsKey(nm.toLowerCase()); + } + + public Symbol lookup(String nm) { + if (contains(nm)) { + return (Symbol) values.get(mapName(nm)); + } else { + Symbol scoped = parent.lookup(nm); + if (scoped != null && getEntityScope() == this && (isGlobal(scoped) || isLexicallyScoped(scoped))) { + values.put(nm, makeSymbol(nm, scoped.isFinal(), -1, scoped.getDefiningScope())); + if (scoped.getDefiningScope().isCaseInsensitive(nm)) { + caseInsensitiveNames.put(nm.toLowerCase(), nm); + } + return (Symbol) values.get(nm); + } else { + return scoped; + } + } + } + + public boolean contains(String nm) { + String mappedName = (String) caseInsensitiveNames.get(nm.toLowerCase()); + return values.containsKey(mappedName == null ? nm : mappedName); + } + + public boolean isGlobal(Symbol s) { + return s.getDefiningScope() == globalScope; + } + + public abstract boolean isLexicallyScoped(Symbol s); + + protected abstract AbstractScope getEntityScope(); + + public abstract CAstEntity getEntity(); + }; + + private AbstractScope makeScriptScope(final CAstEntity s, Scope parent) { + return new AbstractScope(parent) { + SymbolTable scriptGlobalSymtab = new SymbolTable(s.getArgumentCount()); + + public SymbolTable getUnderlyingSymtab() { + return scriptGlobalSymtab; + } + + protected AbstractScope getEntityScope() { + return this; + } + + public boolean isLexicallyScoped(Symbol s) { + if (isGlobal(s)) + return false; + else + return ((AbstractScope) s.getDefiningScope()).getEntityScope() != this; + } + + public CAstEntity getEntity() { + return s; + } + + public int type() { + return TYPE_SCRIPT; + } + + protected Symbol makeSymbol(final String nm, final boolean isFinal, int vn, Scope definer) { + final int v = vn == -1 ? getUnderlyingSymtab().newSymbol() : vn; + return new AbstractSymbol(definer, isFinal) { + public String toString() { + return nm + ":" + System.identityHashCode(this); + } + + public int valueNumber() { + return v; + } + + public boolean isParameter() { + return false; + } + }; + } + }; + } + + private AbstractScope makeFunctionScope(final CAstEntity f, Scope parent) { + return new AbstractScope(parent) { + private final String[] params = f.getArgumentNames(); + + private final SymbolTable functionSymtab = new SymbolTable(f.getArgumentCount()); + + // ctor for scope object + { + for (int i = 0; i < f.getArgumentCount(); i++) + declare(f.getArgumentNames()[i], false, false); + } + + public SymbolTable getUnderlyingSymtab() { + return functionSymtab; + } + + protected AbstractScope getEntityScope() { + return this; + } + + public boolean isLexicallyScoped(Symbol s) { + if (isGlobal(s)) + return false; + else + return ((AbstractScope) s.getDefiningScope()).getEntityScope() != this; + } + + public CAstEntity getEntity() { + return f; + } + + public int type() { + return TYPE_FUNCTION; + } + + private int find(String n) { + for (int i = 0; i < params.length; i++) { + if (n.equals(params[i])) { + return i + 1; + } + } + + return -1; + } + + protected Symbol makeSymbol(final String nm, final boolean isFinal, final int valueNumber, Scope definer) { + return new AbstractSymbol(definer, isFinal) { + final int vn; + + { + int x = find(nm); + if (x != -1) { + Assertions._assert(valueNumber == -1); + vn = x; + } else if (valueNumber != -1) { + vn = valueNumber; + } else { + vn = getUnderlyingSymtab().newSymbol(); + } + } + + public String toString() { + return nm + ":" + System.identityHashCode(this); + } + + public int valueNumber() { + return vn; + } + + public boolean isParameter() { + return vn <= params.length; + } + }; + } + }; + } + + private Scope makeLocalScope(CAstNode s, final Scope parent) { + return new AbstractScope(parent) { + public int type() { + return TYPE_LOCAL; + } + + public SymbolTable getUnderlyingSymtab() { + return ((AbstractScope) parent).getUnderlyingSymtab(); + } + + protected AbstractScope getEntityScope() { + return ((AbstractScope) parent).getEntityScope(); + } + + public boolean isLexicallyScoped(Symbol s) { + return ((AbstractScope) getEntityScope()).isLexicallyScoped(s); + } + + public CAstEntity getEntity() { + return ((AbstractScope) getEntityScope()).getEntity(); + } + + protected Symbol makeSymbol(final String nm, boolean isFinal, int vn, Scope definer) { + final int v = vn == -1 ? getUnderlyingSymtab().newSymbol() : vn; + return new AbstractSymbol(definer, isFinal) { + public String toString() { + return nm + ":" + System.identityHashCode(this); + } + + public int valueNumber() { + return v; + } + + public boolean isParameter() { + return false; + } + }; + } + }; + } + + private Scope makeGlobalScope() { + final Map globalSymbols = new LinkedHashMap(); + final Map caseInsensitiveNames = new LinkedHashMap(); + return new Scope() { + private final String mapName(String nm) { + String mappedName = (String) caseInsensitiveNames.get(nm.toLowerCase()); + return (mappedName == null) ? nm : mappedName; + } + + public boolean isGlobal(Symbol s) { + return true; + } + + public boolean isLexicallyScoped(Symbol s) { + return false; + } + + public CAstEntity getEntity() { + return null; + } + + public int size() { + return globalSymbols.size(); + } + + public Iterator getAllNames() { + return globalSymbols.keySet().iterator(); + } + + public int allocateTempValue() { + throw new UnsupportedOperationException(); + } + + public int getConstantValue(Object c) { + throw new UnsupportedOperationException(); + } + + public boolean isConstant(int valueNumber) { + throw new UnsupportedOperationException(); + } + + public Object getConstantObject(int valueNumber) { + throw new UnsupportedOperationException(); + } + + public int type() { + return TYPE_GLOBAL; + } + + public boolean contains(String name) { + return hasImplicitGlobals() || globalSymbols.containsKey(mapName(name)); + } + + public boolean isCaseInsensitive(String name) { + return caseInsensitiveNames.containsKey(name.toLowerCase()); + } + + public Symbol lookup(String name) { + if (!globalSymbols.containsKey(mapName(name))) + if (hasImplicitGlobals()) + declare(name, false, false); + else if (hasSpecialUndeclaredVariables()) { + return null; + } else { + throw new Error("cannot find " + name); + } + + return (Symbol) globalSymbols.get(mapName(name)); + } + + public void declare(final String name, boolean isFinal, boolean isCaseInsensitive, int vn) { + Assertions._assert(vn == -1); + declare(name, isFinal, isCaseInsensitive); + } + + public void declare(final String name, boolean isFinal, boolean isCaseInsensitive) { + if (isCaseInsensitive) { + caseInsensitiveNames.put(name.toLowerCase(), name); + } + globalSymbols.put(name, new AbstractSymbol(this, isFinal) { + public String toString() { + return name + ":" + System.identityHashCode(this); + } + + public boolean isParameter() { + return false; + } + + public int valueNumber() { + throw new UnsupportedOperationException(); + } + }); + } + }; + } + + protected Scope makeTypeScope(final CAstEntity type, final Scope parent) { + final Map typeSymbols = new LinkedHashMap(); + final Map caseInsensitiveNames = new LinkedHashMap(); + return new Scope() { + private final String mapName(String nm) { + String mappedName = (String) caseInsensitiveNames.get(nm.toLowerCase()); + return (mappedName == null) ? nm : mappedName; + } + + public boolean isGlobal(Symbol s) { + return false; + } + + public boolean isLexicallyScoped(Symbol s) { + return false; + } + + public CAstEntity getEntity() { + return type; + } + + public int size() { + return typeSymbols.size(); + } + + public Iterator getAllNames() { + return typeSymbols.keySet().iterator(); + } + + public int allocateTempValue() { + throw new UnsupportedOperationException(); + } + + public int getConstantValue(Object c) { + throw new UnsupportedOperationException(); + } + + public boolean isConstant(int valueNumber) { + throw new UnsupportedOperationException(); + } + + public Object getConstantObject(int valueNumber) { + throw new UnsupportedOperationException(); + } + + public int type() { + return TYPE_TYPE; + } + + public boolean contains(String name) { + return typeSymbols.containsKey(mapName(name)); + } + + public boolean isCaseInsensitive(String name) { + return caseInsensitiveNames.containsKey(name.toLowerCase()); + } + + public Symbol lookup(String nm) { + if (typeSymbols.containsKey(mapName(nm))) + return (Symbol) typeSymbols.get(mapName(nm)); + else { + return parent.lookup(nm); + } + } + + public void declare(final String name, boolean isFinal, boolean isCaseInsensitive, int vn) { + Assertions._assert(vn == -1); + declare(name, isFinal, isCaseInsensitive); + } + + public void declare(final String name, boolean isFinal, boolean isCaseInsensitive) { + Assertions._assert(!isFinal); + if (isCaseInsensitive) + caseInsensitiveNames.put(name.toLowerCase(), name); + typeSymbols.put(name, new AbstractSymbol(this, isFinal) { + public String toString() { + return name + ":" + System.identityHashCode(this); + } + + public boolean isParameter() { + return false; + } + + public int valueNumber() { + throw new UnsupportedOperationException(); + } + }); + } + }; + } + + public interface WalkContext extends Context { + + String getName(); + + String file(); + + CAstSourcePositionMap getSourceMap(); + + CAstControlFlowMap getControlFlow(); + + Scope currentScope(); + + Set entityScopes(); + + IncipientCFG cfg(); + + UnwindState getUnwindState(); + + void setCatchType(int blockNumber, TypeReference catchType); + + void setCatchType(CAstNode catchNode, TypeReference catchType); + + TypeReference[][] getCatchTypes(); + + } + + private abstract class DelegatingContext implements WalkContext { + private final WalkContext parent; + + DelegatingContext(WalkContext parent) { + this.parent = parent; + } + + public String getName() { + return parent.getName(); + } + + public String file() { + return parent.file(); + } + + public CAstEntity top() { + return parent.top(); + } + + public CAstSourcePositionMap getSourceMap() { + return parent.getSourceMap(); + } + + public CAstControlFlowMap getControlFlow() { + return parent.getControlFlow(); + } + + public Scope currentScope() { + return parent.currentScope(); + } + + public Set entityScopes() { + return parent.entityScopes(); + } + + public IncipientCFG cfg() { + return parent.cfg(); + } + + public UnwindState getUnwindState() { + return parent.getUnwindState(); + } + + public void setCatchType(int blockNumber, TypeReference catchType) { + parent.setCatchType(blockNumber, catchType); + } + + public void setCatchType(CAstNode catchNode, TypeReference catchType) { + parent.setCatchType(catchNode, catchType); + } + + public TypeReference[][] getCatchTypes() { + return parent.getCatchTypes(); + } + + } + + private class FileContext extends DelegatingContext { + private final String fUnitName; + + public FileContext(WalkContext parent, String unitName) { + super(parent); + fUnitName = unitName; + } + + public String getName() { + return fUnitName; + } + } + + private class UnwindContext extends DelegatingContext { + private final UnwindState state; + + UnwindContext(CAstNode unwindNode, WalkContext parent, CAstVisitor visitor) { + super(parent); + this.state = new UnwindState(unwindNode, parent, visitor); + } + + public UnwindState getUnwindState() { + return state; + } + } + + private abstract class EntityContext extends DelegatingContext { + protected final CAstEntity topNode; + + protected final String name; + + EntityContext(WalkContext parent, CAstEntity s) { + super(parent); + this.topNode = s; + this.name = composeEntityName(parent, s); + addEntityName(s, this.name); + } + + public String getName() { + return name; + } + + public CAstEntity top() { + return topNode; + } + + public CAstSourcePositionMap getSourceMap() { + return top().getSourceMap(); + } + + } + + private class CodeEntityContext extends EntityContext { + private final Scope topEntityScope; + + private final Set allEntityScopes; + + private final IncipientCFG cfg; + + private TypeReference[][] catchTypes = new TypeReference[0][]; + + CodeEntityContext(WalkContext parent, Scope entityScope, CAstEntity s) { + super(parent, s); + + this.topEntityScope = entityScope; + + this.allEntityScopes = new HashSet(); + this.allEntityScopes.add(entityScope); + + cfg = new IncipientCFG(); + } + + public CAstControlFlowMap getControlFlow() { + return top().getControlFlow(); + } + + public IncipientCFG cfg() { + return cfg; + } + + public Scope currentScope() { + return topEntityScope; + } + + public Set entityScopes() { + return allEntityScopes; + } + + public UnwindState getUnwindState() { + return null; + } + + public void setCatchType(CAstNode catchNode, TypeReference catchType) { + setCatchType(cfg.getBlock(catchNode).getNumber(), catchType); + } + + public void setCatchType(int blockNumber, TypeReference catchType) { + if (catchTypes.length <= blockNumber) { + TypeReference[][] data = new TypeReference[blockNumber + 1][]; + System.arraycopy(catchTypes, 0, data, 0, catchTypes.length); + catchTypes = data; + } + + if (catchTypes[blockNumber] == null) { + catchTypes[blockNumber] = new TypeReference[] { catchType }; + } else { + TypeReference[] data = catchTypes[blockNumber]; + + for (int i = 0; i < data.length; i++) { + if (data[i] == catchType) { + return; + } + } + + TypeReference[] newData = new TypeReference[data.length + 1]; + System.arraycopy(data, 0, newData, 0, data.length); + newData[data.length] = catchType; + + catchTypes[blockNumber] = newData; + } + } + + public TypeReference[][] getCatchTypes() { + return catchTypes; + } + } + + private final class TypeContext extends EntityContext { + + private TypeContext(WalkContext parent, CAstEntity n) { + super(parent, n); + } + + public CAstControlFlowMap getControlFlow() { + Assertions.UNREACHABLE("TypeContext.getControlFlow()"); + return null; + } + + public IncipientCFG cfg() { + Assertions.UNREACHABLE("TypeContext.cfg()"); + return null; + } + + public UnwindState getUnwindState() { + Assertions.UNREACHABLE("TypeContext.getUnwindState()"); + return null; + } + } + + private class LocalContext extends DelegatingContext { + private final Scope localScope; + + LocalContext(WalkContext parent, Scope localScope) { + super(parent); + this.localScope = localScope; + parent.entityScopes().add(localScope); + } + + public Scope currentScope() { + return localScope; + } + } + + public static class AstLexicalInformation implements LexicalInformation { + private final Pair[] exposedNames; + + private final int[][] instructionLexicalUses; + + private final int[] exitLexicalUses; + + private final String[] scopingParents; + + private int[] buildLexicalUseArray(Pair[] exposedNames) { + if (exposedNames != null) { + int[] lexicalUses = new int[exposedNames.length]; + for (int j = 0; j < exposedNames.length; j++) { + lexicalUses[j] = ((Integer) exposedNames[j].snd).intValue(); + } + + return lexicalUses; + } else { + return null; + } + } + + private Pair[] buildLexicalNamesArray(Pair[] exposedNames) { + if (exposedNames != null) { + Pair[] lexicalNames = new Pair[exposedNames.length]; + for (int j = 0; j < exposedNames.length; j++) { + lexicalNames[j] = (Pair) exposedNames[j].fst; + } + + return lexicalNames; + } else { + return null; + } + } + + AstLexicalInformation(Scope scope, IInstruction[] instrs, Set exposedNamesSet, Set accesses) { + Pair[] EN = null; + if (exposedNamesSet != null) { + EN = (Pair[]) exposedNamesSet.toArray(new Pair[exposedNamesSet.size()]); + } + + this.exposedNames = buildLexicalNamesArray(EN); + + this.exitLexicalUses = buildLexicalUseArray(EN); + + this.instructionLexicalUses = new int[instrs.length][]; + for (int i = 0; i < instrs.length; i++) { + if (instrs[i] instanceof SSAAbstractInvokeInstruction) { + this.instructionLexicalUses[i] = buildLexicalUseArray(EN); + } + } + + if (accesses != null) { + Set parents = new LinkedHashSet(); + for (Iterator ACS = accesses.iterator(); ACS.hasNext();) { + Access AC = (Access) ACS.next(); + if (AC.variableDefiner != null) { + parents.add(AC.variableDefiner); + } + } + scopingParents = (String[]) parents.toArray(new String[parents.size()]); + + if (DEBUG_LEXICAL) { + Trace.println("scoping parents of " + scope.getEntity()); + Trace.println(parents.toString()); + } + + } else { + scopingParents = null; + } + + if (DEBUG_NAMES) { + Trace.println("lexical uses of " + scope.getEntity()); + for (int i = 0; i < instructionLexicalUses.length; i++) { + if (instructionLexicalUses[i] != null) { + Trace.println(" lexical uses of " + instrs[i]); + for (int j = 0; j < instructionLexicalUses[i].length; j++) { + Trace.println(" " + this.exposedNames[j].fst + ": " + instructionLexicalUses[i][j]); + } + } + } + } + } + + public int[] getExitExposedUses() { + return exitLexicalUses; + } + + public int[] getExposedUses(int instructionOffset) { + return instructionLexicalUses[instructionOffset]; + } + + public Pair[] getExposedNames() { + return exposedNames; + } + + public String[] getScopingParents() { + return scopingParents; + } + }; + + private final Map results = new LinkedHashMap(); + + protected boolean hasValue(CAstNode n) { + return results.containsKey(n); + } + + public final int setValue(CAstNode n, int v) { + results.put(n, new Integer(v)); + return v; + } + + public final int getValue(CAstNode n) { + if (results.containsKey(n)) + return ((Integer) results.get(n)).intValue(); + else { + Trace.println("no value for " + n.getKind()); + return -1; + } + } + + private final Map entityNames = new LinkedHashMap(); + + private final Map exposedNames = new LinkedHashMap(); + + private final Map accesses = new LinkedHashMap(); + + private void addEntityName(CAstEntity e, String name) { + entityNames.put(e, name); + } + + private void addAccess(CAstEntity e, Access access) { + if (!accesses.containsKey(e)) + accesses.put(e, new LinkedHashSet()); + ((Set) accesses.get(e)).add(access); + } + + private void addExposedName(CAstEntity entity, CAstEntity declaration, String name, int valueNumber) { + if (!exposedNames.containsKey(entity)) + exposedNames.put(entity, new LinkedHashSet()); + + ((Set) exposedNames.get(entity)).add(new Pair(new Pair(name, getEntityName(declaration)), new Integer(valueNumber))); + } + + private String getEntityName(CAstEntity e) { + if (e == null) { + return null; + } else { + Assertions._assert(entityNames.containsKey(e)); + return "L" + entityNames.get(e); + } + } + + protected UnaryOpInstruction.IOperator translateUnaryOpcode(CAstNode op) { + if (op == CAstOperator.OP_BITNOT) + return UnaryOpInstruction.Operator.NEG; + else if (op == CAstOperator.OP_NOT) + return UnaryOpInstruction.Operator.NEG; + else if (op == CAstOperator.OP_SUB) + return AstConstants.UnaryOp.MINUS; + else + Assertions.UNREACHABLE("cannot translate " + CAstPrinter.print(op)); + return null; + + } + + protected BinaryOpInstruction.IOperator translateBinaryOpcode(CAstNode op) { + if (op == CAstOperator.OP_ADD) + return BinaryOpInstruction.Operator.ADD; + else if (op == CAstOperator.OP_DIV) + return BinaryOpInstruction.Operator.DIV; + else if (op == CAstOperator.OP_LSH) + return ShiftInstruction.Operator.SHL; + else if (op == CAstOperator.OP_MOD) + return BinaryOpInstruction.Operator.REM; + else if (op == CAstOperator.OP_MUL) + return BinaryOpInstruction.Operator.MUL; + else if (op == CAstOperator.OP_RSH) + return ShiftInstruction.Operator.SHR; + else if (op == CAstOperator.OP_SUB) + return BinaryOpInstruction.Operator.SUB; + else if (op == CAstOperator.OP_URSH) + return ShiftInstruction.Operator.USHR; + else if (op == CAstOperator.OP_BIT_AND) + return BinaryOpInstruction.Operator.AND; + else if (op == CAstOperator.OP_BIT_OR) + return BinaryOpInstruction.Operator.OR; + else if (op == CAstOperator.OP_BIT_XOR) + return BinaryOpInstruction.Operator.XOR; + else if (op == CAstOperator.OP_CONCAT) + return AstConstants.BinaryOp.CONCAT; + else if (op == CAstOperator.OP_EQ) + return AstConstants.BinaryOp.EQ; + else if (op == CAstOperator.OP_GE) + return AstConstants.BinaryOp.GE; + else if (op == CAstOperator.OP_GT) + return AstConstants.BinaryOp.GT; + else if (op == CAstOperator.OP_LE) + return AstConstants.BinaryOp.LE; + else if (op == CAstOperator.OP_LT) + return AstConstants.BinaryOp.LT; + else if (op == CAstOperator.OP_NE) + return AstConstants.BinaryOp.NE; + else { + Assertions.UNREACHABLE("cannot translate " + CAstPrinter.print(op)); + return null; + } + } + + protected ConditionalBranchInstruction.IOperator translateConditionOpcode(CAstNode op) { + if (op == CAstOperator.OP_EQ) + return ConditionalBranchInstruction.Operator.EQ; + else if (op == CAstOperator.OP_GE) + return ConditionalBranchInstruction.Operator.GE; + else if (op == CAstOperator.OP_GT) + return ConditionalBranchInstruction.Operator.GT; + else if (op == CAstOperator.OP_LE) + return ConditionalBranchInstruction.Operator.LE; + else if (op == CAstOperator.OP_LT) + return ConditionalBranchInstruction.Operator.LT; + else if (op == CAstOperator.OP_NE) + return ConditionalBranchInstruction.Operator.NE; + + else { + Assertions.UNREACHABLE("cannot translate " + CAstPrinter.print(op)); + return null; + } + } + + private String[] makeNameMap(Set scopes) { + // all scopes share the same underlying symtab, which is what + // size really refers to. + String[] map = new String[((Scope) scopes.iterator().next()).size() + 1]; + + if (DEBUG_NAMES) { + Trace.println("names array of size " + map.length); + } + + for (Iterator S = scopes.iterator(); S.hasNext();) { + Scope scope = (Scope) S.next(); + for (Iterator I = scope.getAllNames(); I.hasNext();) { + String nm = (String) I.next(); + Symbol v = (Symbol) scope.lookup(nm); + + // hack for new expression idiom in the Java translator + if ("ctor temp".equals(nm)) + continue; + + Assertions._assert(map[v.valueNumber()] == null || map[v.valueNumber()].equals(nm), "value number " + v.valueNumber() + + " mapped to multiple names in translator: " + nm + " and " + map[v.valueNumber()]); + + map[v.valueNumber()] = nm; + + if (DEBUG_NAMES) { + Trace.println("mapping name " + nm + " to " + v.valueNumber()); + } + } + } + + return map; + } + + protected final CAstType getTypeForNode(WalkContext context, CAstNode node) { + if (context.top().getNodeTypeMap() != null) { + return context.top().getNodeTypeMap().getNodeType(node); + } else { + return null; + } + } + + private void patchLexicalAccesses(IInstruction[] instrs, Set accesses) { + Access[] AC = accesses == null ? (Access[]) null : (Access[]) accesses.toArray(new Access[accesses.size()]); + for (int i = 0; i < instrs.length; i++) { + if (instrs[i] instanceof AstLexicalAccess && ((AstLexicalAccess) instrs[i]).getAccessCount() == 0) { + if (AC != null) { + ((AstLexicalAccess) instrs[i]).setAccesses(AC); + } else { + instrs[i] = null; + } + } + } + } + + protected Context makeFileContext(Context c, CAstEntity n) { + return new FileContext((WalkContext) c, n.getName()); + } + + protected Context makeTypeContext(Context c, CAstEntity n) { + return new TypeContext((WalkContext) c, n); + } + + protected Context makeCodeContext(Context c, CAstEntity n) { + WalkContext context = (WalkContext) c; + AbstractScope scope; + if (n.getKind() == CAstEntity.SCRIPT_ENTITY) + scope = makeScriptScope(n, context.currentScope()); + else + scope = makeFunctionScope(n, context.currentScope()); + return new CodeEntityContext(context, scope, n); + } + + protected boolean enterEntity(final CAstEntity n, Context context, CAstVisitor visitor) { + if (DEBUG_TOP) + Trace.println("translating " + n.getName()); + return false; + } + + protected boolean visitFileEntity(CAstEntity n, Context context, Context fileContext, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveFileEntity(CAstEntity n, Context context, Context fileContext, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitFieldEntity(CAstEntity n, Context context, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveFieldEntity(CAstEntity n, Context context, CAstVisitor visitor) { + // Define a new field in the enclosing type, if the language we're + // processing allows such. + CAstEntity topEntity = context.top(); // better be a type + Assertions._assert(topEntity.getKind() == CAstEntity.TYPE_ENTITY, "Parent of field entity is not a type???"); + defineField(topEntity, (WalkContext) context, n); + } + + protected boolean visitTypeEntity(CAstEntity n, Context context, Context typeContext, CAstVisitor visitor) { + defineType(n, (WalkContext) context); + return false; + } + + protected void leaveTypeEntity(CAstEntity n, Context context, Context typeContext, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitFunctionEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) { + if (n.getAST() == null) // presumably abstract + declareFunction(n, (WalkContext) context); + else + initFunctionEntity(n, (WalkContext) context, (WalkContext) codeContext); + return false; + } + + protected void leaveFunctionEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) { + if (n.getAST() != null) // non-abstract + closeFunctionEntity(n, (WalkContext) context, (WalkContext) codeContext); + } + + protected boolean visitScriptEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) { + declareFunction(n, (WalkContext) codeContext); + initFunctionEntity(n, (WalkContext) context, (WalkContext) codeContext); + return false; + } + + protected void leaveScriptEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) { + closeFunctionEntity(n, (WalkContext) context, (WalkContext) codeContext); + } + + public void initFunctionEntity(final CAstEntity n, WalkContext parentContext, WalkContext functionContext) { + // entry block + functionContext.cfg().makeEntryBlock(functionContext.cfg().newBlock(false)); + // first real block + functionContext.cfg().newBlock(true); + // prologue code, if any + doPrologue(functionContext); + } + + public void closeFunctionEntity(final CAstEntity n, WalkContext parentContext, WalkContext functionContext) { + // exit block + functionContext.cfg().makeExitBlock(functionContext.cfg().newBlock(true)); + + // create code entry stuff for this entity + SymbolTable symtab = ((AbstractScope) functionContext.currentScope()).getUnderlyingSymtab(); + TypeReference[][] catchTypes = functionContext.getCatchTypes(); + AbstractCFG cfg = new AstCFG(n, functionContext.cfg(), symtab); + Position[] line = functionContext.cfg().getLinePositionMap(); + boolean katch = functionContext.cfg().hasCatchBlock(); + String[] nms = makeNameMap(functionContext.entityScopes()); + + /* + Set reachableBlocks = + DFS.getReachableNodes(cfg, Collections.singleton(cfg.entry())); + Assertions._assert(reachableBlocks.size() == cfg.getNumberOfNodes(), + cfg.toString()); + */ + + // (put here to allow subclasses to handle stuff in scoped entities) + + // assemble lexical information + patchLexicalAccesses(cfg.getInstructions(), (Set) accesses.get(n)); + LexicalInformation LI = + // TODO: Ask Julian if the below change is always correct + new AstLexicalInformation((AbstractScope) functionContext.currentScope(), cfg.getInstructions(), (Set) exposedNames.get(n), + (Set) accesses.get(n)); + + DebuggingInformation DBG = new AstDebuggingInformation(line, nms); + + // actually make code body + defineFunction(n, parentContext, cfg, symtab, katch, catchTypes, LI, DBG); + } + + private final Stack positions = new Stack(); + + protected Context makeLocalContext(Context context, CAstNode n) { + return new LocalContext((WalkContext) context, makeLocalScope(n, ((WalkContext) context).currentScope())); + } + + protected Context makeUnwindContext(Context context, CAstNode n, CAstVisitor visitor) { + return new UnwindContext(n, (WalkContext) context, visitor); + } + + // FIXME: should it be possible to override visit() instead to do the below + // and then call super.visit? + private Map popPositionM = new LinkedHashMap(); + + protected boolean enterNode(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + boolean popPosition = false; + if (context.getSourceMap() != null) { + CAstSourcePositionMap.Position p = context.getSourceMap().getPosition(n); + if (p != null) { + if (context.cfg().getCurrentPosition() != null) { + positions.push(context.cfg().getCurrentPosition()); + popPosition = true; + } + + context.cfg().setCurrentPosition(p); + } + } + + if (popPosition) + popPositionM.put(n, Boolean.TRUE); + return false; + } + + protected void postProcessNode(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + if (popPositionM.get(n) != null) { + context.cfg().setCurrentPosition((Position) positions.pop()); + } + } + + protected int processFunctionExpr(CAstNode n, Context c) { + WalkContext context = (WalkContext) c; + CAstEntity fn = (CAstEntity) n.getChild(0).getValue(); + declareFunction(fn, context); + int result = context.currentScope().allocateTempValue(); + int ex = context.currentScope().allocateTempValue(); + doMaterializeFunction(context, result, ex, fn); + return result; + } + + protected boolean visitFunctionExpr(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveFunctionExpr(CAstNode n, Context c, CAstVisitor visitor) { + int result = processFunctionExpr(n, c); + setValue(n, result); + } + + protected boolean visitFunctionStmt(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveFunctionStmt(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = processFunctionExpr(n, c); + CAstEntity fn = (CAstEntity) n.getChild(0).getValue(); + // FIXME: handle redefinitions of functions + if (! context.currentScope().contains(fn.getName())) { + context.currentScope().declare(fn.getName(), true, false, result); + } + } + + protected boolean visitLocalScope(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveLocalScope(CAstNode n, Context c, CAstVisitor visitor) { + setValue(n, getValue(n.getChild(0))); + } + + protected boolean visitBlockExpr(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveBlockExpr(CAstNode n, Context c, CAstVisitor visitor) { + setValue(n, getValue(n.getChild(n.getChildCount() - 1))); + } + + protected boolean visitBlockStmt(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveBlockStmt(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitLoop(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + // loop test block + context.cfg().newBlock(true); + PreBasicBlock headerB = context.cfg().getCurrentBlock(); + visitor.visit(n.getChild(0), context, visitor); + + Assertions._assert(getValue(n.getChild(0)) != -1, "error in loop test " + + CAstPrinter.print(n.getChild(0), context.top().getSourceMap()) + " of loop " + + CAstPrinter.print(n, context.top().getSourceMap())); + context.cfg().addInstruction( + SSAInstructionFactory.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, getValue(n + .getChild(0)), context.currentScope().getConstantValue(new Integer(0)))); + PreBasicBlock branchB = context.cfg().getCurrentBlock(); + + // loop body + context.cfg().newBlock(true); + visitor.visit(n.getChild(1), context, visitor); + if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { + context.cfg().addInstruction(SSAInstructionFactory.GotoInstruction()); + PreBasicBlock bodyB = context.cfg().getCurrentBlock(); + context.cfg().addEdge(bodyB, headerB); + + // next block + context.cfg().newBlock(false); + } + + PreBasicBlock nextB = context.cfg().getCurrentBlock(); + + // control flow mapping; + context.cfg().addEdge(branchB, nextB); + return true; + } + + // Make final to prevent overriding + protected final void leaveLoopHeader(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveLoop(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitGetCaughtException(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveGetCaughtException(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + String nm = (String) n.getChild(0).getValue(); + context.currentScope().declare(nm, true, false); + context.cfg().addInstruction( + SSAInstructionFactory.GetCaughtExceptionInstruction(context.cfg().getCurrentBlock().getNumber(), context.currentScope() + .lookup(nm).valueNumber())); + } + + protected boolean visitThis(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveThis(CAstNode n, Context c, CAstVisitor visitor) { + setValue(n, 1); + } + + protected boolean visitSuper(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveSuper(CAstNode n, Context c, CAstVisitor visitor) { + setValue(n, 1); + } + + protected boolean visitCall(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + setValue(n, result); + return false; + } + + protected void leaveCall(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = getValue(n); + int exp = context.currentScope().allocateTempValue(); + int fun = getValue(n.getChild(0)); + CAstNode functionName = n.getChild(1); + int[] args = new int[n.getChildCount() - 2]; + for (int i = 0; i < args.length; i++) { + args[i] = getValue(n.getChild(i + 2)); + } + doCall(context, n, result, exp, functionName, fun, args); + } + + protected boolean visitVar(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveVar(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + String nm = (String) n.getChild(0).getValue(); + Symbol s = context.currentScope().lookup(nm); + if (context.currentScope().isGlobal(s)) { + setValue(n, doGlobalRead(context, nm)); + } else if (context.currentScope().isLexicallyScoped(s)) { + setValue(n, doLexicallyScopedRead(context, nm)); + } else { + setValue(n, doLocalRead(context, nm)); + } + } + + protected boolean visitConstant(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveConstant(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + setValue(n, context.currentScope().getConstantValue(n.getValue())); + } + + protected boolean visitBinaryExpr(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + setValue(n, result); + return false; + } + + protected void leaveBinaryExpr(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = getValue(n); + CAstNode l = n.getChild(1); + CAstNode r = n.getChild(2); + Assertions._assert(getValue(r) != -1, CAstPrinter.print(n)); + Assertions._assert(getValue(l) != -1, CAstPrinter.print(n)); + context.cfg().addInstruction( + SSAInstructionFactory.BinaryOpInstruction(translateBinaryOpcode(n.getChild(0)), result, getValue(l), getValue(r))); + } + + protected boolean visitUnaryExpr(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + setValue(n, result); + return false; + } + + protected void leaveUnaryExpr(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = getValue(n); + CAstNode v = n.getChild(1); + context.cfg() + .addInstruction(SSAInstructionFactory.UnaryOpInstruction(translateUnaryOpcode(n.getChild(0)), result, getValue(v))); + } + + protected boolean visitArrayLength(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + setValue(n, result); + return false; + } + + protected void leaveArrayLength(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = getValue(n); + int arrayValue = getValue(n.getChild(0)); + context.cfg().addInstruction(SSAInstructionFactory.ArrayLengthInstruction(result, arrayValue)); + } + + protected boolean visitArrayRef(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveArrayRef(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int arrayValue = getValue(n.getChild(0)); + int result = context.currentScope().allocateTempValue(); + setValue(n, result); + doArrayRead(context, result, arrayValue, n, gatherArrayDims(n)); + } + + protected boolean visitDeclStmt(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + // TODO: should we handle exploded declaration nodes here instead? + protected void leaveDeclStmt(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + String nm = (String) n.getChild(0).getChild(0).getValue(); + Boolean isFinal = (Boolean) n.getChild(1).getValue(); + Boolean isCaseInsensitive = (Boolean) n.getChild(2).getValue(); + Scope scope = context.currentScope(); + if (n.getChildCount() == 4) { + CAstNode v = n.getChild(3); + if (scope.contains(nm) && scope.lookup(nm).getDefiningScope() == scope) { + Assertions._assert(isFinal.equals(Boolean.FALSE)); + context.cfg().addInstruction(new AssignInstruction(scope.lookup(nm).valueNumber(), getValue(v))); + } else if (v.getKind() != CAstNode.CONSTANT && v.getKind() != CAstNode.VAR && v.getKind() != CAstNode.THIS) { + scope.declare(nm, isFinal.booleanValue(), isCaseInsensitive.booleanValue(), getValue(v)); + } else { + scope.declare(nm, isFinal.booleanValue(), isCaseInsensitive.booleanValue()); + context.cfg().addInstruction(new AssignInstruction(context.currentScope().lookup(nm).valueNumber(), getValue(v))); + } + } else { + context.currentScope().declare(nm, isFinal.booleanValue(), isCaseInsensitive.booleanValue()); + } + } + + protected boolean visitReturn(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveReturn(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + if (n.getChildCount() > 0) { + context.cfg().addInstruction(SSAInstructionFactory.ReturnInstruction(getValue(n.getChild(0)), false)); + } else { + context.cfg().addInstruction(SSAInstructionFactory.ReturnInstruction()); + } + + context.cfg().addPreNode(n, context.getUnwindState()); + context.cfg().newBlock(false); + context.cfg().addPreEdgeToExit(n, false); + } + + protected boolean visitIfgoto(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveIfgoto(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + if (n.getChildCount() == 1) { + context.cfg().addInstruction( + SSAInstructionFactory.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_NE), null, getValue(n + .getChild(0)), context.currentScope().getConstantValue(new Integer(0)))); + } else if (n.getChildCount() == 3) { + context.cfg().addInstruction( + SSAInstructionFactory.ConditionalBranchInstruction(translateConditionOpcode(n.getChild(0)), null, + getValue(n.getChild(1)), getValue(n.getChild(2)))); + } else { + Assertions.UNREACHABLE(); + } + + context.cfg().addPreNode(n, context.getUnwindState()); + context.cfg().newBlock(true); + context.cfg().addPreEdge(n, context.getControlFlow().getTarget(n, Boolean.TRUE), false); + } + + protected boolean visitGoto(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveGoto(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + context.cfg().addPreNode(n, context.getUnwindState()); + context.cfg().addInstruction(SSAInstructionFactory.GotoInstruction()); + context.cfg().newBlock(false); + context.cfg().addPreEdge(n, context.getControlFlow().getTarget(n, null), false); + } + + protected boolean visitLabelStmt(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + if (!context.getControlFlow().getSourceNodes(n).isEmpty()) { + context.cfg().newBlock(true); + context.cfg().addPreNode(n, context.getUnwindState()); + } + return false; + } + + protected void leaveLabelStmt(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected void processIf(CAstNode n, boolean isExpr, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + PreBasicBlock trueB = null, falseB = null; + // conditional + CAstNode l = n.getChild(0); + visitor.visit(l, context, visitor); + context.cfg().addInstruction( + SSAInstructionFactory.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, getValue(l), context + .currentScope().getConstantValue(new Integer(0)))); + PreBasicBlock srcB = context.cfg().getCurrentBlock(); + // true clause + context.cfg().newBlock(true); + CAstNode r = n.getChild(1); + walkNodes(r, context); + if (isExpr) + context.cfg().addInstruction(new AssignInstruction(getValue(n), getValue(r))); + if (n.getChildCount() == 3) { + if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { + context.cfg().addInstruction(SSAInstructionFactory.GotoInstruction()); + trueB = context.cfg().getCurrentBlock(); + + // false clause + context.cfg().newBlock(false); + } + + falseB = context.cfg().getCurrentBlock(); + CAstNode f = n.getChild(2); + visitor.visit(f, context, visitor); + if (isExpr) + context.cfg().addInstruction(new AssignInstruction(getValue(n), getValue(f))); + } + + // end + context.cfg().newBlock(true); + if (n.getChildCount() == 3) { + if (trueB != null) + context.cfg().addEdge(trueB, context.cfg().getCurrentBlock()); + context.cfg().addEdge(srcB, falseB); + } else { + context.cfg().addEdge(srcB, context.cfg().getCurrentBlock()); + } + } + + // Make final to prevent overriding + protected final void leaveIfStmtCondition(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveIfStmtTrueClause(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveIfStmt(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveIfExprCondition(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveIfExprTrueClause(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveIfExpr(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitIfStmt(CAstNode n, Context c, CAstVisitor visitor) { + processIf(n, false, c, visitor); + return true; + } + + protected boolean visitIfExpr(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + setValue(n, result); + processIf(n, true, c, visitor); + return true; + } + + protected boolean visitNew(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveNew(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + + int result = context.currentScope().allocateTempValue(); + setValue(n, result); + + int[] arguments; + if (n.getChildCount() <= 1) { + arguments = null; + } else { + arguments = new int[n.getChildCount() - 1]; + for (int i = 1; i < n.getChildCount(); i++) { + arguments[i - 1] = getValue(n.getChild(i)); + } + } + doNewObject(context, n, result, n.getChild(0).getValue(), arguments); + } + + protected boolean visitObjectLiteral(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveObjectLiteralFieldInit(CAstNode n, int i, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + if (n.getChild(i).getKind() == CAstNode.EMPTY) { + handleUnspecifiedLiteralKey(context, n, i, visitor); + } + doFieldWrite(context, getValue(n.getChild(0)), n.getChild(i), n, getValue(n.getChild(i + 1))); + } + + protected void leaveObjectLiteral(CAstNode n, Context c, CAstVisitor visitor) { + setValue(n, getValue(n.getChild(0))); + } + + protected boolean visitArrayLiteral(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveArrayLiteralObject(CAstNode n, Context c, CAstVisitor visitor) { + setValue(n, getValue(n.getChild(0))); + } + + protected void leaveArrayLiteralInitElement(CAstNode n, int i, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + doArrayWrite(context, getValue(n.getChild(0)), n, new int[] { context.currentScope().getConstantValue(new Integer(i - 1)) }, + getValue(n.getChild(i))); + } + + protected void leaveArrayLiteral(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitObjectRef(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + setValue(n, result); + return false; + } + + protected void leaveObjectRef(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = getValue(n); + CAstNode elt = n.getChild(1); + doFieldRead(context, result, getValue(n.getChild(0)), elt, n); + } + + public boolean visitAssign(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + public void leaveAssign(CAstNode n, Context c, CAstVisitor visitor) { + if (n.getKind() == CAstNode.ASSIGN) { + setValue(n, getValue(n.getChild(1))); + } else { + setValue(n, getValue(n.getChild(0))); + } + } + + private int[] gatherArrayDims(CAstNode n) { + int numDims = n.getChildCount() - 2; + int[] dims = new int[numDims]; + for (int i = 0; i < numDims; i++) + dims[i] = getValue(n.getChild(i + 2)); + return dims; + } + + /* Prereq: a.getKind() == ASSIGN_PRE_OP || a.getKind() == ASSIGN_POST_OP */ + protected int processAssignOp(CAstNode n, CAstNode v, CAstNode a, int temp, boolean post, Context c) { + WalkContext context = (WalkContext) c; + int rval = getValue(v); + CAstNode op = a.getChild(2); + int temp2 = context.currentScope().allocateTempValue(); + context.cfg().addInstruction(SSAInstructionFactory.BinaryOpInstruction(translateBinaryOpcode(op), temp2, temp, rval)); + return temp2; + } + + protected boolean visitArrayRefAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveArrayRefAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int rval = getValue(v); + setValue(n, rval); + doArrayWrite(context, getValue(n.getChild(0)), n, gatherArrayDims(n), rval); + } + + protected boolean visitArrayRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveArrayRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int temp = context.currentScope().allocateTempValue(); + int[] dims = gatherArrayDims(n); + doArrayRead(context, temp, getValue(n.getChild(0)), n, dims); + int rval = processAssignOp(n, v, a, temp, !pre, c); + setValue(n, pre? rval: temp); + doArrayWrite(context, getValue(n.getChild(0)), n, dims, rval); + } + + protected boolean visitObjectRefAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveObjectRefAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int rval = getValue(v); + setValue(n, rval); + doFieldWrite(context, getValue(n.getChild(0)), n.getChild(1), n, rval); + } + + protected void processObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, Context c) { + } + + protected boolean visitObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int temp = context.currentScope().allocateTempValue(); + doFieldRead(context, temp, getValue(n.getChild(0)), n.getChild(1), n); + int rval = processAssignOp(n, v, a, temp, !pre, c); + setValue(n, pre? rval: temp); + doFieldWrite(context, getValue(n.getChild(0)), n.getChild(1), n, rval); + } + + protected boolean visitBlockExprAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveBlockExprAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { + setValue(n, getValue(n.getChild(n.getChildCount() - 1))); + } + + protected boolean visitBlockExprAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveBlockExprAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ + setValue(n, getValue(n.getChild(n.getChildCount() - 1))); + } + + protected boolean visitVarAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveVarAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int rval = getValue(v); + String nm = (String) n.getChild(0).getValue(); + Symbol ls = context.currentScope().lookup(nm); + setValue(n, rval); + if (context.currentScope().isGlobal(ls)) + doGlobalWrite(context, nm, rval); + else if (context.currentScope().isLexicallyScoped(ls)) { + doLexicallyScopedWrite(context, nm, rval); + } else { + Assertions._assert(rval != -1, + CAstPrinter.print(n, c.top().getSourceMap())); + doLocalWrite(context, nm, rval); + } + } + + protected boolean visitVarAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveVarAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + String nm = (String) n.getChild(0).getValue(); + Symbol ls = context.currentScope().lookup(nm); + int temp; + + if (context.currentScope().isGlobal(ls)) + temp = doGlobalRead(context, nm); + else if (context.currentScope().isLexicallyScoped(ls)) { + temp = doLexicallyScopedRead(context, nm); + } else { + temp = doLocalRead(context, nm); + } + + if (!pre) { + int ret = context.currentScope().allocateTempValue(); + context.cfg().addInstruction(new AssignInstruction(ret, temp)); + setValue(n, ret); + } + + int rval = processAssignOp(n, v, a, temp, !pre, c); + + if (pre) { + setValue(n, rval); + } + + if (context.currentScope().isGlobal(ls)) { + doGlobalWrite(context, nm, rval); + } else if (context.currentScope().isLexicallyScoped(ls)) { + doLexicallyScopedWrite(context, nm, rval); + } else { + doLocalWrite(context, nm, rval); + } + } + + private boolean isSimpleSwitch(CAstNode n, WalkContext context, CAstVisitor visitor) { + CAstControlFlowMap ctrl = context.getControlFlow(); + Collection caseLabels = ctrl.getTargetLabels(n); + for (Iterator kases = caseLabels.iterator(); kases.hasNext();) { + Object x = kases.next(); + + if (x == CAstControlFlowMap.SWITCH_DEFAULT) + continue; + + CAstNode xn = (CAstNode) x; + if (xn.getKind() == CAstNode.CONSTANT) { + visitor.visit(xn, context, visitor); + if (getValue(xn) != -1) { + if (context.currentScope().isConstant(getValue(xn))) { + Object val = context.currentScope().getConstantObject(getValue(xn)); + if (val instanceof Number) { + Number num = (Number) val; + if ((double) num.intValue() == num.doubleValue()) { + continue; + } + } + } + } + } + + return false; + } + + return true; + } + + private void doSimpleSwitch(CAstNode n, WalkContext context, CAstVisitor visitor) { + PreBasicBlock defaultHackBlock = null; + CAstControlFlowMap ctrl = context.getControlFlow(); + context.cfg().addPreNode(n, context.getUnwindState()); + + CAstNode switchValue = n.getChild(0); + visitor.visit(switchValue, context, visitor); + int v = getValue(switchValue); + + boolean hasExplicitDefault = ctrl.getTarget(n, CAstControlFlowMap.SWITCH_DEFAULT) != null; + + Collection caseLabels = ctrl.getTargetLabels(n); + int cases = caseLabels.size(); + if (hasExplicitDefault) + cases--; + int[] casesAndLabels = new int[cases * 2]; + + int defaultBlock = context.cfg().getCurrentBlock().getGraphNodeId() + 1; + + context.cfg().addInstruction(SSAInstructionFactory.SwitchInstruction(v, defaultBlock, casesAndLabels)); + // PreBasicBlock switchB = context.cfg().getCurrentBlock(); + context.cfg().newBlock(true); + + if (hasExplicitDefault) { + context.cfg().addInstruction(SSAInstructionFactory.GotoInstruction()); + defaultHackBlock = context.cfg().getCurrentBlock(); + context.cfg().newBlock(false); + } + + CAstNode switchBody = n.getChild(1); + visitor.visit(switchBody, context, visitor); + context.cfg().newBlock(true); + + int cn = 0; + for (Iterator kases = caseLabels.iterator(); kases.hasNext();) { + Object x = kases.next(); + CAstNode target = ctrl.getTarget(n, x); + if (x == CAstControlFlowMap.SWITCH_DEFAULT) { + context.cfg().addEdge(defaultHackBlock, context.cfg().getBlock(target)); + } else { + Number caseLabel = (Number) context.currentScope().getConstantObject(getValue((CAstNode) x)); + casesAndLabels[2 * cn] = caseLabel.intValue(); + casesAndLabels[2 * cn + 1] = context.cfg().getBlock(target).getGraphNodeId(); + cn++; + + context.cfg().addPreEdge(n, target, false); + } + } + } + + private void doIfConvertSwitch(CAstNode n, WalkContext context, CAstVisitor visitor) { + CAstControlFlowMap ctrl = context.getControlFlow(); + context.cfg().addPreNode(n, context.getUnwindState()); + + CAstNode switchValue = n.getChild(0); + visitor.visit(switchValue, context, visitor); + int v = getValue(switchValue); + + Collection caseLabels = ctrl.getTargetLabels(n); + Map labelToBlock = new LinkedHashMap(); + for (Iterator kases = caseLabels.iterator(); kases.hasNext();) { + Object x = kases.next(); + if (x != CAstControlFlowMap.SWITCH_DEFAULT) { + walkNodes((CAstNode) x, context); + context.cfg().addInstruction( + SSAInstructionFactory.ConditionalBranchInstruction(translateConditionOpcode(CAstOperator.OP_EQ), null, v, + getValue((CAstNode) x))); + labelToBlock.put(x, context.cfg().getCurrentBlock()); + context.cfg().newBlock(true); + } + } + + PreBasicBlock defaultGotoBlock = context.cfg().getCurrentBlock(); + context.cfg().addInstruction(SSAInstructionFactory.GotoInstruction()); + context.cfg().newBlock(false); + + CAstNode switchBody = n.getChild(1); + visitor.visit(switchBody, context, visitor); + context.cfg().newBlock(true); + + PreBasicBlock nextBlock = context.cfg().getCurrentBlock(); + for (Iterator kases = caseLabels.iterator(); kases.hasNext();) { + Object x = kases.next(); + if (x != CAstControlFlowMap.SWITCH_DEFAULT) { + CAstNode target = ctrl.getTarget(n, x); + context.cfg().addEdge(labelToBlock.get(x), context.cfg().getBlock(target)); + } + } + + if (ctrl.getTarget(n, CAstControlFlowMap.SWITCH_DEFAULT) == null) { + context.cfg().addEdge(defaultGotoBlock, context.cfg().getCurrentBlock()); + } else { + CAstNode target = ctrl.getTarget(n, CAstControlFlowMap.SWITCH_DEFAULT); + context.cfg().addEdge(defaultGotoBlock, context.cfg().getBlock(target)); + } + } + + protected boolean visitSwitch(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + if (isSimpleSwitch(n, context, visitor)) { + doSimpleSwitch(n, context, visitor); + } else { + doIfConvertSwitch(n, context, visitor); + } + return true; + } + + // Make final to prevent overriding + protected final void leaveSwitchValue(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveSwitch(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitThrow(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveThrow(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + doThrow(context, getValue(n.getChild(0))); + + context.cfg().addPreNode(n, context.getUnwindState()); + context.cfg().newBlock(false); + + Collection labels = context.getControlFlow().getTargetLabels(n); + for (Iterator iter = labels.iterator(); iter.hasNext();) { + Object label = iter.next(); + CAstNode target = context.getControlFlow().getTarget(n, label); + if (target == CAstControlFlowMap.EXCEPTION_TO_EXIT) + context.cfg().addPreEdgeToExit(n, true); + else + context.cfg().addPreEdge(n, target, true); + } + } + + protected boolean visitCatch(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + + // unreachable catch block + if (context.getControlFlow().getSourceNodes(n).isEmpty()) { + return true; + } + + String id = (String) n.getChild(0).getValue(); + context.cfg().setCurrentBlockAsHandler(); + if (!context.currentScope().contains(id)) { + context.currentScope().declare(id, true, false); + } + context.cfg().addInstruction( + SSAInstructionFactory.GetCaughtExceptionInstruction(context.cfg().getCurrentBlock().getNumber(), context.currentScope() + .lookup(id).valueNumber())); + + context.cfg().addPreNode(n, context.getUnwindState()); + + CAstType caughtType = getTypeForNode(context, n); + if (caughtType != null) { + TypeReference caughtRef = makeType(caughtType); + context.setCatchType(n, caughtRef); + } else { + context.setCatchType(n, defaultCatchType()); + } + + return false; + } + + protected void leaveCatch(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitUnwind(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveUnwind(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitTry(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + boolean addSkipCatchGoto = false; + visitor.visit(n.getChild(0), context, visitor); + PreBasicBlock endOfTry = context.cfg().getCurrentBlock(); + + if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { + addSkipCatchGoto = true; + ; + context.cfg().addInstruction(SSAInstructionFactory.GotoInstruction()); + context.cfg().newBlock(false); + } + + context.cfg().noteCatchBlock(); + visitor.visit(n.getChild(1), context, visitor); + + if (!context.cfg().isDeadBlock(context.cfg().getCurrentBlock())) { + context.cfg().newBlock(true); + } + + if (addSkipCatchGoto) { + PreBasicBlock afterBlock = context.cfg().getCurrentBlock(); + context.cfg().addEdge(endOfTry, afterBlock); + } + return true; + } + + // Make final to prevent overriding + protected final void leaveTryBlock(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected final void leaveTry(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + } + + protected boolean visitEmpty(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveEmpty(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + setValue(n, context.currentScope().getConstantValue(null)); + } + + protected boolean visitPrimitive(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leavePrimitive(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + int result = context.currentScope().allocateTempValue(); + setValue(n, result); + + doPrimitive(result, context, n); + } + + protected boolean visitVoid(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveVoid(CAstNode n, Context c, CAstVisitor visitor) { + setValue(n, -1); + } + + protected boolean visitAssert(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ + return false; + } + + protected void leaveAssert(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext context = (WalkContext) c; + boolean fromSpec = true; + int result = getValue(n.getChild(0)); + if (n.getChildCount() == 2) { + Assertions._assert(n.getChild(1).getKind() == CAstNode.CONSTANT); + Assertions._assert(n.getChild(1).getValue() instanceof Boolean); + fromSpec = n.getChild(1).getValue().equals(Boolean.TRUE); + } + context.cfg().addInstruction(new AstAssertInstruction(result, fromSpec)); + } + + protected boolean visitEachElementGet(CAstNode n, Context c, CAstVisitor visitor) { + return false; + } + + protected void leaveEachElementGet(CAstNode n, Context c, CAstVisitor visitor) { + int result = ((WalkContext) c).currentScope().allocateTempValue(); + setValue(n, result); + ((WalkContext) c).cfg().addInstruction(new EachElementGetInstruction(result, getValue(n.getChild(0)))); + } + + protected boolean visitEachElementHasNext(CAstNode n, Context c, CAstVisitor visitor) { + return false; + } + + protected void leaveEachElementHasNext(CAstNode n, Context c, CAstVisitor visitor) { + int result = ((WalkContext) c).currentScope().allocateTempValue(); + setValue(n, result); + ((WalkContext) c).cfg().addInstruction(new EachElementHasNextInstruction(result, getValue(n.getChild(0)))); + } + + protected boolean visitTypeLiteralExpr(CAstNode n, Context c, CAstVisitor visitor) { + return false; + } + + protected void leaveTypeLiteralExpr(CAstNode n, Context c, CAstVisitor visitor) { + WalkContext wc = (WalkContext)c; + Assertions._assert(n.getChild(0).getKind() == CAstNode.CONSTANT); + String typeNameStr = (String) n.getChild(0).getValue(); + TypeName typeName = TypeName.string2TypeName(typeNameStr); + TypeReference typeRef = + TypeReference.findOrCreate(loader.getReference(), typeName); + + int result = wc.currentScope().allocateTempValue(); + setValue(n, result); + + wc.cfg().addInstruction(new SSALoadClassInstruction(result, typeRef)); + } + + protected final void walkEntities(CAstEntity N, Context c) { + visitEntities(N, c, this); + } + + protected final void walkNodes(CAstNode N, Context c) { + visit(N, c, this); + } + + public static final class DefaultContext implements WalkContext { + private final AstTranslator t; + + private final CAstEntity N; + + private final String nm; + + public DefaultContext(AstTranslator t, CAstEntity N, String nm) { + this.t = t; + this.N = N; + this.nm = nm; + } + + public String file() { + return nm; + } + + public CAstEntity top() { + return N; + } + + public Scope currentScope() { + return t.globalScope; + } + + public Set entityScopes() { + return Collections.singleton(t.globalScope); + } + + public CAstSourcePositionMap getSourceMap() { + return N.getSourceMap(); + } + + public CAstControlFlowMap getControlFlow() { + return N.getControlFlow(); + } + + public IncipientCFG cfg() { + return null; + } + + public UnwindState getUnwindState() { + return null; + } + + public String getName() { + return null; + } + + public void setCatchType(int blockNumber, TypeReference catchType) { + } + + public void setCatchType(CAstNode castNode, TypeReference catchType) { + } + + public TypeReference[][] getCatchTypes() { + return null; + } + }; + + public void translate(final CAstEntity N, final String nm) { + if (DEBUG_TOP) + Trace.println("translating " + nm); + walkEntities(N, new DefaultContext(this, N, nm)); + } + + private final Scope globalScope = makeGlobalScope(); + + protected Scope getGlobalScope() { + return globalScope; + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/NativeBridge.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/NativeBridge.java new file mode 100644 index 000000000..4104e8c2b --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/NativeBridge.java @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.translator; + +public class NativeBridge { + + protected static native void initialize(); + + /* + * trying to modularize shared library loading like this seems to + * cause trouble on certain VMs. (guess which? :) + * + static { + System.loadLibrary("cast"); + initialize(); + } + */ + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/TranslatorToIR.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/TranslatorToIR.java new file mode 100644 index 000000000..06416619f --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ir/translator/TranslatorToIR.java @@ -0,0 +1,24 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.ir.translator; + +import com.ibm.wala.classLoader.*; + +import java.io.*; +import java.util.*; + +public interface TranslatorToIR { + + void translate(ModuleEntry S, String N) throws IOException; + + void translate(Set modules) throws IOException; + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstClass.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstClass.java new file mode 100644 index 000000000..bfb76011a --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstClass.java @@ -0,0 +1,219 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.loader; + + +import com.ibm.wala.cast.tree.*; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.cha.*; +import com.ibm.wala.shrikeCT.*; +import com.ibm.wala.types.*; +import com.ibm.wala.util.*; +import com.ibm.wala.util.debug.Assertions; + +import java.net.*; +import java.util.*; + +abstract public class AstClass implements IClass, ClassConstants { + private final CAstSourcePositionMap.Position sourcePosition; + private final TypeName typeName; + private final IClassLoader loader; + private final short modifiers; + protected final Map declaredFields; + protected final Map declaredMethods; + + protected AstClass(CAstSourcePositionMap.Position sourcePosition, + TypeName typeName, + IClassLoader loader, + short modifiers, + Map declaredFields, + Map declaredMethods) + { + this.sourcePosition = sourcePosition; + this.typeName = typeName; + this.loader = loader; + this.modifiers = modifiers; + this.declaredFields = declaredFields; + this.declaredMethods = declaredMethods; + } + + public boolean isInterface() { + return (modifiers&ACC_INTERFACE) != 0; + } + + public boolean isAbstract() { + return (modifiers&ACC_ABSTRACT) != 0; + } + + public boolean isPublic() { + return (modifiers&ACC_PUBLIC) != 0; + } + + public boolean isReferenceType() { + return true; + } + + public boolean isArrayClass() { + return false; + } + + public int getModifiers() { + return modifiers; + } + + public CAstSourcePositionMap.Position getSourcePosition() { + return sourcePosition; + } + + public URL getSourceURL() { + return sourcePosition.getURL(); + } + + public String getSourceFileName() { + return sourcePosition.getURL().getFile(); + } + + public TypeName getName() { + return typeName; + } + + public TypeReference getReference() { + return TypeReference.findOrCreate(loader.getReference(), typeName); + } + + public IClassLoader getClassLoader() { + return loader; + } + + public abstract IClass getSuperclass() throws ClassHierarchyException; + + private Collection gatherInterfaces() throws ClassHierarchyException { + Set result = new HashSet(); + result.addAll( getDirectInterfaces() ); + if (getSuperclass() != null) + result.addAll( getSuperclass().getAllImplementedInterfaces() ); + return result; + } + + public abstract Collection getDirectInterfaces() throws ClassHierarchyException; + + public Collection getAllImplementedInterfaces() throws ClassHierarchyException { + Assertions._assert(! isInterface()); + return gatherInterfaces(); + } + + public Collection getAllAncestorInterfaces() throws ClassHierarchyException { + Assertions._assert(isInterface()); + return gatherInterfaces(); + } + + public IMethod getClassInitializer() { + return getMethod( MethodReference.clinitSelector ); + } + + public IMethod getMethod(Selector selector) { + try { + if (declaredMethods.containsKey(selector)) { + return (IMethod)declaredMethods.get(selector); + } else if (getSuperclass() != null) { + return getSuperclass().getMethod(selector); + } else { + return null; + } + } catch (ClassHierarchyException e) { + Assertions.UNREACHABLE(); + return null; + } + } + + public IField getField(Atom name) { + try { + if (declaredFields.containsKey(name)) { + return (IField)declaredFields.get(name); + } else if (getSuperclass() != null) { + return getSuperclass().getField(name); + } else { + return null; + } + } catch (ClassHierarchyException e) { + Assertions.UNREACHABLE(); + return null; + } + } + + public Collection getDeclaredMethods() { + return declaredMethods.values(); + } + + public Collection getDeclaredInstanceFields() { + Set result = new HashSet(); + for(Iterator FS = declaredFields.values().iterator(); FS.hasNext();) { + IField F = (IField) FS.next(); + if (! F.isStatic()) { + result.add( F ); + } + } + + return result; + } + + public Collection getDeclaredStaticFields() { + Set result = new HashSet(); + for(Iterator FS = declaredFields.values().iterator(); FS.hasNext();) { + IField F = (IField) FS.next(); + if (F.isStatic()) { + result.add( F ); + } + } + + return result; + } + + public Collection getAllInstanceFields() throws ClassHierarchyException { + Collection result = new HashSet(); + result.addAll( getDeclaredInstanceFields() ); + if (getSuperclass() != null) { + result.addAll( getSuperclass().getAllInstanceFields() ); + } + + return result; + } + + public Collection getAllStaticFields() throws ClassHierarchyException { + Collection result = new HashSet(); + result.addAll( getDeclaredStaticFields() ); + if (getSuperclass() != null) { + result.addAll( getSuperclass().getAllStaticFields() ); + } + + return result; + } + + public Collection getAllFields() throws ClassHierarchyException { + Collection result = new HashSet(); + result.addAll( getAllInstanceFields() ); + result.addAll( getAllStaticFields() ); + return result; + } + + public Collection getAllMethods() throws ClassHierarchyException { + Collection result = new HashSet(); + for(Iterator ms = getDeclaredMethods().iterator(); ms.hasNext(); ) { + result.add( ms.next() ); + } + if (getSuperclass() != null) { + result.addAll( getSuperclass().getAllMethods() ); + } + + return result; + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstDynamicPropertyClass.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstDynamicPropertyClass.java new file mode 100644 index 000000000..3927e7ddb --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstDynamicPropertyClass.java @@ -0,0 +1,103 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.loader; + + +import com.ibm.wala.cast.tree.*; +import com.ibm.wala.cast.types.*; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.cha.*; +import com.ibm.wala.types.*; +import com.ibm.wala.util.Atom; +import com.ibm.wala.util.collections.*; +import com.ibm.wala.util.debug.Assertions; + +import java.util.*; + +public abstract class AstDynamicPropertyClass extends AstClass { + private final TypeReference defaultDescriptor; + + protected AstDynamicPropertyClass(CAstSourcePositionMap.Position sourcePosition, TypeName typeName, IClassLoader loader, short modifiers, Map declaredMethods, TypeReference defaultDescriptor) { + super(sourcePosition, typeName, loader, modifiers, new HashMap(), declaredMethods); + this.defaultDescriptor = defaultDescriptor; + } + + public IField getField(final Atom name) { + try { + if (declaredFields.containsKey(name)) { + return (IField) declaredFields.get(name); + } else if (getSuperclass() != null) { + return getSuperclass().getField(name); + } else { + final boolean isStatic = isStaticField(name); + declaredFields.put(name, new IField() { + public String toString() { + return ""; + } + + public IClass getDeclaringClass() { + return AstDynamicPropertyClass.this; + } + + public Atom getName() { + return name; + } + + public TypeReference getFieldTypeReference() { + return defaultDescriptor; + } + + public FieldReference getFieldReference() { + return FieldReference.findOrCreate(AstDynamicPropertyClass.this.getReference(), name, defaultDescriptor); + } + + public boolean isFinal() { + return false; + } + + public boolean isPrivate() { + return false; + } + + public boolean isProtected() { + return false; + } + + public boolean isPublic() { + return false; + } + + public boolean isVolatile() { + return false; + } + + public boolean isStatic() { + return isStatic; + } + + public ClassHierarchy getClassHierarchy() { + return AstDynamicPropertyClass.this.getClassHierarchy(); + } + }); + + return (IField) declaredFields.get(name); + } + } catch (ClassHierarchyException e) { + Assertions.UNREACHABLE(); + return null; + } + } + + protected boolean isStaticField(Atom name) { + return name.toString().startsWith("global "); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstField.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstField.java new file mode 100644 index 000000000..64cda897e --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstField.java @@ -0,0 +1,87 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.loader; + + +import com.ibm.wala.cast.tree.*; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.types.*; +import com.ibm.wala.util.Atom; +import com.ibm.wala.util.debug.Assertions; + +import java.util.*; + +public class AstField implements IField { + private final Collection qualifiers; + private final FieldReference ref; + private final IClass declaringClass; + private final ClassHierarchy cha; + + public AstField(FieldReference ref, + Collection qualifiers, + IClass declaringClass, + ClassHierarchy cha) + { + this.declaringClass = declaringClass; + this.qualifiers = qualifiers; + this.ref = ref; + this.cha = cha; + } + + public IClass getDeclaringClass() { + return declaringClass; + } + + public String toString() { + return "field " + ref.getName(); + } + + public Atom getName() { + return ref.getName(); + } + + public TypeReference getFieldTypeReference() { + return ref.getFieldType(); + } + + public FieldReference getFieldReference() { + return ref; + } + + public boolean isStatic() { + return qualifiers.contains(CAstQualifier.STATIC); + } + + public boolean isFinal() { + return qualifiers.contains(CAstQualifier.CONST); + } + + public boolean isPrivate() { + return qualifiers.contains(CAstQualifier.PRIVATE); + } + + public boolean isProtected() { + return qualifiers.contains(CAstQualifier.PROTECTED); + } + + public boolean isPublic() { + return qualifiers.contains(CAstQualifier.PUBLIC); + } + + public boolean isVolatile() { + return qualifiers.contains(CAstQualifier.VOLATILE); + } + + public ClassHierarchy getClassHierarchy() { + return cha; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstFunctionClass.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstFunctionClass.java new file mode 100644 index 000000000..d45206b71 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstFunctionClass.java @@ -0,0 +1,166 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.loader; + + +import com.ibm.wala.cast.tree.*; +import com.ibm.wala.cast.types.*; +import com.ibm.wala.classLoader.*; +import com.ibm.wala.ipa.cha.*; +import com.ibm.wala.shrikeCT.*; +import com.ibm.wala.types.*; +import com.ibm.wala.util.Atom; +import com.ibm.wala.util.collections.*; +import com.ibm.wala.util.debug.Assertions; + +import java.net.*; +import java.util.*; + +abstract public class AstFunctionClass implements IClass, ClassConstants { + private final IClassLoader loader; + + protected IMethod functionBody; + + private final CAstSourcePositionMap.Position sourcePosition; + + private final TypeReference reference; + + private final TypeReference superReference; + + protected AstFunctionClass(TypeReference reference, TypeReference superReference, IClassLoader loader, + CAstSourcePositionMap.Position sourcePosition) { + this.superReference = superReference; + this.sourcePosition = sourcePosition; + this.reference = reference; + this.loader = loader; + } + + protected AstFunctionClass(TypeReference reference, IClassLoader loader, CAstSourcePositionMap.Position sourcePosition) { + this(reference, TypeReference.findOrCreate(reference.getClassLoader(), AstTypeReference.functionTypeName), loader, + sourcePosition); + } + + public String toString() { + return "function " + functionBody.getReference().getDeclaringClass().getName(); + } + + public IClassLoader getClassLoader() { + return loader; + } + + public boolean isInterface() { + return false; + } + + public boolean isAbstract() { + return false; + } + + public boolean isPublic() { + return true; + } + + public int getModifiers() { + return ACC_PUBLIC; + } + + public IClass getSuperclass() throws ClassHierarchyException { + return loader.lookupClass(superReference.getName(), getClassHierarchy()); + } + + public Collection getDirectInterfaces() { + return Collections.EMPTY_SET; + } + + public Collection getAllImplementedInterfaces() { + return Collections.EMPTY_SET; + } + + public Collection getAllAncestorInterfaces() { + return Collections.EMPTY_SET; + } + + public IMethod getMethod(Selector selector) { + if (selector.equals(AstMethodReference.fnSelector)) { + return functionBody; + } else { + return loader.lookupClass(superReference.getName(), getClassHierarchy()).getMethod(selector); + } + } + + public IField getField(Atom name) { + return loader.lookupClass(superReference.getName(), getClassHierarchy()).getField(name); + } + + public TypeReference getReference() { + return reference; + } + + public CAstSourcePositionMap.Position getSourcePosition() { + return sourcePosition; + } + + public URL getSourceURL() { + return sourcePosition.getURL(); + } + + public String getSourceFileName() { + return sourcePosition.getURL().getFile(); + } + + public IMethod getClassInitializer() { + return null; + } + + public boolean isArrayClass() { + return false; + } + + public Collection getDeclaredMethods() { + if (functionBody != null) { + return Collections.singleton(functionBody); + } else { + throw new Error("function " + reference + " has no body!"); + } + } + + public Collection getDeclaredInstanceFields() { + return Collections.EMPTY_SET; + } + + public Collection getDeclaredStaticFields() { + return Collections.EMPTY_SET; + } + + public Collection getAllInstanceFields() { + return Collections.EMPTY_SET; + } + + public Collection getAllStaticFields() { + return Collections.EMPTY_SET; + } + + public Collection getAllFields() { + return Collections.EMPTY_SET; + } + + public Collection getAllMethods() { + return Collections.singleton(functionBody); + } + + public TypeName getName() { + return reference.getName(); + } + + public boolean isReferenceType() { + return true; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstMethod.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstMethod.java new file mode 100644 index 000000000..89ea24a25 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/AstMethod.java @@ -0,0 +1,223 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.loader; + +import java.util.Collection; + +import com.ibm.wala.cast.tree.CAstQualifier; +import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; +import com.ibm.wala.cfg.AbstractCFG; +import com.ibm.wala.cfg.ControlFlowGraph; +import com.ibm.wala.classLoader.IClass; +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.ssa.SymbolTable; +import com.ibm.wala.types.Descriptor; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.types.Selector; +import com.ibm.wala.types.TypeReference; +import com.ibm.wala.util.Atom; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.debug.Assertions; + +public abstract class AstMethod implements IMethod { + + public interface DebuggingInformation { + + Position getInstructionPosition(int instructionOffset); + + String[][] getSourceNamesForValues(); + + } + + public interface LexicalInformation { + + public int[] getExitExposedUses(); + + public int[] getExposedUses(int instructionOffset); + + public Pair[] getExposedNames(); + + public String[] getScopingParents(); + + } + + public final IClass cls; + public final Collection qualifiers; + public final AbstractCFG cfg; + public final SymbolTable symtab; + public final MethodReference ref; + public final boolean hasCatchBlock; + public final TypeReference[][] catchTypes; + public final LexicalInformation lexicalInfo; + public final DebuggingInformation debugInfo; + + protected AstMethod(IClass cls, + Collection qualifiers, + AbstractCFG cfg, + SymbolTable symtab, + MethodReference ref, + boolean hasCatchBlock, + TypeReference[][] catchTypes, + LexicalInformation lexicalInfo, + DebuggingInformation debugInfo) + { + this.cls = cls; + this.cfg = cfg; + this.ref = ref; + this.symtab = symtab; + this.qualifiers = qualifiers; + this.catchTypes = catchTypes; + this.hasCatchBlock = hasCatchBlock; + this.lexicalInfo = lexicalInfo; + this.debugInfo = debugInfo; + } + + protected AstMethod(IClass cls, + Collection qualifiers, + MethodReference ref) + { + this.cls = cls; + this.qualifiers = qualifiers; + this.ref = ref; + + this.cfg = null; + this.symtab = null; + this.catchTypes = null; + this.hasCatchBlock = false; + this.lexicalInfo = null; + this.debugInfo = null; + + Assertions._assert(isAbstract()); + } + + /** + * Parents of this method with respect to lexical scoping, that is, + * methods containing state possibly referenced lexically in this + * method + */ + public abstract class LexicalParent { + public abstract String getName(); + public abstract AstMethod getMethod(); + + public int hashCode() { + return getName().hashCode()*getMethod().hashCode(); + } + + public boolean equals(Object o) { + return (o instanceof LexicalParent) && + getName().equals(((LexicalParent)o).getName()) && + getMethod().equals(((LexicalParent)o).getMethod()); + } + }; + + public abstract LexicalParent[] getParents(); + + public IClass getDeclaringClass() { + return cls; + } + + public String getSignature() { + return ref.toString(); + } + + public Selector getSelector() { + return ref.getSelector(); + } + + public boolean isClinit() { + return getSelector().equals(MethodReference.clinitSelector); + } + + public boolean isInit() { + return getSelector().equals(MethodReference.initSelector); + } + + public Atom getName() { + return ref.getName(); + } + + public Descriptor getDescriptor() { + return ref.getDescriptor(); + } + + public MethodReference getReference() { + return ref; + } + + public TypeReference getReturnType() { + return ref.getReturnType(); + } + + public boolean isStatic() { + return qualifiers.contains(CAstQualifier.STATIC); + } + + public boolean isSynchronized() { + return qualifiers.contains(CAstQualifier.SYNCHRONIZED); + } + + public boolean isNative() { + return qualifiers.contains(CAstQualifier.NATIVE); + } + + public boolean isSynthetic() { + return false; + } + + public boolean isAbstract() { + return qualifiers.contains(CAstQualifier.ABSTRACT); + } + + public boolean isPrivate() { + return qualifiers.contains(CAstQualifier.PRIVATE); + } + + public boolean isProtected() { + return qualifiers.contains(CAstQualifier.PROTECTED); + } + + public boolean isPublic() { + return qualifiers.contains(CAstQualifier.PUBLIC); + } + + public boolean isFinal() { + return qualifiers.contains(CAstQualifier.FINAL); + } + + public boolean isVolatile() { + return qualifiers.contains(CAstQualifier.VOLATILE); + } + + public ControlFlowGraph getControlFlowGraph() { + return cfg; + } + + public boolean hasExceptionHandler() { + return hasCatchBlock; + } + + public int getNumberOfParameters() { + return symtab.getParameterValueNumbers().length; + } + + public int getLineNumber(int instructionIndex) { + Position pos = debugInfo.getInstructionPosition(instructionIndex); + if (pos == null) { + return -1; + } else { + return pos.getFirstLine(); + } + } + + public Position getSourcePosition(int instructionIndex) { + return debugInfo.getInstructionPosition(instructionIndex); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/SingleClassLoaderFactory.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/SingleClassLoaderFactory.java new file mode 100644 index 000000000..d799d61e0 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/loader/SingleClassLoaderFactory.java @@ -0,0 +1,49 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.loader; + +import com.ibm.wala.classLoader.ClassLoaderFactory; +import com.ibm.wala.classLoader.IClassLoader; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.util.debug.Assertions; + +public abstract class SingleClassLoaderFactory implements ClassLoaderFactory { + private IClassLoader THE_LOADER = null; + + public IClassLoader getLoader(ClassLoaderReference classLoaderReference, + ClassHierarchy cha, + AnalysisScope scope) + { + if (THE_LOADER == null) { + THE_LOADER = makeTheLoader(cha); + try { + THE_LOADER.init(scope.getModules(getTheReference())); + } catch (java.io.IOException e) { + Assertions.UNREACHABLE(); + } + } + + Assertions._assert(classLoaderReference.equals(getTheReference())); + + return THE_LOADER; + } + + public IClassLoader getTheLoader() { + return THE_LOADER; + } + + public abstract ClassLoaderReference getTheReference(); + + protected abstract IClassLoader makeTheLoader(ClassHierarchy cha); + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/plugin/AstPlugin.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/plugin/AstPlugin.java new file mode 100644 index 000000000..8dacb26f3 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/plugin/AstPlugin.java @@ -0,0 +1,53 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.plugin; + +import org.eclipse.core.runtime.Plugin; +import org.osgi.framework.BundleContext; + +/** + * The main plugin class to be used in the desktop. + */ +public class AstPlugin extends Plugin { + + //The shared instance. + private static AstPlugin plugin; + + /** + * The constructor. + */ + public AstPlugin() { + plugin = this; + } + + /** + * This method is called upon plug-in activation + */ + public void start(BundleContext context) throws Exception { + super.start(context); + } + + /** + * This method is called when the plug-in is stopped + */ + public void stop(BundleContext context) throws Exception { + super.stop(context); + plugin = null; + } + + /** + * Returns the shared instance. + */ + public static AstPlugin getDefault() { + return plugin; + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/AstPlugin.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/AstPlugin.java new file mode 100644 index 000000000..2e032360e --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/AstPlugin.java @@ -0,0 +1,53 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree; + +import org.eclipse.core.runtime.Plugin; +import org.osgi.framework.BundleContext; + +/** + * The main plugin class to be used in the desktop. + */ +public class AstPlugin extends Plugin { + + //The shared instance. + private static AstPlugin plugin; + + /** + * The constructor. + */ + public AstPlugin() { + plugin = this; + } + + /** + * This method is called upon plug-in activation + */ + public void start(BundleContext context) throws Exception { + super.start(context); + } + + /** + * This method is called when the plug-in is stopped + */ + public void stop(BundleContext context) throws Exception { + super.stop(context); + plugin = null; + } + + /** + * Returns the shared instance. + */ + public static AstPlugin getDefault() { + return plugin; + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAst.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAst.java new file mode 100644 index 000000000..39beeabfa --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAst.java @@ -0,0 +1,80 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree; + +/** + * The main interface for creating CAPA Abstract Syntax Trees. This + * interface provides essentially a factory for creating AST nodes in + * a tree structure. There is no strong assumption about the meaning + * of specific nodes; however, the `kind' argument to a makeNode call + * should be a value from the constants in the CAstNode interface. + * The other arguments to makeNode calls are child nodes. The + * structure of the tree is a matter of agreement between providers and + * consumers of specific trees. + * + * @author Julian Dolby (dolby@us.ibm.com) + * + */ +public interface CAst { + + /** Make a node of type kind with no children. */ + CAstNode makeNode(int kind); + + /** Make a node of type kind with one child. */ + CAstNode makeNode(int kind, CAstNode c1); + + /** Make a node of type kind with two children. */ + CAstNode makeNode(int kind, CAstNode c1, CAstNode c2); + + /** Make a node of type kind with three children. */ + CAstNode makeNode(int kind, CAstNode c1, CAstNode c2, CAstNode c3); + + /** Make a node of type kind with four children. */ + CAstNode makeNode(int kind, CAstNode c1, CAstNode c2, CAstNode c3, CAstNode c4); + /** Make a node of type kind with five children. */ + CAstNode makeNode(int kind, CAstNode c1, CAstNode c2, CAstNode c3, CAstNode c4, CAstNode c5); + + /** Make a node of type kind with six children. */ + CAstNode makeNode(int kind, CAstNode c1, CAstNode c2, CAstNode c3, CAstNode c4, CAstNode c5, CAstNode c6); + + /** Make a node of type kind specifying an array of children. */ + CAstNode makeNode(int kind, CAstNode[] cs); + + /** Make a node of type kind giving a first child and array of the rest. */ + CAstNode makeNode(int kind, CAstNode firstChild, CAstNode[] otherChildren); + + /** Make a boolean constant node. */ + CAstNode makeConstant(boolean value); + + /** Make a char constant node. */ + CAstNode makeConstant(char value); + + /** Make a short integer constant node. */ + CAstNode makeConstant(short value); + + /** Make an integer constant node. */ + CAstNode makeConstant(int value); + + /** Make a long integer constant node. */ + CAstNode makeConstant(long value); + + /** Make a double-precision floating point constant node. */ + CAstNode makeConstant(double value); + + /** Make a single-precision floating point constant node. */ + CAstNode makeConstant(float value); + + /** Make an arbitrary object constant node. */ + CAstNode makeConstant(Object value); + + /** Make a new identifier, unqiue to this CAst instance. */ + String makeUnique(); +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstControlFlowMap.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstControlFlowMap.java new file mode 100644 index 000000000..877ce90e5 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstControlFlowMap.java @@ -0,0 +1,76 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree; + +import java.util.Collection; + +import com.ibm.wala.util.debug.Assertions; + +/** + * The control flow information for the CAPA AST of a particular + * entity. An ast may contain various nodes that pertain to control + * flow---such as gotos, branches, exceptions and so on---and this map + * denotes the target ast nodes of ast nodes that are control flow + * instructions. The label is fairly arbitrary---it will depend on + * the language, producers and consumers of the tree---but is + * generally expected to be things like case labels, exception types, + * conditional outcomes and so on. + * + * @author Julian Dolby (dolby@us.ibm.com) + * + */ +public interface CAstControlFlowMap { + + /** + * A distinguished label that means this control flow is the + * default target of a switch (or case) statement as found in many + * procedural languages. + */ + public static final Object SWITCH_DEFAULT = new Object(); + + /** + * A distinguished target that means this control flow is the target + * of an uncaught exception. + */ + public static final CAstNode EXCEPTION_TO_EXIT = new CAstNode() { + public int getKind() { return CAstNode.CONSTANT; } + public Object getValue() { return this; } + public CAstNode getChild(int n) { Assertions.UNREACHABLE(); return null; } + public int getChildCount() { return 0;} + public String toString() { return "EXCEPTION_TO_EXIT"; } + public int hashCode() { return getKind()*toString().hashCode(); } + public boolean equals(Object o) { return o == this; } + }; + + /** + * Return the target ast node of the control-flow instruction + * denoted by from with respect to the given label. + */ + CAstNode getTarget(CAstNode from, Object label); + + /** + * Return a collection of all labels for which the control-flow ast + * node from has a target. + */ + Collection getTargetLabels(CAstNode from); + + /** + * Return a collection of control-flow ast nodes that have this one + * as a possible target. + */ + Collection getSourceNodes(CAstNode to); + + /** + * Returns an iterator of all CAstNodes for which this map contains + * control flow mapping information. + */ + Collection getMappedNodes(); +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstEntity.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstEntity.java new file mode 100644 index 000000000..40537ac54 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstEntity.java @@ -0,0 +1,168 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree; + +import java.util.*; + +/** + * The assumption is that abstract syntax trees pertain to particular + * programming language constructs, such as classes, methods, programs + * and the like. Thus, the expectation is that users of CAPA AST will + * typically be communicating such entities, and this interface is + * meant to give them a mechanism to do this. + * + * The set of kinds that are currently in this file is not meant to + * be exhaustive, and should be extended as needed for any new + * languages that come along. + * + * @author Julian Dolby (dolby@us.ibm.com) + * + */ +public interface CAstEntity { + + /** This entity is a function. + * Children: in JavaScript, FUNCTION_ENTITY's; in Java, none. + **/ + public static int FUNCTION_ENTITY = 1; + + /** This entity is a program script for a scripting language. + * Children: in JavaScript, FUNCTION_ENTITY's(?); doesn't occur in Java. + **/ + public static int SCRIPT_ENTITY = 2; + + /** This entity is a type in an object-oriented language. + * Children: typically, immediately enclosed FIELD_ENTITY's, + * FUNCTION_ENTITY's, and TYPE_ENTITY's. + **/ + public static int TYPE_ENTITY = 3; + + /** This entity is a field in an object-oriented language. + * Children: usually, none + **/ + public static int FIELD_ENTITY = 4; + + /** This entity is a source file (i.e. a compilation unit). + * Children: in JavaScript, nothing(doesn't occur?); in Java, TYPE_ENTITY's. + **/ + public static int FILE_ENTITY = 5; + + /** This entity represents a rule in a logic language. + */ + public static int RULE_ENTITY = 6; + + /** + * Languages that introduce new kinds of CAstEntity should use this + * number as the base of integers chosen to denote the new entity + * types. + */ + public static final int SUB_LANGUAGE_BASE = 100; + + /** + * What kind of entity is this? The answer should be one of the + * constants in this file. This has no meaning to the CAPA AST + * interfaces, but should be meaningful to a given producer and + * consumer of an entity. + */ + int getKind(); + + /** + * Some programming language constructs have names. This should be + * it, if appropriate, and null otherwise. + */ + String getName(); + + /** + * Some programming language constructs have signatures, which are like + * names but usually have some detail to distinguish the construct from + * others with the same name. Signatures often denote typing information + * as well, but this is not required. This method should return a + * signature if appropriate, and null otherwise. + */ + String getSignature(); + + /** + * Some programming language constructs have named arguments. This + * should be their names, if appropriate. Otherwise, please return + * an array of size 0, since null can be a pain. + */ + String[] getArgumentNames(); + + /** + * Some programming language constructs allow arguments to have default + * values. This should be those defaults, one per named argument above. + * Otherwise, please return an array of size 0, since null can be a pain. + */ + CAstNode[] getArgumentDefaults(); + + /** + * Some programming language constructs have a specific number of + * arguments. This should be that number, if appropriate, and 0 + * otherwise. + */ + int getArgumentCount(); + + /** + * Some programming language constructs have a lexical structure. + * This should be those constructs that are directly inside the current + * one. The result of this method is a map from source construct to + * the set of entities induced by that construct. Entities induced by + * no particular construct are mapped by the null key. + */ + Map getAllScopedEntities(); + + /** + * Some programming language constructs have a lexical structure. + * This should be those constructs that are directly inside the current + * one. The result of this method is the scoped entities induced by + * the construct `construct' (i.e. a node of the AST returned by + * + * Enclosed entities not induced by a specific AST node are mapped + * by the construct 'null'. + */ + Iterator getScopedEntities(CAstNode construct); + + /** + * The CAPA AST of this entity. + */ + CAstNode getAST(); + + /** + * The control flow map for the CAPA AST of this entity. + */ + CAstControlFlowMap getControlFlow(); + + /** + * The map of CAstNodes to source positions for the CAPA AST of this entity. + */ + CAstSourcePositionMap getSourceMap(); + + /** + * The source position of this entity. + */ + CAstSourcePositionMap.Position getPosition(); + + /** + * The map from CAstNodes to types. Valid for nodes that have an explicitly + * declared type (e.g. local vars). + */ + CAstNodeTypeMap getNodeTypeMap(); + + /** + * Returns an Iterator over the qualifiers of the given entity, if it has + * any, e.g., "final", "private". + */ + Collection/**/ getQualifiers(); + + /** + * The CAst type of this entity. + */ + CAstType getType(); +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstMemberReference.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstMemberReference.java new file mode 100644 index 000000000..3ea0d471b --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstMemberReference.java @@ -0,0 +1,40 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree; + +public interface CAstMemberReference extends CAstReference { + + public static final CAstMemberReference FUNCTION = + new CAstMemberReference() { + public String member() { + return "the function body"; + } + + public CAstType type() { + return null; + } + + public String toString() { + return "Any::FUNCTION CALL"; + } + + public int hashCode() { + return toString().hashCode(); + } + + public boolean equals(Object o) { + return o == this; + } + }; + + String member(); + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstNode.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstNode.java new file mode 100644 index 000000000..2af1d23a9 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstNode.java @@ -0,0 +1,182 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree; + +/** + * This interface represents nodes of CAPA Abstract Syntax Trees. It + * is a deliberately minimal interface, simply assuming that the nodes + * form a tree and have some minimal state at each node. In + * particular, a node has a kind---which should be one of the symbolic + * constants in this file---and potentially has child nodes, a + * constant values, or possibly both. + * + * Note that there is no support for mutating these trees. This is + * deliberate, and should not be changed. We do not want to force all + * clients of the capa ast to handle mutating programs. In + * particular, the DOMO infrastructure has many forms of caching and + * other operations that rely on the underlying program being + * immutable. If you need to mutate these trees for some reason---and + * think carefully if you really need to, since this is meant to be + * essentially a wire format between components---make specialized + * implementations that understand how to do that. + * + * Also note that this interface does not assume that you need some + * great big class hierarchy to structure types of nodes in an ast. + * Some people prefer such hierarchies as a matter of taste, but this + * interface is designed to not inflict this design choice on others. + * + * Finally note that the set of node types in this file is not meant + * to be exhaustive. As new languages are added, feel free to add new + * nodes types as needed. + * + * @author Julian Dolby (dolby@us.ibm.com) + * @author Robert M. Fuhrer (rfuhrer@watson.ibm.com) + * + */ +public interface CAstNode { + + // statement kinds + /** + * Represents a standard case statement. Children: + * + *
  • condition expression + *
  • BLOCK_STMT containing all the cases + * + */ + public static final int SWITCH = 1; + + /** + * Represents a standard while loop. Children: + *
      + *
    • expression denoting the loop condition + *
    • statement denoting the loop body + *
    + */ + public static final int LOOP = 2; + + /** + * Represents a block of sequential statements. Children: + *
      + *
    • statement #1 + *
    • statement #2 + *
    • ... + *
    + */ + public static final int BLOCK_STMT = 3; + + /** + * Represents a standard try/catch statement. Note that while some + * languages choose to bundle together the notion of try/catch and + * the notion of unwind-protect (aka 'finally'), the CAst does not. + * There is a separate UNWIND node type. Children: + *
      + *
    • the code of the try block. + *
    • the code of the catch block
    • ... + *
    + */ + public static final int TRY = 4; + + /** + * Represents an expression statement (e.g. "foo();"). Children: + *
      + *
    • the expression + *
    + */ + public static final int EXPR_STMT = 5; + public static final int DECL_STMT = 6; + public static final int RETURN = 7; + public static final int GOTO = 8; + public static final int BREAK = 9; + public static final int CONTINUE = 10; + public static final int IF_STMT = 11; + public static final int THROW = 12; + public static final int FUNCTION_STMT = 13; + public static final int ASSIGN = 14; + public static final int ASSIGN_PRE_OP = 15; + public static final int ASSIGN_POST_OP = 16; + public static final int LABEL_STMT = 17; + public static final int IFGOTO = 18; + public static final int EMPTY = 19; + public static final int RETURN_WITHOUT_BRANCH = 20; + public static final int CATCH = 21; + public static final int UNWIND = 22; + public static final int MONITOR_ENTER = 23; + public static final int MONITOR_EXIT = 24; + public static final int ECHO = 25; + + // expression kinds + public static final int FUNCTION_EXPR = 100; + public static final int EXPR_LIST = 101; + public static final int CALL = 102; + public static final int GET_CAUGHT_EXCEPTION = 103; + public static final int BLOCK_EXPR = 104; + public static final int BINARY_EXPR = 105; + public static final int UNARY_EXPR = 106; + public static final int IF_EXPR = 107; + public static final int ANDOR_EXPR = 108; // TODO blow away? + public static final int NEW = 109; + public static final int OBJECT_LITERAL = 110; + public static final int VAR = 111; + public static final int OBJECT_REF = 112; + public static final int CHOICE_EXPR = 113; + public static final int CHOICE_CASE = 114; + public static final int SUPER = 115; + public static final int THIS = 116; + public static final int ARRAY_LITERAL = 117; + public static final int CAST = 118; + public static final int INSTANCEOF = 119; + public static final int ARRAY_REF = 120; + public static final int ARRAY_LENGTH = 121; + public static final int TYPE_OF = 122; + public static final int EACH_ELEMENT_HAS_NEXT = 123; + public static final int EACH_ELEMENT_GET = 124; + public static final int LIST_EXPR = 125; + public static final int EMPTY_LIST_EXPR = 126; + public static final int TYPE_LITERAL_EXPR = 127; + + // explicit lexical scopes + public static final int LOCAL_SCOPE = 200; + + // literal expression kinds + public static final int CONSTANT = 300; + public static final int OPERATOR = 301; + + // special stuff + public static final int PRIMITIVE = 400; + public static final int ERROR = 401; + public static final int VOID = 402; + public static final int ASSERT = 403; + + public static final int SUB_LANGUAGE_BASE = 1000; + + /** + * What kind of node is this? Should return some constant from this file. + */ + int getKind(); + + /** + * Returns the constant value represented by this node, if + * appropriate, and null otherwise. + */ + Object getValue(); + + /** + * Return the nth child of this node. If there is no such child, + * this method should throw a NoSuchElementException. + */ + CAstNode getChild(int n); + + /** + * How many children does this node have? + */ + int getChildCount(); + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstNodeTypeMap.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstNodeTypeMap.java new file mode 100644 index 000000000..45845e9d8 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstNodeTypeMap.java @@ -0,0 +1,18 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +/* + * Created on Aug 30, 2005 + */ +package com.ibm.wala.cast.tree; + +public interface CAstNodeTypeMap { + CAstType getNodeType(CAstNode node); +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstQualifier.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstQualifier.java new file mode 100644 index 000000000..56fa74da2 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstQualifier.java @@ -0,0 +1,85 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +/* + * Created on Sep 1, 2005 + */ +package com.ibm.wala.cast.tree; + +import java.util.*; + +public class CAstQualifier { + public static final Set/* */sQualifiers = new HashSet(); + + public static final CAstQualifier CONST = new CAstQualifier("const"); + public static final CAstQualifier STRICTFP = new CAstQualifier("strictfp"); + public static final CAstQualifier VOLATILE = new CAstQualifier("volatile"); + public static final CAstQualifier ABSTRACT = new CAstQualifier("abstract"); + public static final CAstQualifier INTERFACE = new CAstQualifier("interface"); + public static final CAstQualifier NATIVE = new CAstQualifier("native"); + public static final CAstQualifier TRANSIENT = new CAstQualifier("transient"); + public static final CAstQualifier FINAL = new CAstQualifier("final"); + public static final CAstQualifier STATIC = new CAstQualifier("static"); + public static final CAstQualifier PRIVATE = new CAstQualifier("private"); + public static final CAstQualifier PROTECTED = new CAstQualifier("protected"); + public static final CAstQualifier PUBLIC = new CAstQualifier("public"); + public static final CAstQualifier SYNCHRONIZED = + new CAstQualifier("synchronized"); + + static { + sQualifiers.add(PUBLIC); + sQualifiers.add(PROTECTED); + sQualifiers.add(PRIVATE); + sQualifiers.add(STATIC); + sQualifiers.add(FINAL); + sQualifiers.add(SYNCHRONIZED); + sQualifiers.add(TRANSIENT); + sQualifiers.add(NATIVE); + sQualifiers.add(INTERFACE); + sQualifiers.add(ABSTRACT); + sQualifiers.add(VOLATILE); + sQualifiers.add(STRICTFP); + sQualifiers.add(CONST); + } + + private static int sNextBitNum = 0; + + private String fName; + + private long fBit; + + public CAstQualifier(String name) { + super(); + fBit = 1L << sNextBitNum++; + fName = name; + sQualifiers.add(this); + } + + public long getBit() { + return fBit; + } + + public String getName() { + return fName; + } + + public boolean equals(Object o) { + if (!(o instanceof CAstQualifier)) + return false; + CAstQualifier other = (CAstQualifier) o; + return other.fName.equals(fName) && (fBit == other.fBit); + } + + public int hashCode() { + int result = 37; + result = result * 13 + fName.hashCode(); + return result; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstReference.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstReference.java new file mode 100644 index 000000000..17d581336 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstReference.java @@ -0,0 +1,25 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree; + +/** + * This interface is used to denote various kinds of references in + * CAst structures. It can be used to denote types for languages like + * Java and PHP that have non-trivial mappings from names to actual + * entities. + * + * @author Julian Dolby (dolby@us.ibm.com) + */ +public interface CAstReference { + + CAstType type(); + +}; diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstSourcePositionMap.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstSourcePositionMap.java new file mode 100644 index 000000000..daa97f94b --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstSourcePositionMap.java @@ -0,0 +1,58 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree; + +import java.io.*; +import java.net.*; +import java.util.Iterator; + +/** + * The assumption is that a typical CAst is derived from some kind of + * textual source file, for which it makes sense to record source + * position in terms of line and column numbers. This interface + * encapsulates a mapping from CAstNodes of the an ast to such source + * positions. + * + * @author Julian Dolby (dolby@us.ibm.com) + */ +public interface CAstSourcePositionMap { + + /** + * This interface encapsulates the source position of an ast node + * in its source file. Since different parsers record different + * degrees of source position information, any client of these + * Positions must be prepared to expect -1---symbolizing no + * information---to be returned by some or all of its accessors. + * + * @author Julian Dolby (dolby@us.ibm.com) + */ + public interface Position extends Comparable { + int getFirstLine(); + int getLastLine(); + int getFirstCol(); + int getLastCol(); + URL getURL(); + InputStream getInputStream() throws IOException; + } + + /** + * Returns the position of a given node in its source file, or + * null if the position is not known or does not exist. + */ + Position getPosition(CAstNode n); + + /** + * Returns an iterator of all CAstNodes for which this map contains + * source mapping information. + */ + Iterator getMappedNodes(); + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstType.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstType.java new file mode 100644 index 000000000..a770b0fbe --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstType.java @@ -0,0 +1,55 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +/* + * Created on Aug 30, 2005 + */ +package com.ibm.wala.cast.tree; + +import java.util.Collection; +import java.util.List; + +public interface CAstType { + /** + * Returns the fully-qualified (e.g. bytecode-compliant for Java) type name. + */ + String getName(); + + Collection/**/ getSupertypes(); + + public interface Primitive extends CAstType { + // Need anything else? The name pretty much says it all... + } + + public interface Reference extends CAstType { + } + + public interface Class extends Reference { + boolean isInterface(); + } + + public interface Array extends Reference { + int getNumDimensions(); + CAstType getElementType(); + } + + public interface Function extends Reference { + CAstType getReturnType(); + + List/**/ getArgumentTypes(); + Collection/**/ getExceptionTypes(); + + int getArgumentCount(); + } + + public interface Method extends Function { + CAstType getDeclaringType(); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstTypeDictionary.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstTypeDictionary.java new file mode 100644 index 000000000..0bff62fba --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/CAstTypeDictionary.java @@ -0,0 +1,23 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +/* + * Created on Aug 31, 2005 + */ +package com.ibm.wala.cast.tree; + + +public interface CAstTypeDictionary/**/ { + + CAstType getCAstTypeFor(Object/*ASTType*/ type); + + CAstReference resolveReference(CAstReference ref); + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/TranslatorToCAst.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/TranslatorToCAst.java new file mode 100644 index 000000000..325cf149f --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/TranslatorToCAst.java @@ -0,0 +1,26 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree; + +import java.io.*; + +/** + * Encapsulates a translator from source files to CAstEntities. This + * interface is meant ease the creation of CAst consumers that can + * take asts from multiple sources. + * + * @author Julian Dolby (dolby@us.ibm.com) + */ +public interface TranslatorToCAst { + + CAstEntity translate(Reader file, String fileName) throws IOException; + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/AbstractSourcePosition.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/AbstractSourcePosition.java new file mode 100644 index 000000000..515dcb2ba --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/AbstractSourcePosition.java @@ -0,0 +1,58 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.*; +import com.ibm.wala.cast.tree.CAstSourcePositionMap.*; + +public abstract class AbstractSourcePosition implements Position { + + public boolean equals(Object o){ + if (o instanceof Position) { + Position p = (Position)o; + return getFirstLine() == p.getFirstLine() && + getLastLine() == p.getLastLine() && + getFirstCol() == p.getFirstCol() && + getLastCol() == p.getLastCol() && + ( (getURL() != null)? + getURL().equals(p.getURL()): + p.getURL() == null); + } else { + return false; + } + } + + public int hashCode() { + return getFirstLine()*getLastLine()*getFirstCol()*getLastCol(); + } + + public int compareTo(Object o) { + if (o instanceof Position) { + Position p = (Position)o; + if (getFirstLine() != p.getFirstLine()) { + return getFirstLine() - p.getFirstLine(); + } else if (getFirstCol() != p.getFirstCol()) { + return getFirstCol() - p.getFirstCol(); + } else if (getLastLine() != p.getLastLine()) { + return getLastLine() - p.getLastLine(); + } else { + return getLastCol() - p.getLastCol(); + } + } else { + return 0; + } + } + + public String toString() { + return "["+getFirstLine()+":"+getFirstCol()+"] -> ["+getLastLine()+":"+getLastCol()+"]"; + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstCloner.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstCloner.java new file mode 100644 index 000000000..fa8ee4ee2 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstCloner.java @@ -0,0 +1,128 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.*; + +import java.util.*; + +public class CAstCloner { + + private final CAst Ast; + + public CAstCloner(CAst Ast) { + this.Ast = Ast; + } + + public interface Clone { + + CAstNode newRoot(); + + CAstControlFlowMap newCfg(); + + CAstSourcePositionMap newPos(); + + } + + private CAstNode copyNodes(CAstNode root, Map nodeMap) { + if (root instanceof CAstOperator) { + nodeMap.put(root, root); + return root; + } else if (root.getValue() != null) { + CAstNode copy = Ast.makeConstant( root.getValue() ); + nodeMap.put(root, copy); + return copy; + } else { + CAstNode newChildren[] = new CAstNode[ root.getChildCount() ]; + + for(int i = 0; i < root.getChildCount(); i++) { + newChildren[i] = copyNodes(root.getChild(i), nodeMap); + } + + CAstNode copy = Ast.makeNode(root.getKind(), newChildren); + nodeMap.put(root, copy); + return copy; + } + } + + private CAstControlFlowMap copyFlow(Map nodeMap, CAstControlFlowMap orig) { + Collection oldSources = orig.getMappedNodes(); + CAstControlFlowRecorder newMap = new CAstControlFlowRecorder(); + for(Iterator NS = nodeMap.keySet().iterator(); NS.hasNext(); ) { + CAstNode old = (CAstNode) NS.next(); + CAstNode newNode = (CAstNode) nodeMap.get(old); + newMap.map(newNode, newNode); + if (oldSources.contains(old)) { + if (orig.getTarget(old, null) != null) { + CAstNode oldTarget = orig.getTarget(old, null); + if (nodeMap.containsKey(oldTarget)) { + newMap.add(newNode, nodeMap.get(oldTarget), null); + } else { + newMap.add(newNode, oldTarget, null); + } + } + + for(Iterator LS = orig.getTargetLabels(old).iterator(); LS.hasNext(); ) { + Object label = LS.next(); + CAstNode oldTarget = orig.getTarget(old, label); + if (nodeMap.containsKey(oldTarget)) { + newMap.add(newNode, nodeMap.get(oldTarget), label); + } else { + newMap.add(newNode, oldTarget, label); + } + } + } + } + + return newMap; + } + + private CAstSourcePositionMap + copySource(Map nodeMap, CAstSourcePositionMap orig) + { + if (orig == null) { + return null; + } else { + CAstSourcePositionRecorder newMap = new CAstSourcePositionRecorder(); + for(Iterator NS = nodeMap.keySet().iterator(); NS.hasNext(); ) { + CAstNode old = (CAstNode) NS.next(); + CAstNode newNode = (CAstNode) nodeMap.get(old); + + if (orig.getPosition(old) != null) { + newMap.setPosition(newNode, orig.getPosition(old)); + } + } + + return newMap; + } + } + + public Clone copy(CAstNode root, + final CAstControlFlowMap cfg, + final CAstSourcePositionMap pos) + { + final Map nodes = new HashMap(); + final CAstNode newRoot = copyNodes(root, nodes); + return new Clone() { + private CAstControlFlowMap theCfg = null; + private CAstSourcePositionMap theSource = null; + public CAstNode newRoot() { return newRoot; } + public CAstControlFlowMap newCfg() { + if (theCfg == null) theCfg = copyFlow(nodes, cfg); + return theCfg; + } + public CAstSourcePositionMap newPos() { + if (theSource == null) theSource = copySource(nodes, pos); + return theSource; + } + }; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstControlFlowRecorder.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstControlFlowRecorder.java new file mode 100644 index 000000000..beb1649a8 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstControlFlowRecorder.java @@ -0,0 +1,137 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.*; +import com.ibm.wala.util.debug.Assertions; + +import java.util.*; + +/** + * An implementation of a CAstControlFlowMap that is designed to be + * used by producers of CAPA asts. In addition to implementing the + * control flow map, it additionally allows clients to record control + * flow mappings in terms of some arbitrary type object that are then + * mapped to CAstNodes by the client. These objects can be anything, + * but one common use is that some type of parse tree is walked to + * build a capa ast, with control flow being recorded in terms of + * parse tree nodes and then ast nodes being mapped to parse tree + * nodes. + * + * Note that, at present, support for mapping control flow on ast + * nodes directly is clunky. It is necessary to establish that an ast + * nodes maps to itself, i.e. call xx.map(node, node). + * + * @author Julian Dolby (dolby@us.ibm.com) + */ +public class CAstControlFlowRecorder implements CAstControlFlowMap { + private final Map CAstToNode = new LinkedHashMap(); + private final Map nodeToCAst = new LinkedHashMap(); + private final Map table = new LinkedHashMap(); + private final Map labelMap = new LinkedHashMap(); + private final Map sourceMap = new LinkedHashMap(); + + private class Key { + private final Object label; + private final Object from; + + Key(Object label, Object from) { + this.from = from; + this.label = label; + } + + Key(Object label, CAstNode from) { + this(label, CAstToNode.get(from)); + Assertions._assert(CAstToNode.containsKey(from)); + } + + public int hashCode() { + if (label != null) + return from.hashCode()*label.hashCode(); + else + return from.hashCode(); + } + + public boolean equals(Object o) { + return (o instanceof Key) && + from == ((Key)o).from && + ((label==null)? + ((Key)o).label == null: + label.equals( ((Key)o).label )); + } + } + + public CAstControlFlowRecorder() { + map(EXCEPTION_TO_EXIT, EXCEPTION_TO_EXIT); + } + + public CAstNode getTarget(CAstNode from, Object label) { + Key key = new Key(label, from); + if (table.containsKey(key)) + return (CAstNode)nodeToCAst.get( table.get(key) ); + else + return null; + } + + public Collection getTargetLabels(CAstNode from) { + if (labelMap.containsKey( CAstToNode.get(from) )) { + return (Set) labelMap.get( CAstToNode.get(from) ); + } else { + return Collections.EMPTY_SET; + } + } + + public Collection getSourceNodes(CAstNode to) { + if (sourceMap.containsKey( CAstToNode.get(to) )) { + return (Set) sourceMap.get( CAstToNode.get(to) ); + } else { + return Collections.EMPTY_SET; + } + } + + public Collection getMappedNodes() { + Set nodes = new LinkedHashSet(); + for(Iterator keys = table.keySet().iterator(); keys.hasNext(); ) { + nodes.add( (CAstNode) nodeToCAst.get( ((Key)keys.next()).from ) ); + } + + return nodes; + } + + /** + * Add a control-flow edge from the `from' node to the `to' node + * with the (possibly null) label `label'. These nodes must be + * mapped by the client to CAstNodes using the `map' call; this mapping + * can happen before or after this add call. + */ + public void add(Object from, Object to, Object label) { + table.put(new Key(label, from), to); + + Set ls = (Set)labelMap.get(from); + if (ls==null) labelMap.put(from, ls=new LinkedHashSet(2)); + ls.add( label ); + + Set ss = (Set)sourceMap.get(to); + if (ss==null) sourceMap.put(to, ss=new LinkedHashSet(2)); + ss.add( from ); + } + + /** + * Establish a mapping between some object `node' and the ast node + * `ast'. Objects used a endpoints in a control flow edge must be + * mapped to ast nodes using this call. + */ + public void map(Object node, CAstNode ast) { + nodeToCAst.put(node, ast); + CAstToNode.put(ast, node); + } +} + diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstImpl.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstImpl.java new file mode 100644 index 000000000..30b333877 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstImpl.java @@ -0,0 +1,187 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.*; +import com.ibm.wala.cast.util.CAstPrinter; +import com.ibm.wala.util.debug.Assertions; + +import java.util.NoSuchElementException; + +/** + * An implementation of CAst, i.e. a simple factory for creating capa + * ast nodes. This class simply creates generic nodes with a kind + * field, and either an array of children or a constant values. Note + * that there is no easy way to mutate these trees; do not change + * this (see CAstNode for the rationale for this rule). + * + * @author Julian Dolby (dolby@us.ibm.com) + * + */ +public class CAstImpl implements CAst { + private int nextID= 0; + + public String makeUnique() { + return "id" + (nextID++); + } + + protected static class CAstNodeImpl implements CAstNode { + protected final CAstNode[] cs; + protected final int kind; + + protected CAstNodeImpl(int kind, CAstNode[] cs) { + this.kind = kind; + this.cs = cs; + + if (Assertions.verifyAssertions) + for(int i = 0; i < cs.length; i++) + Assertions._assert(cs[i] != null, + "argument " + i + " is null for node kind " + kind + " [" + CAstPrinter.entityKindAsString(kind) + "]"); + } + + public int getKind() { + return kind; + } + + public Object getValue() { + return null; + } + + public CAstNode getChild(int n) { + try { + return cs[n]; + } catch (ArrayIndexOutOfBoundsException e) { + throw new NoSuchElementException(); + } + } + + public int getChildCount() { + return cs.length; + } + + public String toString() { + return CAstPrinter.print(this); + } + + public int hashCode() { + int code = getKind() * (getChildCount()+13); + for(int i = 0; i < getChildCount(); i++) { + code *= getChild(i).getKind(); + } + + return code; + } + } + + public CAstNode makeNode(final int kind, final CAstNode[] cs) { + return new CAstNodeImpl(kind, cs); + } + + public CAstNode makeNode(int kind, CAstNode c1, CAstNode[] cs) { + CAstNode[] children = new CAstNode[ cs.length + 1 ]; + children[0] = c1; + System.arraycopy(cs, 0, children, 1, cs.length); + return makeNode(kind, children); + } + + public CAstNode makeNode(int kind) { + return makeNode(kind, new CAstNode[0]); + } + + public CAstNode makeNode(int kind, CAstNode c1) { + return makeNode(kind, new CAstNode[]{c1}); + } + + public CAstNode makeNode(int kind, CAstNode c1, CAstNode c2) { + return makeNode(kind, new CAstNode[]{c1, c2}); + } + + public CAstNode makeNode(int kind, CAstNode c1, CAstNode c2, CAstNode c3) { + return makeNode(kind, new CAstNode[]{c1, c2, c3}); + } + + public CAstNode makeNode(int kind, CAstNode c1, CAstNode c2, CAstNode c3, CAstNode c4) { + return makeNode(kind, new CAstNode[]{c1, c2, c3, c4}); + } + + public CAstNode makeNode(int kind, CAstNode c1, CAstNode c2, CAstNode c3, CAstNode c4, CAstNode c5) { + return makeNode(kind, new CAstNode[]{c1, c2, c3, c4, c5}); + } + + public CAstNode makeNode(int kind, CAstNode c1, CAstNode c2, CAstNode c3, CAstNode c4, CAstNode c5, CAstNode c6) { + return makeNode(kind, new CAstNode[]{c1, c2, c3, c4, c5, c6}); + } + + protected static class CAstValueImpl implements CAstNode { + protected final Object value; + + protected CAstValueImpl(Object value) { + this.value = value; + } + + public int getKind() { + return CAstNode.CONSTANT; + } + + public Object getValue() { + return value; + } + + public CAstNode getChild(int n) { + throw new NoSuchElementException(); + } + + public int getChildCount() { + return 0; + } + + public String toString() { + return "CAstValue: " + value; + } + + public int hashCode() { + return getKind() * toString().hashCode(); + } + } + + public CAstNode makeConstant(final Object value) { + return new CAstValueImpl(value); + } + + public CAstNode makeConstant(boolean value) { + return makeConstant(value? Boolean.TRUE: Boolean.FALSE); + } + + public CAstNode makeConstant(char value) { + return makeConstant( new Character(value) ); + } + + public CAstNode makeConstant(short value) { + return makeConstant( new Short(value) ); + } + + public CAstNode makeConstant(int value) { + return makeConstant( new Integer(value) ); + } + + public CAstNode makeConstant(long value) { + return makeConstant( new Long(value) ); + } + + public CAstNode makeConstant(float value) { + return makeConstant( new Float(value) ); + } + + public CAstNode makeConstant(double value) { + return makeConstant( new Double(value) ); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstNodeTypeMapRecorder.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstNodeTypeMapRecorder.java new file mode 100644 index 000000000..7fb66280f --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstNodeTypeMapRecorder.java @@ -0,0 +1,34 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +/* + * Created on Oct 10, 2005 + */ +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.*; + +import java.util.*; + +public class CAstNodeTypeMapRecorder + extends HashMap + implements CAstNodeTypeMap +{ + private static final long serialVersionUID= 7812144102027916961L; + + public CAstType getNodeType(CAstNode node) { + return (CAstType) get(node); + } + + public void add(CAstNode node, CAstType type) { + put(node, type); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstOperator.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstOperator.java new file mode 100644 index 000000000..5ebe9b3a3 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstOperator.java @@ -0,0 +1,76 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.*; + +import java.util.NoSuchElementException; + +/** + * Various operators that are built in to many languages, and hence + * perhaps deserve special notice in capa ast interface. There is no + * strong notion of what should be in here, so feel free to add other + * common operators. + * + * @author Julian Dolby (dolby@us.ibm.com) + */ +public class CAstOperator implements CAstNode { + private final String op; + + private CAstOperator(String op) { + this.op = op; + } + + public String toString() { + return "OP:" + op; + } + + public int getKind() { + return CAstNode.OPERATOR; + } + + public Object getValue() { + return op; + } + + public CAstNode getChild(int n) { + throw new NoSuchElementException(); + } + + public int getChildCount() { + return 0; + } + + public final static CAstOperator OP_ADD = new CAstOperator("+"); + public final static CAstOperator OP_CONCAT = new CAstOperator("."); + public final static CAstOperator OP_DIV = new CAstOperator("/"); + public final static CAstOperator OP_LSH = new CAstOperator("<<"); + public final static CAstOperator OP_MOD = new CAstOperator("%"); + public final static CAstOperator OP_MUL = new CAstOperator("*"); + public final static CAstOperator OP_RSH = new CAstOperator(">>"); + public final static CAstOperator OP_URSH = new CAstOperator(">>>"); + public final static CAstOperator OP_SUB = new CAstOperator("-"); + public final static CAstOperator OP_EQ = new CAstOperator("=="); + public final static CAstOperator OP_GE = new CAstOperator(">="); + public final static CAstOperator OP_GT = new CAstOperator(">"); + public final static CAstOperator OP_LE = new CAstOperator("<="); + public final static CAstOperator OP_LT = new CAstOperator("<"); + public final static CAstOperator OP_NE = new CAstOperator("!="); + public final static CAstOperator OP_NOT = new CAstOperator("!"); + public final static CAstOperator OP_BITNOT = new CAstOperator("~"); + public final static CAstOperator OP_BIT_AND = new CAstOperator("&"); + public final static CAstOperator OP_REL_AND = new CAstOperator("&&"); + public final static CAstOperator OP_BIT_OR = new CAstOperator("|"); + public final static CAstOperator OP_REL_OR = new CAstOperator("||"); + public final static CAstOperator OP_BIT_XOR = new CAstOperator("^"); + public final static CAstOperator OP_REL_XOR = new CAstOperator("^^"); +} + diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstSourcePositionRecorder.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstSourcePositionRecorder.java new file mode 100644 index 000000000..835c0358f --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstSourcePositionRecorder.java @@ -0,0 +1,87 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.*; + +import java.io.*; +import java.net.*; +import java.util.*; + +public class CAstSourcePositionRecorder implements CAstSourcePositionMap { + + private final HashMap positions = new HashMap(); + + public Position getPosition(CAstNode n) { + return (Position) positions.get(n); + } + + public Iterator getMappedNodes() { + return positions.keySet().iterator(); + } + + public void setPosition(CAstNode n, Position p) { + positions.put(n, p); + } + + public void setPosition(CAstNode n, + final int fl, + final int fc, + final int ll, + final int lc, + final String url, + final String file) + throws MalformedURLException + { + setPosition(n, fl, fc, ll, lc, new URL(url), new URL(file)); + } + + public void setPosition(CAstNode n, + final int fl, + final int fc, + final int ll, + final int lc, + final URL url, + final URL file) + { + setPosition(n, + new AbstractSourcePosition() { + public int getFirstLine() { return fl; } + public int getLastLine() { return ll; } + public int getFirstCol() { return fc; } + public int getLastCol() { return lc; } + public URL getURL() { return url; } + public InputStream getInputStream() throws IOException { + return file.openConnection().getInputStream(); + } + public String toString() { + return "["+fl+":"+fc+"]->["+ll+":"+lc+"]"; + } + }); + } + + public void setPosition(CAstNode n, int lineNumber, String url, String file) + throws MalformedURLException + { + setPosition(n, lineNumber, new URL(url), new URL(file)); + } + + public void setPosition(CAstNode n, int lineNumber, URL url, URL file) { + setPosition(n, new LineNumberPosition(url, file, lineNumber)); + } + + public void addAll(CAstSourcePositionMap other) { + for(Iterator nodes = other.getMappedNodes(); nodes.hasNext(); ) { + CAstNode node = (CAstNode) nodes.next(); + setPosition(node, other.getPosition(node)); + } + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstTypeDictionaryImpl.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstTypeDictionaryImpl.java new file mode 100644 index 000000000..03fa0d53e --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstTypeDictionaryImpl.java @@ -0,0 +1,34 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +/* + * Created on Sep 21, 2005 + */ +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.*; + +import java.util.*; + +public class CAstTypeDictionaryImpl implements CAstTypeDictionary { + private final Map/**/ fMap= new HashMap(); + + public CAstType getCAstTypeFor(Object/*ASTType*/ astType) { + return (CAstType) fMap.get(astType); + } + + public void map(Object/*ASTType*/ astType, CAstType castType) { + fMap.put(astType, castType); + } + + public CAstReference resolveReference(CAstReference ref) { + return ref; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstValueImpl.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstValueImpl.java new file mode 100644 index 000000000..c0c00f2fb --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/CAstValueImpl.java @@ -0,0 +1,82 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.*; + +/** + * An implementation of CAst, i.e. a simple factory for creating capa + * ast nodes. This class simply creates generic nodes with a kind + * field, and either an array of children. Note that there is no easy + * way to mutate these trees; do not changes this (see CAstNode for + * the rationale for this rule). + * + * @author Julian Dolby (dolby@us.ibm.com) + * + */ +public class CAstValueImpl extends CAstImpl { + + protected static class CAstNodeValueImpl extends CAstNodeImpl { + + protected CAstNodeValueImpl(int kind, CAstNode cs[]) { + super(kind, cs); + } + + public int hashCode() { + int value = 1237 * kind; + for(int i = 0; i < cs.length; i++) + value *= cs[i].hashCode(); + + return value; + } + + public boolean equals(Object o) { + if (! (o instanceof CAstNode)) return false; + if (kind != ((CAstNode)o).getKind()) return false; + if (((CAstNode)o).getChildCount() != cs.length) return false; + for(int i = 0; i < cs.length; i++) + if (! cs[i].equals(((CAstNode)o).getChild(i))) + return false; + + return true; + } + } + + public CAstNode makeNode(final int kind, final CAstNode[] cs) { + return new CAstNodeValueImpl(kind, cs); + } + + protected static class CAstValueValueImpl extends CAstValueImpl { + + protected CAstValueValueImpl(Object value) { + super(value); + } + + public int hashCode() { + return value.hashCode(); + } + + public boolean equals(Object o) { + if (o instanceof CAstNode) { + return value==null? + ((CAstNode)o).getValue()==null: + value.equals(((CAstNode)o).getValue()); + } else { + return false; + } + } + } + + public CAstNode makeConstant(final Object value) { + return new CAstValueValueImpl(value); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/DelegatingEntity.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/DelegatingEntity.java new file mode 100644 index 000000000..1e7c7eda5 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/DelegatingEntity.java @@ -0,0 +1,84 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.*; + +import java.util.*; + +public class DelegatingEntity implements CAstEntity { + private final CAstEntity base; + + public DelegatingEntity(CAstEntity base) { + this.base = base; + } + + public int getKind() { + return base.getKind(); + } + + public String getName() { + return base.getName(); + } + + public String getSignature() { + return base.getSignature(); + } + + public String[] getArgumentNames() { + return base.getArgumentNames(); + } + + public CAstNode[] getArgumentDefaults() { + return base.getArgumentDefaults(); + } + + public int getArgumentCount() { + return base.getArgumentCount(); + } + + public Map getAllScopedEntities() { + return base.getAllScopedEntities(); + } + + public Iterator getScopedEntities(CAstNode construct) { + return base.getScopedEntities(construct); + } + + public CAstNode getAST() { + return base.getAST(); + } + + public CAstControlFlowMap getControlFlow() { + return base.getControlFlow(); + } + + public CAstSourcePositionMap getSourceMap() { + return base.getSourceMap(); + } + + public CAstSourcePositionMap.Position getPosition() { + return base.getPosition(); + } + + public CAstNodeTypeMap getNodeTypeMap() { + return base.getNodeTypeMap(); + } + + public Collection getQualifiers() { + return base.getQualifiers(); + } + + public CAstType getType() { + return base.getType(); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/LineNumberPosition.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/LineNumberPosition.java new file mode 100644 index 000000000..fa07d1f9c --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/impl/LineNumberPosition.java @@ -0,0 +1,46 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree.impl; + +import com.ibm.wala.cast.tree.*; + +import java.io.*; +import java.net.*; + +public class LineNumberPosition extends AbstractSourcePosition { + private final URL url; + private final URL localFile; + private final int lineNumber; + + public LineNumberPosition(URL url, URL localFile, int lineNumber) { + this.url = url; + this.localFile = localFile; + this.lineNumber = lineNumber; + } + + public int getFirstLine() { return lineNumber; } + + public int getLastLine() { return lineNumber; } + + public int getFirstCol() { return -1; } + + public int getLastCol() { return -1; } + + public URL getURL() { return url; } + + public InputStream getInputStream() throws IOException { + return localFile.openConnection().getInputStream(); + } + + public String toString() { + return "[line:"+lineNumber+"]"; + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/visit/CAstVisitor.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/visit/CAstVisitor.java new file mode 100644 index 000000000..bb0f7d856 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/visit/CAstVisitor.java @@ -0,0 +1,1591 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree.visit; + +import com.ibm.wala.cast.tree.*; +import com.ibm.wala.cast.util.CAstPrinter; +import com.ibm.wala.util.debug.Assertions; +import com.ibm.wala.util.debug.Trace; + +import java.util.*; + +/** + * @author Igor Peshansky + * Ripped out of Julian's AstTranslator + * TODO: document me. + */ +public abstract class CAstVisitor { + + /** + * This interface represents a visitor-specific context. All + * it knows is how to get its top-level entity. It is expected + * that visitors will have classes implementing this interface + * to collect visitor-specific information. + * + * @author Igor Peshansky + */ + public interface Context { + CAstEntity top(); + } + + /** + * Construct a context for a File entity. + * @param context a visitor-specific context in which this file was visited + * @param n the file entity + */ + protected Context makeFileContext(Context context, CAstEntity n) { return context; } + /** + * Construct a context for a Type entity. + * @param context a visitor-specific context in which this type was visited + * @param n the type entity + */ + protected Context makeTypeContext(Context context, CAstEntity n) { return context; } + /** + * Construct a context for a Code entity. + * @param context a visitor-specific context in which the code was visited + * @param n the code entity + */ + protected Context makeCodeContext(Context context, CAstEntity n) { return context; } + + /** + * Construct a context for a LocalScope node. + * @param context a visitor-specific context in which the local scope was visited + * @param n the local scope node + */ + protected Context makeLocalContext(Context context, CAstNode n) { return context; } + /** + * Construct a context for an Unwind node. + * @param context a visitor-specific context in which the unwind was visited + * @param n the unwind node + */ + protected Context makeUnwindContext(Context context, CAstNode n, CAstVisitor visitor) { return context; } + + private final Map entityParents = new HashMap(); + + /** + * Get the parent entity for a given entity. + * @param entity the child entity + * @return the parent entity for the given entity + */ + protected CAstEntity getParent(CAstEntity entity) { + return (CAstEntity) entityParents.get(entity); + } + + /** + * Set the parent entity for a given entity. + * @param entity the child entity + * @param parent the parent entity + */ + protected void setParent(CAstEntity entity, CAstEntity parent) { + entityParents.put(entity, parent); + } + + /** + * Entity processing hook; sub-classes are expected to override if they introduce new + * entity types. + * Should invoke super.doVisitEntity() for unprocessed entities. + * @return true if entity was handled + */ + protected boolean doVisitEntity(CAstEntity n, Context context, CAstVisitor visitor) { + return false; + } + + + /** + * Visit scoped entities of an entity using a given iterator. + * Prerequisite (unchecked): i iterates over entities scoped in n. + * @param n the parent entity of the entities to process + * @param i the iterator over some scoped entities of n + * @param context a visitor-specific context + */ + public final void visitScopedEntities(CAstEntity n, Map allScopedEntities, Context context, CAstVisitor visitor) { + for(Iterator i = allScopedEntities.values().iterator(); i.hasNext(); ) { + visitScopedEntities(n, ((Collection)i.next()).iterator(), context, visitor); + } + } + + public final void visitScopedEntities(CAstEntity n, Iterator i, Context context, CAstVisitor visitor) { + while (i.hasNext()) { + CAstEntity child = (CAstEntity) i.next(); + setParent(child, n); + visitor.visitEntities(child, context, visitor); + } + } + /** + * Recursively visit an entity. + * @param n the entity to process + * @param context a visitor-specific context + */ + public final void visitEntities(final CAstEntity n, Context context, CAstVisitor visitor) { + if (visitor.enterEntity(n, context, visitor)) + return; + switch (n.getKind()) { + case CAstEntity.FILE_ENTITY: { + Context fileContext = visitor.makeFileContext(context, n); + if (visitor.visitFileEntity(n, context, fileContext, visitor)) + break; + visitor.visitScopedEntities(n, n.getAllScopedEntities(), fileContext, visitor); + visitor.leaveFileEntity(n, context, fileContext, visitor); + break; + } + case CAstEntity.FIELD_ENTITY: { + if (visitor.visitFieldEntity(n, context, visitor)) + break; + visitor.leaveFieldEntity(n, context, visitor); + break; + } + case CAstEntity.TYPE_ENTITY: { + Context typeContext = visitor.makeTypeContext(context, n); + if (visitor.visitTypeEntity(n, context, typeContext, visitor)) + break; + visitor.visitScopedEntities(n, n.getAllScopedEntities(), typeContext, visitor); + visitor.leaveTypeEntity(n, context, typeContext, visitor); + break; + } + case CAstEntity.FUNCTION_ENTITY: { + Context codeContext = visitor.makeCodeContext(context, n); + if (visitor.visitFunctionEntity(n, context, codeContext, visitor)) + break; + // visit the AST if any + if (n.getAST() != null) + visitor.visit(n.getAST(), codeContext, visitor); + // XXX: there may be code that needs to go in here + // process any remaining scoped children + visitor.visitScopedEntities(n, n.getScopedEntities(null), codeContext, visitor); + visitor.leaveFunctionEntity(n, context, codeContext, visitor); + break; + } + case CAstEntity.SCRIPT_ENTITY: { + Context codeContext = visitor.makeCodeContext(context, n); + if (visitor.visitScriptEntity(n, context, codeContext, visitor)) + break; + // visit the AST if any + if (n.getAST() != null) + visitor.visit(n.getAST(), codeContext, visitor); + // XXX: there may be code that needs to go in here + // process any remaining scoped children + visitor.visitScopedEntities(n, n.getScopedEntities(null), codeContext, visitor); + visitor.leaveScriptEntity(n, context, codeContext, visitor); + break; + } + default: { + if (!visitor.doVisitEntity(n, context, visitor)) { + Trace.println("No handler for entity " + n.getName()); + Assertions.UNREACHABLE("cannot handle entity of kind" + n.getKind()); + } + } + } + visitor.postProcessEntity(n, context, visitor); + } + + /** + * Enter the entity visitor. + * @param n the entity to process + * @param context a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean enterEntity(CAstEntity n, Context context, CAstVisitor visitor) { return false; } + /** + * Post-process an entity after visiting it. + * @param n the entity to process + * @param context a visitor-specific context + */ + protected void postProcessEntity(CAstEntity n, Context context, CAstVisitor visitor) { return; } + + /** + * Visit any entity. Override only this to change behavior for all entities. + * @param n the entity to process + * @param context a visitor-specific context + * @return true if no further processing is needed + */ + public boolean visitEntity(CAstEntity n, Context context, CAstVisitor visitor) { return false; } + /** + * Leave any entity. Override only this to change behavior for all entities. + * @param n the entity to process + * @param context a visitor-specific context + */ + public void leaveEntity(CAstEntity n, Context context, CAstVisitor visitor) { return; } + + /** + * Visit a File entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param fileContext a visitor-specific context for this file + * @return true if no further processing is needed + */ + protected boolean visitFileEntity(CAstEntity n, Context context, Context fileContext, CAstVisitor visitor) { return visitor.visitEntity(n, context, visitor); } + /** + * Leave a File entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param fileContext a visitor-specific context for this file + */ + protected void leaveFileEntity(CAstEntity n, Context context, Context fileContext, CAstVisitor visitor) { visitor.leaveEntity(n, context, visitor); } + /** + * Visit a Field entity. + * @param n the entity to process + * @param context a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitFieldEntity(CAstEntity n, Context context, CAstVisitor visitor) { return visitor.visitEntity(n, context, visitor); } + /** + * Leave a Field entity. + * @param n the entity to process + * @param context a visitor-specific context + */ + protected void leaveFieldEntity(CAstEntity n, Context context, CAstVisitor visitor) { visitor.leaveEntity(n, context, visitor); } + /** + * Visit a Type entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param typeContext a visitor-specific context for this type + * @return true if no further processing is needed + */ + protected boolean visitTypeEntity(CAstEntity n, Context context, Context typeContext, CAstVisitor visitor) { return visitor.visitEntity(n, context, visitor); } + /** + * Leave a Type entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param typeContext a visitor-specific context for this type + */ + protected void leaveTypeEntity(CAstEntity n, Context context, Context typeContext, CAstVisitor visitor) { visitor.leaveEntity(n, context, visitor); } + /** + * Visit a Function entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param codeContext a visitor-specific context for this function + * @return true if no further processing is needed + */ + protected boolean visitFunctionEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) { return visitor.visitEntity(n, context, visitor); } + /** + * Leave a Function entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param codeContext a visitor-specific context for this function + */ + protected void leaveFunctionEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) { visitor.leaveEntity(n, context, visitor); } + /** + * Visit a Script entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param codeContext a visitor-specific context for this script + * @return true if no further processing is needed + */ + protected boolean visitScriptEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) { return visitor.visitEntity(n, context, visitor); } + /** + * Leave a Script entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param codeContext a visitor-specific context for this script + */ + protected void leaveScriptEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) { visitor.leaveEntity(n, context, visitor); } + + /** + * Node processing hook; sub-classes are expected to override if they + * introduce new node types. + * + * (Should invoke super.doVisit() for unprocessed nodes.) + * + * @return true if node was handled + */ + protected boolean doVisit(CAstNode n, Context context, CAstVisitor visitor) { + return false; + } + + /** + * Node processing hook; sub-classes are expected to override if they + * introduce new node types that appear on the left hand side of assignment + * operations. + * + * (Should invoke super.doVisit() for unprocessed nodes.) + * + * @return true if node was handled + */ + protected boolean doVisitAssignNodes(CAstNode n, Context context, CAstNode v, CAstNode a, CAstVisitor visitor) { + return false; + } + + /** + * Visit children of a node starting at a given index. + * @param n the parent node of the nodes to process + * @param start the starting index of the nodes to process + * @param context a visitor-specific context + */ + public final void visitChildren(CAstNode n, int start, Context context, CAstVisitor visitor) { + int end = n.getChildCount(); + for (int i = start; i < end; i++) + visitor.visit(n.getChild(i), context, visitor); + } + /** + * Visit all children of a node. + * @param n the parent node of the nodes to process + * @param context a visitor-specific context + */ + public final void visitAllChildren(CAstNode n, Context context, CAstVisitor visitor) { + visitor.visitChildren(n, 0, context, visitor); + } + /** + * Recursively visit a given node. + * TODO: do assertions about structure belong here? + * @param n the node to process + * @param context a visitor-specific context + */ + public final void visit(final CAstNode n, Context context, CAstVisitor visitor) { + if (visitor.enterNode(n, context, visitor)) + return; + + int NT = n.getKind(); + switch (NT) { + case CAstNode.FUNCTION_EXPR: { + if (visitor.visitFunctionExpr(n, context, visitor)) + break; + visitor.leaveFunctionExpr(n, context, visitor); + break; + } + + case CAstNode.FUNCTION_STMT: { + if (visitor.visitFunctionStmt(n, context, visitor)) + break; + visitor.leaveFunctionStmt(n, context, visitor); + break; + } + + case CAstNode.LOCAL_SCOPE: { + if (visitor.visitLocalScope(n, context, visitor)) + break; + Context localContext = visitor.makeLocalContext(context, n); + visitor.visit(n.getChild(0), localContext, visitor); + visitor.leaveLocalScope(n, context, visitor); + break; + } + + case CAstNode.BLOCK_EXPR: { + if (visitor.visitBlockExpr(n, context, visitor)) + break; + visitor.visitAllChildren(n, context, visitor); + visitor.leaveBlockExpr(n, context, visitor); + break; + } + + case CAstNode.BLOCK_STMT: { + if (visitor.visitBlockStmt(n, context, visitor)) + break; + visitor.visitAllChildren(n, context, visitor); + visitor.leaveBlockStmt(n, context, visitor); + break; + } + + case CAstNode.LOOP: { + if (visitor.visitLoop(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveLoopHeader(n, context, visitor); + visitor.visit(n.getChild(1), context, visitor); + visitor.leaveLoop(n, context, visitor); + break; + } + + case CAstNode.GET_CAUGHT_EXCEPTION: { + if (visitor.visitGetCaughtException(n, context, visitor)) + break; + visitor.leaveGetCaughtException(n, context, visitor); + break; + } + + case CAstNode.THIS: { + if (visitor.visitThis(n, context, visitor)) + break; + visitor.leaveThis(n, context, visitor); + break; + } + + case CAstNode.SUPER: { + if (visitor.visitSuper(n, context, visitor)) + break; + visitor.leaveSuper(n, context, visitor); + break; + } + + case CAstNode.CALL: { + if (visitor.visitCall(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.visitChildren(n, 2, context, visitor); + visitor.leaveCall(n, context, visitor); + break; + } + + case CAstNode.VAR: { + if (visitor.visitVar(n, context, visitor)) + break; + visitor.leaveVar(n, context, visitor); + break; + } + + case CAstNode.CONSTANT: { + if (visitor.visitConstant(n, context, visitor)) + break; + visitor.leaveConstant(n, context, visitor); + break; + } + + case CAstNode.BINARY_EXPR: { + if (visitor.visitBinaryExpr(n, context, visitor)) + break; + visitor.visit(n.getChild(1), context, visitor); + visitor.visit(n.getChild(2), context, visitor); + visitor.leaveBinaryExpr(n, context, visitor); + break; + } + + case CAstNode.UNARY_EXPR: { + if (visitor.visitUnaryExpr(n, context, visitor)) + break; + visitor.visit(n.getChild(1), context, visitor); + visitor.leaveUnaryExpr(n, context, visitor); + break; + } + + case CAstNode.ARRAY_LENGTH: { + if (visitor.visitArrayLength(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveArrayLength(n, context, visitor); + break; + } + + case CAstNode.ARRAY_REF: { + if (visitor.visitArrayRef(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.visitChildren(n, 2, context, visitor); + visitor.leaveArrayRef(n, context, visitor); + break; + } + + case CAstNode.DECL_STMT: { + if (visitor.visitDeclStmt(n, context, visitor)) + break; + if (n.getChildCount() == 4) + visitor.visit(n.getChild(3), context, visitor); + visitor.leaveDeclStmt(n, context, visitor); + break; + } + + case CAstNode.RETURN: { + if (visitor.visitReturn(n, context, visitor)) + break; + if (n.getChildCount() > 0) + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveReturn(n, context, visitor); + break; + } + + case CAstNode.IFGOTO: { + if (visitor.visitIfgoto(n, context, visitor)) + break; + if (n.getChildCount() == 1) { + visitor.visit(n.getChild(0), context, visitor); + } else if (n.getChildCount() == 3) { + visitor.visit(n.getChild(1), context, visitor); + visitor.visit(n.getChild(2), context, visitor); + } else { + Assertions.UNREACHABLE(); + } + + visitor.leaveIfgoto(n, context, visitor); + break; + } + + case CAstNode.GOTO: { + if (visitor.visitGoto(n, context, visitor)) + break; + visitor.leaveGoto(n, context, visitor); + break; + } + + case CAstNode.LABEL_STMT: { + if (visitor.visitLabelStmt(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + if (n.getChildCount() == 2) + visitor.visit(n.getChild(1), context, visitor); + else // FIXME: this doesn't belong here + Assertions._assert(n.getChildCount() < 2); + visitor.leaveLabelStmt(n, context, visitor); + break; + } + + case CAstNode.IF_STMT: { + if (visitor.visitIfStmt(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveIfStmtCondition(n, context, visitor); + visitor.visit(n.getChild(1), context, visitor); + visitor.leaveIfStmtTrueClause(n, context, visitor); + if (n.getChildCount() == 3) + visitor.visit(n.getChild(2), context, visitor); + visitor.leaveIfStmt(n, context, visitor); + break; + } + + case CAstNode.IF_EXPR: { + if (visitor.visitIfExpr(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveIfExprCondition(n, context, visitor); + visitor.visit(n.getChild(1), context, visitor); + visitor.leaveIfExprTrueClause(n, context, visitor); + if (n.getChildCount() == 3) + visitor.visit(n.getChild(2), context, visitor); + visitor.leaveIfExpr(n, context, visitor); + break; + } + + case CAstNode.NEW: { + if (visitor.visitNew(n, context, visitor)) + break; + + for(int i = 1; i < n.getChildCount(); i++) { + visitor.visit(n.getChild(i), context, visitor); + } + + visitor.leaveNew(n, context, visitor); + break; + } + + case CAstNode.OBJECT_LITERAL: { + if (visitor.visitObjectLiteral(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + for (int i = 1; i < n.getChildCount(); i+=2) { + visitor.visit(n.getChild(i), context, visitor); + visitor.visit(n.getChild(i+1), context, visitor); + visitor.leaveObjectLiteralFieldInit(n, i, context, visitor); + } + visitor.leaveObjectLiteral(n, context, visitor); + break; + } + + case CAstNode.ARRAY_LITERAL: { + if (visitor.visitArrayLiteral(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveArrayLiteralObject(n, context, visitor); + for (int i = 1; i < n.getChildCount(); i++) { + visitor.visit(n.getChild(i), context, visitor); + visitor.leaveArrayLiteralInitElement(n, i, context, visitor); + } + visitor.leaveArrayLiteral(n, context, visitor); + break; + } + + case CAstNode.OBJECT_REF: { + if (visitor.visitObjectRef(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveObjectRef(n, context, visitor); + break; + } + + case CAstNode.ASSIGN: + case CAstNode.ASSIGN_PRE_OP: + case CAstNode.ASSIGN_POST_OP: { + if (visitor.visitAssign(n, context, visitor)) + break; + visitor.visit(n.getChild(1), context, visitor); + // TODO: is this correct? + if (visitor.visitAssignNodes(n.getChild(0), context, n.getChild(1), n, visitor)) + break; + visitor.leaveAssign(n, context, visitor); + break; + } + + case CAstNode.SWITCH: { + if (visitor.visitSwitch(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveSwitchValue(n, context, visitor); + visitor.visit(n.getChild(1), context, visitor); + visitor.leaveSwitch(n, context, visitor); + break; + } + + case CAstNode.THROW: { + if (visitor.visitThrow(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveThrow(n, context, visitor); + break; + } + + case CAstNode.CATCH: { + if (visitor.visitCatch(n, context, visitor)) + break; + visitor.visitChildren(n, 1, context, visitor); + visitor.leaveCatch(n, context, visitor); + break; + } + + case CAstNode.UNWIND: { + if (visitor.visitUnwind(n, context, visitor)) + break; + Context unwindContext = visitor.makeUnwindContext(context, n.getChild(1), visitor); + visitor.visit(n.getChild(0), unwindContext, visitor); + visitor.visit(n.getChild(1), context, visitor); + visitor.leaveUnwind(n, context, visitor); + break; + } + + case CAstNode.TRY: { + if (visitor.visitTry(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveTryBlock(n, context, visitor); + visitor.visit(n.getChild(1), context, visitor); + visitor.leaveTry(n, context, visitor); + break; + } + + case CAstNode.EMPTY: { + if (visitor.visitEmpty(n, context, visitor)) + break; + visitor.leaveEmpty(n, context, visitor); + break; + } + + case CAstNode.PRIMITIVE: { + if (visitor.visitPrimitive(n, context, visitor)) + break; + visitor.leavePrimitive(n, context, visitor); + break; + } + + case CAstNode.VOID: { + if (visitor.visitVoid(n, context, visitor)) + break; + visitor.leaveVoid(n, context, visitor); + break; + } + + case CAstNode.CAST: { + if (visitor.visitCast(n, context, visitor)) + break; + visitor.visit(n.getChild(1), context, visitor); + visitor.leaveCast(n, context, visitor); + break; + } + + case CAstNode.INSTANCEOF: { + if (visitor.visitInstanceOf(n, context, visitor)) + break; + visitor.visit(n.getChild(1), context, visitor); + visitor.leaveInstanceOf(n, context, visitor); + break; + } + + case CAstNode.ASSERT: { + if (visitor.visitAssert(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveAssert(n, context, visitor); + break; + } + + case CAstNode.EACH_ELEMENT_GET: { + if (visitor.visitEachElementGet(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveEachElementGet(n, context, visitor); + break; + } + + case CAstNode.EACH_ELEMENT_HAS_NEXT: { + if (visitor.visitEachElementHasNext(n, context, visitor)) + break; + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveEachElementHasNext(n, context, visitor); + break; + } + + case CAstNode.TYPE_LITERAL_EXPR: { + if (visitor.visitTypeLiteralExpr(n, context, visitor)) { + break; + } + visitor.visit(n.getChild(0), context, visitor); + visitor.leaveTypeLiteralExpr(n, context, visitor); + break; + } + + default: { + if (!visitor.doVisit(n, context, visitor)) { + Trace.println("looking at unhandled " + n + "(" + NT + ")" + " of " + n.getClass()); + Assertions.UNREACHABLE("cannot handle node of kind " + NT); + } + } + } + + if (context != null) { + visitor.visitScopedEntities(context.top(), context.top().getScopedEntities(n), context, visitor); + } + + visitor.postProcessNode(n, context, visitor); + } + + protected boolean visitAssignNodes(CAstNode n, Context context, CAstNode v, CAstNode a, CAstVisitor visitor) { + int NT = a.getKind(); + boolean assign = NT == CAstNode.ASSIGN; + boolean preOp = NT == CAstNode.ASSIGN_PRE_OP; + switch (n.getKind()) { + case CAstNode.ARRAY_REF: { + if (assign ? visitor.visitArrayRefAssign(n, v, a, context, visitor) + : visitor.visitArrayRefAssignOp(n, v, a, preOp, context, visitor)) + return true; + visitor.visit(n.getChild(0), context, visitor); + // XXX: we don't really need to visit array dims twice! + visitor.visitChildren(n, 2, context, visitor); + if (assign) + visitor.leaveArrayRefAssign(n, v, a, context, visitor); + else + visitor.leaveArrayRefAssignOp(n, v, a, preOp, context, visitor); + break; + } + + case CAstNode.OBJECT_REF: { + if (assign ? visitor.visitObjectRefAssign(n, v, a, context, visitor) + : visitor.visitObjectRefAssignOp(n, v, a, preOp, context, visitor)) + return true; + visitor.visit(n.getChild(0), context, visitor); + if (assign) + visitor.leaveObjectRefAssign(n, v, a, context, visitor); + else + visitor.leaveObjectRefAssignOp(n, v, a, preOp, context, visitor); + break; + } + + case CAstNode.BLOCK_EXPR: { + if (assign ? visitor.visitBlockExprAssign(n, v, a, context, visitor) + : visitor.visitBlockExprAssignOp(n, v, a, preOp, context, visitor)) + return true; + // FIXME: is it correct to ignore all the other children? + if (visitor.visitAssignNodes(n.getChild(n.getChildCount() - 1), context, v, a, visitor)) + return true; + if (assign) + visitor.leaveBlockExprAssign(n, v, a, context, visitor); + else + visitor.leaveBlockExprAssignOp(n, v, a, preOp, context, visitor); + break; + } + + case CAstNode.VAR: { + if (assign ? visitor.visitVarAssign(n, v, a, context, visitor) + : visitor.visitVarAssignOp(n, v, a, preOp, context, visitor)) + return true; + if (assign) + visitor.leaveVarAssign(n, v, a, context, visitor); + else + visitor.leaveVarAssignOp(n, v, a, preOp, context, visitor); + break; + } + + default: { + if (!visitor.doVisitAssignNodes(n, context, v, a, visitor)) { + Trace.println("cannot handle assign to kind " + n.getKind()); + throw new UnsupportedOperationException( + "cannot handle assignment: " + + CAstPrinter.print(a, context.top().getSourceMap())); + } + } + } + return false; + } + + /** + * Enter the node visitor. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean enterNode(CAstNode n, Context c, CAstVisitor visitor) { return false; } + /** + * Post-process a node after visiting it. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void postProcessNode(CAstNode n, Context c, CAstVisitor visitor) { return; } + + /** + * Visit any node. Override only this to change behavior for all nodes. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + public boolean visitNode(CAstNode n, Context c, CAstVisitor visitor) { return false; } + /** + * Leave any node. Override only this to change behavior for all nodes. + * @param n the node to process + * @param c a visitor-specific context + */ + public void leaveNode(CAstNode n, Context c, CAstVisitor visitor) { return; } + + /** + * Visit a FunctionExpr node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitFunctionExpr(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a FunctionExpr node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveFunctionExpr(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a FunctionStmt node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitFunctionStmt(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a FunctionStmt node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveFunctionStmt(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a LocalScope node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitLocalScope(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a LocalScope node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveLocalScope(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a BlockExpr node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitBlockExpr(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a BlockExpr node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveBlockExpr(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a BlockStmt node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitBlockStmt(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a BlockStmt node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveBlockStmt(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Loop node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitLoop(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Visit a Loop node after processing the loop header. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveLoopHeader(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Leave a Loop node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveLoop(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a GetCaughtException node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitGetCaughtException(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a GetCaughtException node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveGetCaughtException(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a This node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitThis(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a This node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveThis(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Super node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitSuper(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a Super node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveSuper(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Call node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitCall(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a Call node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveCall(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Var node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitVar(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a Var node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveVar(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Constant node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitConstant(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a Constant node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveConstant(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a BinaryExpr node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitBinaryExpr(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a BinaryExpr node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveBinaryExpr(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a UnaryExpr node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitUnaryExpr(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a UnaryExpr node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveUnaryExpr(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an ArrayLength node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitArrayLength(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave an ArrayLength node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveArrayLength(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an ArrayRef node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitArrayRef(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave an ArrayRef node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveArrayRef(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a DeclStmt node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitDeclStmt(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a DeclStmt node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveDeclStmt(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Return node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitReturn(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a Return node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveReturn(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an Ifgoto node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitIfgoto(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave an Ifgoto node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfgoto(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Goto node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitGoto(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a Goto node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveGoto(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a LabelStmt node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitLabelStmt(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a LabelStmt node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveLabelStmt(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an IfStmt node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitIfStmt(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Visit an IfStmt node after processing the condition. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfStmtCondition(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Visit an IfStmt node after processing the true clause. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfStmtTrueClause(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Leave an IfStmt node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfStmt(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an IfExpr node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitIfExpr(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Visit an IfExpr node after processing the condition. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfExprCondition(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Visit an IfExpr node after processing the true clause. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfExprTrueClause(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Leave an IfExpr node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfExpr(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a New node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitNew(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a New node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveNew(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an ObjectLiteral node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitObjectLiteral(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Visit an ObjectLiteral node after processing the {i}th field initializer. + * @param n the node to process + * @param i the field position that was initialized + * @param c a visitor-specific context + */ + protected void leaveObjectLiteralFieldInit(CAstNode n, int i, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Leave an ObjectLiteral node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveObjectLiteral(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an ArrayLiteral node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitArrayLiteral(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Visit an ArrayLiteral node after processing the array object. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveArrayLiteralObject(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Visit an ArrayLiteral node after processing the {i}th element initializer. + * @param n the node to process + * @param i the index that was initialized + * @param c a visitor-specific context + */ + protected void leaveArrayLiteralInitElement(CAstNode n, int i, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Leave a ArrayLiteral node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveArrayLiteral(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an ObjectRef node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitObjectRef(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave an ObjectRef node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveObjectRef(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an Assign node. Override only this to change behavior for all assignment nodes. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + public boolean visitAssign(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave an Assign node. Override only this to change behavior for all assignment nodes. + * @param n the node to process + * @param c a visitor-specific context + */ + public void leaveAssign(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an ArrayRef Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitArrayRefAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { /* empty */ return false; } + /** + * Visit an ArrayRef Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + */ + protected void leaveArrayRefAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Visit an ArrayRef Op/Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitArrayRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ return false; } + /** + * Visit an ArrayRef Op/Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + */ + protected void leaveArrayRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Visit an ObjectRef Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitObjectRefAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { /* empty */ return false; } + /** + * Visit an ObjectRef Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + */ + protected void leaveObjectRefAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Visit an ObjectRef Op/Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ return false; } + /** + * Visit an ObjectRef Op/Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + */ + protected void leaveObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Visit a BlockExpr Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitBlockExprAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { /* empty */ return false; } + /** + * Visit a BlockExpr Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + */ + protected void leaveBlockExprAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Visit a BlockExpr Op/Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitBlockExprAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ return false; } + /** + * Visit a BlockExpr Op/Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + */ + protected void leaveBlockExprAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Visit a Var Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitVarAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { /* empty */ return false; } + /** + * Visit a Var Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + */ + protected void leaveVarAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Visit a Var Op/Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitVarAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ return false; } + /** + * Visit a Var Op/Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + */ + protected void leaveVarAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Visit a Switch node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitSwitch(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Visit a Switch node after processing the switch value. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveSwitchValue(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Leave a Switch node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveSwitch(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Throw node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitThrow(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a Throw node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveThrow(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Catch node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitCatch(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a Catch node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveCatch(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an Unwind node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitUnwind(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave an Unwind node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveUnwind(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Try node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitTry(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Visit a Try node after processing the try block. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveTryBlock(CAstNode n, Context c, CAstVisitor visitor) { /* empty */ } + /** + * Leave a Try node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveTry(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an Empty node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitEmpty(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave an Empty node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveEmpty(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Primitive node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitPrimitive(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a Primitive node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leavePrimitive(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Void node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitVoid(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a Void node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveVoid(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit a Cast node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitCast(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave a Cast node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveCast(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an InstanceOf node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitInstanceOf(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave an InstanceOf node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveInstanceOf(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an InstanceOf node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitAssert(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave an InstanceOf node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveAssert(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an InstanceOf node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitEachElementHasNext(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave an InstanceOf node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveEachElementHasNext(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an InstanceOf node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitEachElementGet(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave an FOR_EACH_ELEMENT_GET node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveEachElementGet(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } + /** + * Visit an TYPE_LITERAL_EXPR node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitTypeLiteralExpr(CAstNode n, Context c, CAstVisitor visitor) { return visitor.visitNode(n, c, visitor); } + /** + * Leave an TYPE_LITERAL_EXPR node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveTypeLiteralExpr(CAstNode n, Context c, CAstVisitor visitor) { visitor.leaveNode(n, c, visitor); } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/visit/DelegatingCAstVisitor.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/visit/DelegatingCAstVisitor.java new file mode 100644 index 000000000..77287bc84 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/tree/visit/DelegatingCAstVisitor.java @@ -0,0 +1,1188 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.tree.visit; + +import com.ibm.wala.cast.tree.*; +import com.ibm.wala.util.debug.Assertions; + +/** + * @author Igor Peshansky + * Extend CAstVisitor to delegate unimplemented functionality to another + * visitor. Needed to work around Java's retarded multiple inheritance rules. + * TODO: document me. + */ +public abstract class DelegatingCAstVisitor extends CAstVisitor { + + /** + * Construct a context for a File entity or delegate by default. + * @param context a visitor-specific context in which this file was visited + * @param n the file entity + */ + protected Context makeFileContext(Context context, CAstEntity n) { + return delegate.makeFileContext(context, n); + } + /** + * Construct a context for a Type entity or delegate by default. + * @param context a visitor-specific context in which this type was visited + * @param n the type entity + */ + protected Context makeTypeContext(Context context, CAstEntity n) { + return delegate.makeTypeContext(context, n); + } + /** + * Construct a context for a Code entity or delegate by default. + * @param context a visitor-specific context in which the code was visited + * @param n the code entity + */ + protected Context makeCodeContext(Context context, CAstEntity n) { + return delegate.makeCodeContext(context, n); + } + + /** + * Construct a context for a LocalScope node or delegate by default. + * @param context a visitor-specific context in which the local scope was visited + * @param n the local scope node + */ + protected Context makeLocalContext(Context context, CAstNode n) { + return delegate.makeLocalContext(context, n); + } + /** + * Construct a context for an Unwind node or delegate by default. + * @param context a visitor-specific context in which the unwind was visited + * @param n the unwind node + */ + protected Context makeUnwindContext(Context context, CAstNode n, CAstVisitor visitor) { + return delegate.makeUnwindContext(context, n, visitor); + } + + /** + * Get the parent entity for a given entity. + * @param entity the child entity + * @return the parent entity for the given entity + */ + protected CAstEntity getParent(CAstEntity entity) { + return delegate.getParent(entity); + } + + /** + * Set the parent entity for a given entity. + * @param entity the child entity + * @param parent the parent entity + */ + protected void setParent(CAstEntity entity, CAstEntity parent) { + delegate.setParent(entity, parent); + } + + private final CAstVisitor delegate; + + protected final CAstVisitor delegate() { return delegate; } + + /** + * Delegating CAstVisitor constructor. + * Needs to have a valid (non-null) delegate visitor. + * @param delegate the visitor to delegate to for default implementation + */ + protected DelegatingCAstVisitor(CAstVisitor delegate) { + Assertions._assert(delegate != null); + this.delegate = delegate; + } + + /** + * Entity processing hook; sub-classes are expected to override if they + * introduce new entity types. + * Should invoke super.doVisitEntity() for unprocessed entities. + * @return true if entity was handled + */ + protected boolean doVisitEntity(CAstEntity n, Context context, CAstVisitor visitor) { + return delegate.doVisitEntity(n, context, visitor); + } + + /** + * Enter the entity visitor. + * @param n the entity to process + * @param context a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean enterEntity(CAstEntity n, Context context, CAstVisitor visitor) { + return delegate.enterEntity(n, context, visitor); + } + /** + * Post-process an entity after visiting it. + * @param n the entity to process + * @param context a visitor-specific context + */ + protected void postProcessEntity(CAstEntity n, Context context, CAstVisitor visitor) { + delegate.postProcessEntity(n, context, visitor); + } + + /** + * Visit any entity. Override only this to change behavior for all entities. + * @param n the entity to process + * @param context a visitor-specific context + * @return true if no further processing is needed + */ + public boolean visitEntity(CAstEntity n, Context context, CAstVisitor visitor) { + return delegate.visitEntity(n, context, visitor); + } + /** + * Leave any entity. Override only this to change behavior for all entities. + * @param n the entity to process + * @param context a visitor-specific context + */ + public void leaveEntity(CAstEntity n, Context context, CAstVisitor visitor) { + delegate.leaveEntity(n, context, visitor); + } + + /** + * Visit a File entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param fileContext a visitor-specific context for this file + * @return true if no further processing is needed + */ + protected boolean visitFileEntity(CAstEntity n, Context context, Context fileContext, CAstVisitor visitor) { + return delegate.visitFileEntity(n, context, fileContext, visitor); + } + /** + * Leave a File entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param fileContext a visitor-specific context for this file + */ + protected void leaveFileEntity(CAstEntity n, Context context, Context fileContext, CAstVisitor visitor) { + delegate.leaveFileEntity(n, context, fileContext, visitor); + } + /** + * Visit a Field entity. + * @param n the entity to process + * @param context a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitFieldEntity(CAstEntity n, Context context, CAstVisitor visitor) { + return delegate.visitFieldEntity(n, context, visitor); + } + /** + * Leave a Field entity. + * @param n the entity to process + * @param context a visitor-specific context + */ + protected void leaveFieldEntity(CAstEntity n, Context context, CAstVisitor visitor) { + delegate.leaveFieldEntity(n, context, visitor); + } + /** + * Visit a Type entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param typeContext a visitor-specific context for this type + * @return true if no further processing is needed + */ + protected boolean visitTypeEntity(CAstEntity n, Context context, Context typeContext, CAstVisitor visitor) { + return delegate.visitTypeEntity(n, context, typeContext, visitor); + } + /** + * Leave a Type entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param typeContext a visitor-specific context for this type + */ + protected void leaveTypeEntity(CAstEntity n, Context context, Context typeContext, CAstVisitor visitor) { + delegate.leaveTypeEntity(n, context, typeContext, visitor); + } + /** + * Visit a Function entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param codeContext a visitor-specific context for this function + * @return true if no further processing is needed + */ + protected boolean visitFunctionEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) { + return delegate.visitFunctionEntity(n, context, codeContext, visitor); + } + /** + * Leave a Function entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param codeContext a visitor-specific context for this function + */ + protected void leaveFunctionEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) { + delegate.leaveFunctionEntity(n, context, codeContext, visitor); + } + /** + * Visit a Script entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param codeContext a visitor-specific context for this script + * @return true if no further processing is needed + */ + protected boolean visitScriptEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) { + return delegate.visitScriptEntity(n, context, codeContext, visitor); + } + /** + * Leave a Script entity. + * @param n the entity to process + * @param context a visitor-specific context + * @param codeContext a visitor-specific context for this script + */ + protected void leaveScriptEntity(CAstEntity n, Context context, Context codeContext, CAstVisitor visitor) { + delegate.leaveScriptEntity(n, context, codeContext, visitor); + } + + /** + * Node processing hook; sub-classes are expected to override if they + * introduce new node types. + * Should invoke super.doVisit() for unprocessed nodes. + * @return true if node was handled + */ + protected boolean doVisit(CAstNode n, Context context, CAstVisitor visitor) { + return delegate.doVisit(n, context, visitor); + } + + /** + * Enter the node visitor. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean enterNode(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.enterNode(n, c, visitor); + } + /** + * Post-process a node after visiting it. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void postProcessNode(CAstNode n, Context c, CAstVisitor visitor) { + delegate.postProcessNode(n, c, visitor); + } + + /** + * Visit any node. Override only this to change behavior for all nodes. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + public boolean visitNode(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitNode(n, c, visitor); + } + /** + * Leave any node. Override only this to change behavior for all nodes. + * @param n the node to process + * @param c a visitor-specific context + */ + public void leaveNode(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveNode(n, c, visitor); + } + + /** + * Visit a FunctionExpr node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitFunctionExpr(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitFunctionExpr(n, c, visitor); + } + /** + * Leave a FunctionExpr node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveFunctionExpr(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveFunctionExpr(n, c, visitor); + } + /** + * Visit a FunctionStmt node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitFunctionStmt(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitFunctionStmt(n, c, visitor); + } + /** + * Leave a FunctionStmt node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveFunctionStmt(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveFunctionStmt(n, c, visitor); + } + /** + * Visit a LocalScope node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitLocalScope(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitLocalScope(n, c, visitor); + } + /** + * Leave a LocalScope node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveLocalScope(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveLocalScope(n, c, visitor); + } + /** + * Visit a BlockExpr node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitBlockExpr(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitBlockExpr(n, c, visitor); + } + /** + * Leave a BlockExpr node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveBlockExpr(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveBlockExpr(n, c, visitor); + } + /** + * Visit a BlockStmt node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitBlockStmt(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitBlockStmt(n, c, visitor); + } + /** + * Leave a BlockStmt node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveBlockStmt(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveBlockStmt(n, c, visitor); + } + /** + * Visit a Loop node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitLoop(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitLoop(n, c, visitor); + } + /** + * Visit a Loop node after processing the loop header. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveLoopHeader(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveLoopHeader(n, c, visitor); + } + /** + * Leave a Loop node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveLoop(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveLoop(n, c, visitor); + } + /** + * Visit a GetCaughtException node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitGetCaughtException(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitGetCaughtException(n, c, visitor); + } + /** + * Leave a GetCaughtException node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveGetCaughtException(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveGetCaughtException(n, c, visitor); + } + /** + * Visit a This node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitThis(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitThis(n, c, visitor); + } + /** + * Leave a This node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveThis(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveThis(n, c, visitor); + } + /** + * Visit a Super node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitSuper(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitSuper(n, c, visitor); + } + /** + * Leave a Super node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveSuper(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveSuper(n, c, visitor); + } + /** + * Visit a Call node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitCall(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitCall(n, c, visitor); + } + /** + * Leave a Call node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveCall(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveCall(n, c, visitor); + } + /** + * Visit a Var node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitVar(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitVar(n, c, visitor); + } + /** + * Leave a Var node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveVar(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveVar(n, c, visitor); + } + /** + * Visit a Constant node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitConstant(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitConstant(n, c, visitor); + } + /** + * Leave a Constant node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveConstant(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveConstant(n, c, visitor); + } + /** + * Visit a BinaryExpr node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitBinaryExpr(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitBinaryExpr(n, c, visitor); + } + /** + * Leave a BinaryExpr node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveBinaryExpr(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveBinaryExpr(n, c, visitor); + } + /** + * Visit a UnaryExpr node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitUnaryExpr(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitUnaryExpr(n, c, visitor); + } + /** + * Leave a UnaryExpr node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveUnaryExpr(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveUnaryExpr(n, c, visitor); + } + /** + * Visit an ArrayLength node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitArrayLength(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitArrayLength(n, c, visitor); + } + /** + * Leave an ArrayLength node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveArrayLength(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveArrayLength(n, c, visitor); + } + /** + * Visit an ArrayRef node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitArrayRef(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitArrayRef(n, c, visitor); + } + /** + * Leave an ArrayRef node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveArrayRef(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveArrayRef(n, c, visitor); + } + /** + * Visit a DeclStmt node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitDeclStmt(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitDeclStmt(n, c, visitor); + } + /** + * Leave a DeclStmt node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveDeclStmt(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveDeclStmt(n, c, visitor); + } + /** + * Visit a Return node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitReturn(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitReturn(n, c, visitor); + } + /** + * Leave a Return node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveReturn(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveReturn(n, c, visitor); + } + /** + * Visit an Ifgoto node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitIfgoto(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitIfgoto(n, c, visitor); + } + /** + * Leave an Ifgoto node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfgoto(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveIfgoto(n, c, visitor); + } + /** + * Visit a Goto node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitGoto(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitGoto(n, c, visitor); + } + /** + * Leave a Goto node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveGoto(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveGoto(n, c, visitor); + } + /** + * Visit a LabelStmt node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitLabelStmt(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitLabelStmt(n, c, visitor); + } + /** + * Leave a LabelStmt node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveLabelStmt(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveLabelStmt(n, c, visitor); + } + /** + * Visit an IfStmt node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitIfStmt(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitIfStmt(n, c, visitor); + } + /** + * Visit an IfStmt node after processing the condition. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfStmtCondition(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveIfStmtCondition(n, c, visitor); + } + /** + * Visit an IfStmt node after processing the true clause. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfStmtTrueClause(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveIfStmtTrueClause(n, c, visitor); + } + /** + * Leave an IfStmt node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfStmt(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveIfStmt(n, c, visitor); + } + /** + * Visit an IfExpr node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitIfExpr(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitIfExpr(n, c, visitor); + } + /** + * Visit an IfExpr node after processing the condition. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfExprCondition(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveIfExprCondition(n, c, visitor); + } + /** + * Visit an IfExpr node after processing the true clause. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfExprTrueClause(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveIfExprTrueClause(n, c, visitor); + } + /** + * Leave an IfExpr node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveIfExpr(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveIfExpr(n, c, visitor); + } + /** + * Visit a New node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitNew(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitNew(n, c, visitor); + } + /** + * Leave a New node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveNew(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveNew(n, c, visitor); + } + /** + * Visit an ObjectLiteral node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitObjectLiteral(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitObjectLiteral(n, c, visitor); + } + /** + * Visit an ObjectLiteral node after processing the {i}th field initializer. + * @param n the node to process + * @param i the field position that was initialized + * @param c a visitor-specific context + */ + protected void leaveObjectLiteralFieldInit(CAstNode n, int i, Context c, CAstVisitor visitor) { + delegate.leaveObjectLiteralFieldInit(n, i, c, visitor); + } + /** + * Leave an ObjectLiteral node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveObjectLiteral(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveObjectLiteral(n, c, visitor); + } + /** + * Visit an ArrayLiteral node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitArrayLiteral(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitArrayLiteral(n, c, visitor); + } + /** + * Visit an ArrayLiteral node after processing the array object. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveArrayLiteralObject(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveArrayLiteralObject(n, c, visitor); + } + /** + * Visit an ArrayLiteral node after processing the {i}th element initializer. + * @param n the node to process + * @param i the index that was initialized + * @param c a visitor-specific context + */ + protected void leaveArrayLiteralInitElement(CAstNode n, int i, Context c, CAstVisitor visitor) { + delegate.leaveArrayLiteralInitElement(n, i, c, visitor); + } + /** + * Leave a ArrayLiteral node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveArrayLiteral(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveArrayLiteral(n, c, visitor); + } + /** + * Visit an ObjectRef node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitObjectRef(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitObjectRef(n, c, visitor); + } + /** + * Leave an ObjectRef node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveObjectRef(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveObjectRef(n, c, visitor); + } + /** + * Visit an Assign node. Override only this to change behavior for all assignment nodes. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + public boolean visitAssign(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitAssign(n, c, visitor); + } + /** + * Leave an Assign node. Override only this to change behavior for all assignment nodes. + * @param n the node to process + * @param c a visitor-specific context + */ + public void leaveAssign(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveAssign(n, c, visitor); + } + /** + * Visit an ArrayRef Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitArrayRefAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { + return delegate.visitArrayRefAssign(n, v, a, c, visitor); + } + /** + * Visit an ArrayRef Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + */ + protected void leaveArrayRefAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { + delegate.leaveArrayRefAssign(n, v, a, c, visitor); + } + /** + * Visit an ArrayRef Op/Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitArrayRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { + return delegate.visitArrayRefAssignOp(n, v, a, pre, c, visitor); + } + /** + * Visit an ArrayRef Op/Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + */ + protected void leaveArrayRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { + delegate.leaveArrayRefAssignOp(n, v, a, pre, c, visitor); + } + /** + * Visit an ObjectRef Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitObjectRefAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { + return delegate.visitObjectRefAssign(n, v, a, c, visitor); + } + /** + * Visit an ObjectRef Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + */ + protected void leaveObjectRefAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { + delegate.leaveObjectRefAssign(n, v, a, c, visitor); + } + /** + * Visit an ObjectRef Op/Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { + return delegate.visitObjectRefAssignOp(n, v, a, pre, c, visitor); + } + /** + * Visit an ObjectRef Op/Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + */ + protected void leaveObjectRefAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { + delegate.leaveObjectRefAssignOp(n, v, a, pre, c, visitor); + } + /** + * Visit a BlockExpr Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitBlockExprAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { + return delegate.visitBlockExprAssign(n, v, a, c, visitor); + } + /** + * Visit a BlockExpr Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + */ + protected void leaveBlockExprAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { + delegate.leaveBlockExprAssign(n, v, a, c, visitor); + } + /** + * Visit a BlockExpr Op/Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitBlockExprAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { + return delegate.visitBlockExprAssignOp(n, v, a, pre, c, visitor); + } + /** + * Visit a BlockExpr Op/Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + */ + protected void leaveBlockExprAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { + delegate.leaveBlockExprAssignOp(n, v, a, pre, c, visitor); + } + /** + * Visit a Var Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitVarAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { + return delegate.visitVarAssign(n, v, a, c, visitor); + } + /** + * Visit a Var Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param c a visitor-specific context + */ + protected void leaveVarAssign(CAstNode n, CAstNode v, CAstNode a, Context c, CAstVisitor visitor) { + delegate.leaveVarAssign(n, v, a, c, visitor); + } + /** + * Visit a Var Op/Assignment node after visiting the RHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitVarAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { + return delegate.visitVarAssignOp(n, v, a, pre, c, visitor); + } + /** + * Visit a Var Op/Assignment node after visiting the LHS. + * @param n the LHS node to process + * @param v the RHS node to process + * @param a the assignment node to process + * @param pre whether the value before the operation should be used + * @param c a visitor-specific context + */ + protected void leaveVarAssignOp(CAstNode n, CAstNode v, CAstNode a, boolean pre, Context c, CAstVisitor visitor) { + delegate.leaveVarAssignOp(n, v, a, pre, c, visitor); + } + /** + * Visit a Switch node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitSwitch(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitSwitch(n, c, visitor); + } + /** + * Visit a Switch node after processing the switch value. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveSwitchValue(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveSwitchValue(n, c, visitor); + } + /** + * Leave a Switch node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveSwitch(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveSwitch(n, c, visitor); + } + /** + * Visit a Throw node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitThrow(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitThrow(n, c, visitor); + } + /** + * Leave a Throw node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveThrow(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveThrow(n, c, visitor); + } + /** + * Visit a Catch node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitCatch(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitCatch(n, c, visitor); + } + /** + * Leave a Catch node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveCatch(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveCatch(n, c, visitor); + } + /** + * Visit an Unwind node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitUnwind(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitUnwind(n, c, visitor); + } + /** + * Leave an Unwind node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveUnwind(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveUnwind(n, c, visitor); + } + /** + * Visit a Try node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitTry(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitTry(n, c, visitor); + } + /** + * Visit a Try node after processing the try block. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveTryBlock(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveTryBlock(n, c, visitor); + } + /** + * Leave a Try node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveTry(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveTry(n, c, visitor); + } + /** + * Visit an Empty node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitEmpty(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitEmpty(n, c, visitor); + } + /** + * Leave an Empty node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveEmpty(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveEmpty(n, c, visitor); + } + /** + * Visit a Primitive node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitPrimitive(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitPrimitive(n, c, visitor); + } + /** + * Leave a Primitive node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leavePrimitive(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leavePrimitive(n, c, visitor); + } + /** + * Visit a Void node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitVoid(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitVoid(n, c, visitor); + } + /** + * Leave a Void node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveVoid(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveVoid(n, c, visitor); + } + /** + * Visit a Cast node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitCast(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitCast(n, c, visitor); + } + /** + * Leave a Cast node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveCast(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveCast(n, c, visitor); + } + /** + * Visit an InstanceOf node. + * @param n the node to process + * @param c a visitor-specific context + * @return true if no further processing is needed + */ + protected boolean visitInstanceOf(CAstNode n, Context c, CAstVisitor visitor) { + return delegate.visitInstanceOf(n, c, visitor); + } + /** + * Leave an InstanceOf node. + * @param n the node to process + * @param c a visitor-specific context + */ + protected void leaveInstanceOf(CAstNode n, Context c, CAstVisitor visitor) { + delegate.leaveInstanceOf(n, c, visitor); + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/types/AstMethodReference.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/types/AstMethodReference.java new file mode 100644 index 000000000..0d5bb0052 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/types/AstMethodReference.java @@ -0,0 +1,28 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.types; + +import com.ibm.wala.types.*; +import com.ibm.wala.util.Atom; + +public class AstMethodReference { + + public final static String fnAtomStr = "do"; + public final static Atom fnAtom = Atom.findOrCreateUnicodeAtom(fnAtomStr); + public final static String fnDescStr = "()" + AstTypeReference.rootTypeName; + public final static Descriptor fnDesc = Descriptor.findOrCreateUTF8(fnDescStr); + public final static Selector fnSelector = new Selector(fnAtom, fnDesc); + + public static MethodReference fnReference(TypeReference cls) { + return MethodReference.findOrCreate(cls, fnAtom, fnDesc); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/types/AstTypeReference.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/types/AstTypeReference.java new file mode 100644 index 000000000..98e5d6efa --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/types/AstTypeReference.java @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.types; + +import com.ibm.wala.types.*; + +public class AstTypeReference { + + public static final String rootTypeSourceStr = "Root"; + public static final String rootTypeDescStr = "L" + rootTypeSourceStr; + public static final TypeName rootTypeName = + TypeName.string2TypeName(rootTypeDescStr); + + public static final String functionTypeSourceStr = "CodeBody"; + public static final String functionTypeDescStr = "L" + functionTypeSourceStr; + public static final TypeName functionTypeName = + TypeName.string2TypeName(functionTypeDescStr); + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstFunctions.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstFunctions.java new file mode 100644 index 000000000..1b47ced17 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstFunctions.java @@ -0,0 +1,77 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.util; + +import com.ibm.wala.cast.tree.*; +import com.ibm.wala.util.collections.*; +import com.ibm.wala.util.graph.traverse.*; + +import java.util.*; + +public class CAstFunctions { + + public static CAstNode findIf(CAstNode tree, Filter f) { + if (f.accepts(tree)) { + return tree; + } else { + for(int i = 0; i < tree.getChildCount(); i++) { + CAstNode result = findIf(tree.getChild(i), f); + if (result != null) { + return result; + } + } + } + + return null; + } + + public static Iterator iterateNodes(final CAstNode tree) { + return new DFSDiscoverTimeIterator() { + + private final Map pendingChildren = new HashMap(); + + protected Iterator getPendingChildren(Object n) { + return (Iterator) pendingChildren.get(n); + } + + protected void setPendingChildren(Object v, Iterator iterator) { + pendingChildren.put(v, iterator); + } + + protected Iterator getConnected(final Object n) { + return new Iterator() { + private int i = 0; + + public boolean hasNext() { + return i < ((CAstNode)n).getChildCount(); + } + + public Object next() { + return ((CAstNode)n).getChild(i++); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + { + init(tree); + } + }; + } + + public static Iterator findAll(CAstNode tree, Filter f) { + return new FilterIterator(iterateNodes(tree), f); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstPattern.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstPattern.java new file mode 100644 index 000000000..bb59a2618 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstPattern.java @@ -0,0 +1,503 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.util; + +import com.ibm.wala.cast.tree.*; +import com.ibm.wala.cast.tree.impl.*; +import com.ibm.wala.util.debug.*; + +import java.lang.reflect.*; +import java.util.*; + +public class CAstPattern { + private static boolean DEBUG_PARSER = false; + private static boolean DEBUG_MATCH = false; + + private final static int CHILD_KIND = -1; + private final static int CHILDREN_KIND = -2; + private final static int REPEATED_PATTERN_KIND = -3; + private final static int ALTERNATIVE_PATTERN_KIND = -4; + private final static int OPTIONAL_PATTERN_KIND = -5; + private final static int REFERENCE_PATTERN_KIND = -6; + + private final static int IGNORE_KIND = -99; + + private final String name; + + private final int kind; + private final String value; + private final CAstPattern[] children; + private final Map references; + + public static class Segments extends TreeMap { + + public CAstNode getSingle(String name) { + Assertions._assert(containsKey(name), name); + return (CAstNode) get(name); + } + + public List getMultiple(String name) { + if (! containsKey(name)) { + return Collections.EMPTY_LIST; + } else { + Object o = get(name); + if (o instanceof CAstNode) { + return Collections.singletonList(o); + } else { + Assertions._assert(o instanceof List); + return (List)o; + } + } + } + + private void addAll(Segments other) { + for(Iterator xs = other.entrySet().iterator(); xs.hasNext(); ) { + Map.Entry e = (Map.Entry) xs.next(); + String name = (String)e.getKey(); + if (e.getValue() instanceof CAstNode) { + add(name, (CAstNode) e.getValue()); + } else { + for(Iterator vs = ((List)e.getValue()).iterator(); + vs.hasNext(); ) + { + add(name, (CAstNode) vs.next()); + } + } + } + } + + private void add(String name, CAstNode result) { + if (containsKey(name)) { + Object o = get(name); + if (o instanceof List) { + ((List)o).add(result); + } else { + Assertions._assert(o instanceof CAstNode); + List x = new ArrayList(); + x.add(o); + x.add(result); + put(name, x); + } + } else { + put(name, result); + } + } + } + + public CAstPattern(String name, int kind, CAstPattern[] children) { + this.name = name; + this.kind = kind; + this.value = null; + this.children = children; + this.references = null; + } + + public CAstPattern(String name, String value) { + this.name = name; + this.kind = IGNORE_KIND; + this.value = value; + this.children = null; + this.references = null; + } + + public CAstPattern(String patternName, Map references) { + this.name = null; + this.kind = REFERENCE_PATTERN_KIND; + this.value = patternName; + this.references = references; + this.children = null; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + + if (name != null) { + sb.append("<").append(name).append(">"); + } + + if (value != null) { + if (kind == REFERENCE_PATTERN_KIND) { + sb.append("ref:").append(value); + } else { + sb.append("literal:").append(value); + } + } else if (kind == CHILD_KIND) { + sb.append("*"); + } else if (kind == CHILDREN_KIND) { + sb.append("**"); + } else if (kind == REPEATED_PATTERN_KIND) { + sb.append("@"); + } else if (kind == ALTERNATIVE_PATTERN_KIND) { + sb.append("|"); + } else if (kind == OPTIONAL_PATTERN_KIND) { + sb.append("?"); + } else { + sb.append(CAstPrinter.kindAsString(kind)); + } + + if (children != null) { + sb.append("("); + for(int i = 0; i < children.length; i++) { + sb.append( children[i].toString() ); + if (i == children.length-1) { + sb.append(")"); + } else { + sb.append(","); + } + } + } + + return sb.toString(); + } + + private static boolean + matchChildren(CAstNode tree, int i, CAstPattern[] cs, int j, Segments s) + { + if (i >= tree.getChildCount() && j >= cs.length) { + return true; + } else if (i < tree.getChildCount() && j >= cs.length) { + return false; + } else if (i >= tree.getChildCount() && j < cs.length) { + switch (cs[j].kind) { + case CHILDREN_KIND: + case OPTIONAL_PATTERN_KIND: + case REPEATED_PATTERN_KIND: + return matchChildren(tree, i, cs, j+1, s); + + default: + return false; + } + } else { + if (cs[j].kind == CHILD_KIND) { + + if (DEBUG_MATCH) { + Trace.println("* matches "+CAstPrinter.print(tree.getChild(i))); + } + + if (s != null && cs[j].name != null) { + s.add(cs[j].name, tree.getChild(i)); + } + return matchChildren(tree, i+1, cs, j+1, s); + + } else if (cs[j].kind == CHILDREN_KIND) { + if (tryMatchChildren(tree, i, cs, j+1, s)) { + + if (DEBUG_MATCH) { + Trace.println("** matches nothing"); + } + + return true; + + } else { + + if (DEBUG_MATCH) { + Trace.println( + "** matches " + CAstPrinter.print(tree.getChild(i))); + } + + if (s != null && cs[j].name != null) { + s.add(cs[j].name, tree.getChild(i) ); + } + + return matchChildren(tree, i+1, cs, j, s); + } + + } else if (cs[j].kind == REPEATED_PATTERN_KIND) { + CAstPattern repeatedPattern = cs[j].children[0]; + if (repeatedPattern.tryMatch(tree.getChild(i), s)) { + if (s != null && cs[j].name != null) { + s.add(cs[j].name, tree.getChild(i) ); + } + + if (DEBUG_MATCH) { + Trace.println( + cs[j] + " matches " + CAstPrinter.print(tree.getChild(i))); + } + + return matchChildren(tree, i+1, cs, j, s); + + } else { + + if (DEBUG_MATCH) { + Trace.println(cs[j] + " matches nothing"); + } + + return matchChildren(tree, i, cs, j+1, s); + } + + } else if (cs[j].kind == OPTIONAL_PATTERN_KIND) { + if (tryMatchChildren(tree, i, cs, j+1, s)) { + + if (DEBUG_MATCH) { + Trace.println(cs[j] + " matches nothing"); + } + + return true; + } else { + CAstPattern optionalPattern = cs[j].children[0]; + if (optionalPattern.tryMatch(tree.getChild(i), s)) { + + if (DEBUG_MATCH) { + Trace.println( + cs[j] + " matches " + CAstPrinter.print(tree.getChild(i))); + } + + return matchChildren(tree, i+1, cs, j+1, s); + } else { + return false; + } + } + + } else { + return + cs[j].match(tree.getChild(i), s) + && + matchChildren(tree, i+1, cs, j+1, s); + } + } + } + + public boolean match(CAstNode tree, Segments s) { + if (DEBUG_MATCH) { + Trace.println("matching "+this+" against "+CAstPrinter.print(tree)); + } + + if (kind == REFERENCE_PATTERN_KIND) { + return ((CAstPattern)references.get(value)).match(tree, s); + + } else if (kind == ALTERNATIVE_PATTERN_KIND) { + for(int i = 0; i < children.length; i++) { + if (children[i].tryMatch(tree, s)) { + + if (s != null && name != null) s.add(name, tree); + + return true; + } + } + + if (DEBUG_MATCH) { + Trace.println("match failed (a)"); + } + return false; + + } else { + if ( (value == null)? + tree.getKind() != kind: + ( tree.getKind()!=CAstNode.CONSTANT + || + !value.equals(tree.getValue().toString()) ) ) + { + if (DEBUG_MATCH) { + Trace.println("match failed (b)"); + } + + return false; + } + + if (s != null && name != null) s.add(name, tree); + + if (children == null || children.length == 0) { + if (DEBUG_MATCH && tree.getChildCount() != 0) { + Trace.println("match failed (c)"); + } + return tree.getChildCount() == 0; + } else { + return matchChildren(tree, 0, children, 0, s); + } + } + } + + private static boolean + tryMatchChildren(CAstNode tree, int i, CAstPattern[] cs, int j, Segments s) + { + if (s == null) { + return matchChildren(tree, i, cs, j, s); + } else { + Segments ss = new Segments(); + boolean result = matchChildren(tree, i, cs, j, ss); + if (result) s.addAll(ss); + return result; + } + } + + private boolean tryMatch(CAstNode tree, Segments s) { + if (s == null) { + return match(tree, s); + } else { + Segments ss = new Segments(); + boolean result = match(tree, ss); + if (result) s.addAll(ss); + return result; + } + } + + public static Segments match(CAstPattern p, CAstNode n) { + Segments s = new Segments(); + if (p.match(n, s)) { + return s; + } else { + return null; + } + } + + public static CAstPattern parse(String patternString) { + try { + return (new Parser(patternString)).parse(); + } catch (NoSuchFieldException e) { + Assertions.UNREACHABLE("no such kind in pattern: " + e.getMessage()); + return null; + } catch (IllegalAccessException e) { + Assertions.UNREACHABLE("internal error in CAstPattern" + e); + return null; + } + } + + private static class Parser { + private final Map namedPatterns = new HashMap(); + private final String patternString; + private int start; + private int end; + + private Parser(String patternString) { + this.patternString = patternString; + } + + private Parser(String patternString, int start) { + this(patternString); + this.start = start; + } + + private String parseName(boolean internal) { + if (patternString.charAt(start) == (internal?'{':'<')) { + int nameStart = start+1; + int nameEnd = patternString.indexOf(internal?'}':'>', nameStart); + start = nameEnd + 1; + return patternString.substring(nameStart, nameEnd); + } else { + return null; + } + } + + public CAstPattern parse() + throws NoSuchFieldException, IllegalAccessException + { + if (DEBUG_PARSER) { + Trace.println("parsing " + patternString.substring(start)); + } + + String internalName = parseName(true); + String name = parseName(false); + + CAstPattern result; + if (patternString.charAt(start) == '`') { + int strEnd = patternString.indexOf('`', start+1); + end = strEnd+1; + String patternName = patternString.substring(start+1, strEnd); + Assertions._assert(internalName == null); + result = new CAstPattern(patternName, namedPatterns); + + } else if (patternString.charAt(start) == '"') { + int strEnd = patternString.indexOf('"', start+1); + end = strEnd+1; + result = + new CAstPattern( + name, + patternString.substring(start+1, strEnd)); + + } else if (patternString.startsWith("**", start)) { + end = start+2; + result = new CAstPattern(name, CHILDREN_KIND, null); + + } else if (patternString.startsWith("*", start)) { + end = start+1; + result = new CAstPattern(name, CHILD_KIND, null); + + } else if (patternString.startsWith("|(", start)) { + List alternatives = new ArrayList(); + start += 2; + do { + alternatives.add( parse() ); + start = end+2; + } while (patternString.startsWith("||", end)); + Assertions._assert(patternString.startsWith(")|", end), patternString); + end += 2; + result = new CAstPattern(name, + ALTERNATIVE_PATTERN_KIND, + (CAstPattern[]) + alternatives.toArray(new CAstPattern[alternatives.size()])); + + } else if (patternString.startsWith("@(", start)) { + start += 2; + CAstPattern children[] = new CAstPattern[]{ parse() }; + Assertions._assert( patternString.startsWith(")@", end) ); + end += 2; + + if (DEBUG_PARSER) { + Trace.println("repeated pattern: " + children[0]); + } + + result = new CAstPattern(name, REPEATED_PATTERN_KIND, children); + + } else if (patternString.startsWith("?(", start)) { + start += 2; + CAstPattern children[] = new CAstPattern[]{ parse() }; + Assertions._assert( patternString.startsWith(")?", end) ); + end += 2; + + if (DEBUG_PARSER) { + Trace.println("optional pattern: " + children[0]); + } + + result = new CAstPattern(name, OPTIONAL_PATTERN_KIND, children); + + } else { + int kindEnd = patternString.indexOf('(', start); + String kindStr = patternString.substring(start, kindEnd); + Field kindField = CAstNode.class.getField(kindStr); + int kind = kindField.getInt(null); + + if (patternString.charAt(kindEnd+1) == ')') { + end = kindEnd+2; + result = new CAstPattern(name, kind, null); + + } else { + List children = new ArrayList(); + start = patternString.indexOf('(', start) + 1; + do { + children.add( parse() ); + start = end+1; + + if (DEBUG_PARSER) { + Trace.println( + "parsing children: " + patternString.substring(end)); + } + + } while (patternString.charAt(end) == ','); + + Assertions._assert(patternString.charAt(end) == ')'); + end++; + + result = new CAstPattern( + name, + kind, + (CAstPattern[]) + children.toArray(new CAstPattern[children.size()])); + } + } + + if (internalName != null) { + namedPatterns.put(internalName, result); + } + + return result; + } + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstPrinter.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstPrinter.java new file mode 100644 index 000000000..ea7a66700 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstPrinter.java @@ -0,0 +1,282 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.util; + +import com.ibm.wala.cast.tree.*; + +import java.io.*; +import java.util.*; + +public class CAstPrinter { + private static CAstPrinter instance= new CAstPrinter(); + + public static void setPrinter(CAstPrinter printer) { + instance= printer; + } + + public static String kindAsString(int kind) { + return instance.getKindAsString(kind); + } + + public String getKindAsString(int kind) { + switch (kind) { + // statements + case CAstNode.SWITCH: return "SWITCH"; + case CAstNode.LOOP: return "LOOP"; + case CAstNode.BLOCK_STMT: return "BLOCK"; + case CAstNode.TRY: return "TRY"; + case CAstNode.EXPR_STMT: return "EXPR_STMT"; + case CAstNode.DECL_STMT: return "DECL_STMT"; + case CAstNode.RETURN: return "RETURN"; + case CAstNode.GOTO: return "GOTO"; + case CAstNode.BREAK: return "BREAK"; + case CAstNode.CONTINUE: return "CONTINUE"; + case CAstNode.IF_STMT: return "IF_STMT"; + case CAstNode.THROW: return "THROW"; + case CAstNode.FUNCTION_STMT: return "FUNCTION_STMT"; + case CAstNode.ASSIGN: return "ASSIGN"; + case CAstNode.ASSIGN_PRE_OP: return "ASSIGN_PRE_OP"; + case CAstNode.ASSIGN_POST_OP: return "ASSIGN_POST_OP"; + case CAstNode.LABEL_STMT: return "LABEL_STMT"; + case CAstNode.IFGOTO: return "IFGOTO"; + case CAstNode.EMPTY: return "EMPTY"; + case CAstNode.RETURN_WITHOUT_BRANCH: return "RET_WO_BRANCH"; + case CAstNode.CATCH: return "CATCH"; + case CAstNode.UNWIND: return "UNWIND"; + case CAstNode.MONITOR_ENTER: return "MONITOR_ENTER"; + case CAstNode.MONITOR_EXIT: return "MONITOR_EXIT"; + case CAstNode.ECHO: return "ECHO"; + + // expression kinds + case CAstNode.FUNCTION_EXPR: return "FUNCTION_EXPR"; + case CAstNode.EXPR_LIST: return "EXPR_LIST"; + case CAstNode.CALL: return "CALL"; + case CAstNode.GET_CAUGHT_EXCEPTION: return "EXCEPTION"; + case CAstNode.BLOCK_EXPR: return "BLOCK_EXPR"; + case CAstNode.BINARY_EXPR: return "BINARY_EXPR"; + case CAstNode.UNARY_EXPR: return "UNARY_EXPR"; + case CAstNode.IF_EXPR: return "IF_EXPR"; + case CAstNode.ANDOR_EXPR: return "ANDOR_EXPR"; + case CAstNode.NEW: return "NEW"; + case CAstNode.OBJECT_LITERAL: return "LITERAL"; + case CAstNode.VAR: return "VAR"; + case CAstNode.OBJECT_REF: return "OBJECT_REF"; + case CAstNode.CHOICE_EXPR: return "CHOICE_EXPR"; + case CAstNode.CHOICE_CASE: return "CHOICE_CASE"; + case CAstNode.SUPER: return "SUPER"; + case CAstNode.THIS: return "THIS"; + case CAstNode.ARRAY_LITERAL: return "ARRAY_LITERAL"; + case CAstNode.CAST: return "CAST"; + case CAstNode.INSTANCEOF: return "INSTANCEOF"; + case CAstNode.ARRAY_REF: return "ARRAY_REF"; + case CAstNode.ARRAY_LENGTH: return "ARRAY_LENGTH"; + case CAstNode.TYPE_OF: return "TYPE_OF"; + case CAstNode.EACH_ELEMENT_HAS_NEXT: return "EACH_ELEMENT_HAS_NEXT"; + case CAstNode.EACH_ELEMENT_GET: return "EACH_ELEMENT_GET"; + case CAstNode.LIST_EXPR: return "LIST_EXPR"; + case CAstNode.EMPTY_LIST_EXPR: return "EMPTY_LIST_EXPR"; + + // explicit lexical scopes + case CAstNode.LOCAL_SCOPE: return "SCOPE"; + + // literal expression kinds + case CAstNode.CONSTANT: return "CONSTANT"; + case CAstNode.OPERATOR: return "OPERATOR"; + + // special stuff + case CAstNode.PRIMITIVE: return "PRIMITIVE"; + case CAstNode.VOID: return "VOID"; + case CAstNode.ERROR: return "ERROR"; + case CAstNode.ASSERT: return "ASSERT"; + + default: return "UNKNOWN(" + kind + ")"; + } + } + + public static String print(CAstNode top) { + return instance.doPrint(top); + } + + public String doPrint(CAstNode top) { + return print(top, null); + } + + public static String print(CAstNode top, CAstSourcePositionMap pos) { + return instance.doPrint(top, pos); + } + + public String doPrint(CAstNode top, CAstSourcePositionMap pos) { + StringWriter writer = new StringWriter(); + printTo(top, pos, writer); + return writer.toString(); + } + + public String doPrint(CAstEntity ce) { + StringWriter writer = new StringWriter(); + printTo(ce, writer); + return writer.toString(); + } + + public static String print(CAstEntity ce) { + return instance.doPrint(ce); + } + + public static void printTo(CAstNode top, Writer w) { + instance.doPrintTo(top, w); + } + + public void doPrintTo(CAstNode top, Writer w) { + printTo(top, null, w, 0, false); + } + + public static void printTo(CAstNode top, CAstSourcePositionMap pos, Writer w) { + instance.doPrintTo(top, pos, w); + } + + public void doPrintTo(CAstNode top, CAstSourcePositionMap pos, Writer w) { + printTo(top, pos, w, 0, false); + } + + public static void xmlTo(CAstNode top, Writer w) { + instance.doXmlTo(top, w); + } + + public void doXmlTo(CAstNode top, Writer w) { + printTo(top, null, w, 0, true); + } + + public static void xmlTo(CAstNode top, CAstSourcePositionMap pos, Writer w) { + instance.doXmlTo(top, pos, w); + } + + private void doXmlTo(CAstNode top, CAstSourcePositionMap pos, Writer w) { + printTo(top, pos, w, 0, true); + } + + private static String escapeForXML(String x, char from, String to) { + return (x.indexOf(from) != -1) ? x.replaceAll(Character.toString(from), to) : x; + } + + public static String escapeForXML(String x) { + return + escapeForXML( + escapeForXML( + escapeForXML( + escapeForXML(x, '&', "&"), + '"', """), + '<', "<"), + '>', ">"); + } + + public static void printTo(CAstNode top, CAstSourcePositionMap pos, Writer w, int depth, boolean uglyBrackets) { + instance.doPrintTo(top, pos, w, depth, uglyBrackets); + } + + public void doPrintTo(CAstNode top, CAstSourcePositionMap pos, Writer w, int depth, boolean uglyBrackets) { + try { + CAstSourcePositionMap.Position p = (pos!=null)? pos.getPosition( top ): null; + for(int i = 0; i < depth; i++) w.write(" "); + if (top == null) { + w.write("(null)\n"); + } else if (top.getValue() != null) { + if (uglyBrackets) { + w.write(""); + w.write("\n"); + } else { + if (uglyBrackets) w.write("<"); + w.write( kindAsString( top.getKind() ) ); + if (p != null) + if (uglyBrackets) + w.write( " position=\"" + p + "\""); + else + w.write( " at " + p ); + if (uglyBrackets) w.write(">"); + w.write("\n"); + for(int i = 0; i < top.getChildCount(); i++) { + doPrintTo( top.getChild(i), pos, w, depth+1, uglyBrackets ); + } + if (uglyBrackets) { + for(int i = 0; i < depth; i++) w.write(" "); + w.write("\n"); + } + } + } catch (java.io.IOException e) { + + } + } + + public static String entityKindAsString(int kind) { + return instance.getEntityKindAsString(kind); + } + + public String getEntityKindAsString(int kind) { + switch (kind) { + case CAstEntity.FUNCTION_ENTITY: return "function"; + case CAstEntity.FIELD_ENTITY: return "field"; + case CAstEntity.FILE_ENTITY: return "unit"; + case CAstEntity.TYPE_ENTITY: return "type"; + case CAstEntity.SCRIPT_ENTITY: return "script"; + case CAstEntity.RULE_ENTITY: return "rule"; + default: return ""; + } + } + + public static void printTo(CAstEntity e, Writer w) { + instance.doPrintTo(e, w); + } + + protected void doPrintTo(CAstEntity e, Writer w) { + try { + w.write(getEntityKindAsString(e.getKind())); + w.write(": "); + w.write(e.getName()); + w.write('\n'); + if (e.getArgumentNames().length > 0) { + w.write("("); + String[] names = e.getArgumentNames(); + for(int i = 0; i < names.length; i++) { + w.write(" " + names[i]); + } + w.write(" )\n"); + } + if (e.getAST() != null) { + doPrintTo(e.getAST(), e.getSourceMap(), w); + w.write('\n'); + } + for(Iterator i= e.getAllScopedEntities().values().iterator(); + i.hasNext(); ) + { + for(Iterator j = ((Collection) i.next()).iterator(); j.hasNext(); ) { + doPrintTo((CAstEntity) j.next(), w); + } + } + w.flush(); + } catch (IOException e1) { + System.err.println("unexpected I/O exception " + e1); + } + } +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstToDOM.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstToDOM.java new file mode 100644 index 000000000..8ea206e7a --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/CAstToDOM.java @@ -0,0 +1,70 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.util; + +import com.ibm.wala.cast.tree.*; +import com.ibm.wala.cast.tree.impl.*; + +import javax.xml.parsers.*; + +import org.w3c.dom.*; + +public class CAstToDOM extends CAstPrinter { + + private static final String VALUE_TAG = "value"; + private static final String TYPE_TAG = "type"; + + public static Document toDOM(CAstNode astRoot) { + try { + DocumentBuilderFactory documentBuilderFactory = + DocumentBuilderFactory.newInstance(); + DocumentBuilder documentBuilder = + documentBuilderFactory.newDocumentBuilder(); + DOMImplementation domImplementation = + documentBuilder.getDOMImplementation(); + Document document = + domImplementation.createDocument("CAst", "CAst", null); + Element rootNode = + document.getDocumentElement(); + + nodeToDOM(document, rootNode, astRoot); + + return document; + } catch (ParserConfigurationException e) { + e.printStackTrace(); + throw new RuntimeException("DOM builder error."); + } + } + + private static void nodeToDOM(Document doc, Element root, CAstNode astNode) { + Element nodeElt = doc.createElement(kindAsString(astNode.getKind())); + + if (astNode.getValue() == null) { + for(int i = 0; i < astNode.getChildCount(); i++) { + nodeToDOM(doc, nodeElt, astNode.getChild(i)); + } + + } else { + Element typeTag = doc.createElement(TYPE_TAG); + Text type = doc.createTextNode(astNode.getValue().getClass().toString()); + typeTag.appendChild( type ); + nodeElt.appendChild(typeTag); + + Element valueTag = doc.createElement(VALUE_TAG); + Text value = doc.createTextNode( astNode.getValue().toString() ); + valueTag.appendChild( value ); + nodeElt.appendChild(valueTag); + } + + root.appendChild(nodeElt); + } + +} diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/SourceBuffer.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/SourceBuffer.java new file mode 100644 index 000000000..c57f81f95 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/SourceBuffer.java @@ -0,0 +1,129 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.util; + +import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position; +import com.ibm.wala.cast.tree.impl.*; + +import java.io.*; +import java.net.*; + +public class SourceBuffer { + private String[] lines; + private final Position p; + + public SourceBuffer(Position p) throws IOException { + this.p = p; + this.lines = new String[ p.getLastLine() - p.getFirstLine() + 1]; + BufferedReader r = + new BufferedReader(new InputStreamReader(p.getInputStream())); + int line = 1; + while (line <= p.getLastLine()) { + String theLine = r.readLine(); + if (line >= p.getFirstLine()) { + lines[line-p.getFirstLine()] = + line == p.getLastLine()? + theLine.substring(0, p.getLastCol()+1): + theLine; + } + line++; + } + } + + public String toString() { + StringBuffer result = new StringBuffer(); + for(int i = 0; i < lines.length; i++) { + if (i == 0) { + result.append(lines[i].substring(p.getFirstCol())).append("\n"); + } else if (i == lines.length - 1) { + result.append(lines[i]); + } else { + result.append(lines[i]).append("\n"); + } + } + + return result.toString(); + } + + public void substitute(Position range, String newText) { + int startLine = range.getFirstLine() - p.getFirstLine(); + int endLine = range.getLastLine() - p.getFirstLine(); + + if (startLine != endLine) { + String newLines[] = new String[ lines.length - (endLine-startLine) ]; + int i = 0; + while (i < startLine) { + newLines[i] = lines[i]; + i++; + } + newLines[i++] = + lines[startLine].substring(0, range.getFirstCol()) + + lines[endLine].substring(range.getLastCol()); + while(i < newLines.length) { + newLines[i] = lines[i+ (endLine-startLine)]; + i++; + } + + lines = newLines; + endLine = startLine; + + final Position hack = range; + range = new AbstractSourcePosition() { + public int getFirstLine() { return hack.getFirstLine(); } + public int getLastLine() { return hack.getFirstLine(); } + public int getFirstCol() { return hack.getFirstCol(); } + public int getLastCol() { return hack.getFirstCol(); } + public URL getURL() { return hack.getURL(); } + public InputStream getInputStream() throws IOException { + return hack.getInputStream(); + } + }; + } + + String[] newTextLines = newText.split("\n"); + + if (newTextLines.length == 1) { + lines[startLine] = + lines[startLine].substring(0, range.getFirstCol()) + + newTextLines[0] + + lines[startLine].substring(range.getLastCol()+1); + } else { + String[] newLines = + new String[ lines.length + newTextLines.length - 1 ]; + int i = 0; + while (i < startLine) { + newLines[i] = lines[i]; + i++; + } + + newLines[i++] = + lines[startLine].substring(0, range.getFirstCol()) + + newTextLines[0]; + + for(int j = 1; j < newTextLines.length - 1; j++) { + lines[i++] = newTextLines[j]; + } + + newLines[i++] = + newTextLines[newTextLines.length-1] + + lines[endLine].substring(range.getLastCol()+1); + + while (i < newLines.length) { + newLines[i] = lines[i - newTextLines.length + 1]; + i++; + } + + lines = newLines; + } + } +} + + diff --git a/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/TemporaryFile.java b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/TemporaryFile.java new file mode 100644 index 000000000..8807df244 --- /dev/null +++ b/com.ibm.wala.cast/source/java/com/ibm/wala/cast/util/TemporaryFile.java @@ -0,0 +1,51 @@ +/****************************************************************************** + * Copyright (c) 2002 - 2006 IBM Corporation. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *****************************************************************************/ +package com.ibm.wala.cast.util; + +import com.ibm.wala.util.warnings.*; + +import java.io.*; +import java.net.*; + +public class TemporaryFile { + + private final static String outputDir; + + static { + String dir = System.getProperty("java.io.tmpdir"); + + while (dir.endsWith(File.separator)) + dir = dir.substring(0, dir.length()-1); + + dir = dir + File.separator; + + outputDir = dir; + } + + public static File urlToFile(String fileName, URL input) throws IOException { + return streamToFile( fileName, input.openStream() ); + } + + public static File streamToFile(String fileName, InputStream input) throws IOException { + File F = new File(outputDir + File.separator + fileName); + FileOutputStream output = new FileOutputStream(F); + int read; + byte[] buffer = new byte[ 1024 ]; + while ( (read = input.read(buffer)) != -1 ) { + output.write(buffer, 0, read); + } + + output.close(); + input.close(); + + return F; + } +}