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!k7kiGpf3WK+F!)WLk!qD*(p\tBo@fQS>pAb-mqu6f:)urCorVlp1!:0CZ
+"Rn#D2YHtIrrDcmrrDcmrrDfnJ,~>
+r;QigLu7t,"T2a0!k7kiGpf3WK+F!)WLk!qD*(p\tBo@fQS>pAb-mqu6f:)urCorVlp1!:0CZ
+"Rn#D2YHtIrrDcmrrDcmrrDfnJ,~>
+r;QigLu7t,"T2a0!k7kiGpf3WK+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 ( :=
+ *
+ * @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:
+ *
+ */
+ 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("" + kindAsString(top.getKind()) + ">\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;
+ }
+}