attempt to introduce tags and trunk
git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@490 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
commit
df97f42b7e
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="src" path="dat"/>
|
||||||
|
<classpathentry kind="src" path="lib"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>com.ibm.wala.core</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.pde.PluginNature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
|
@ -0,0 +1,12 @@
|
||||||
|
#Mon Oct 02 08:58:10 EDT 2006
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||||
|
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||||
|
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.5
|
|
@ -0,0 +1,3 @@
|
||||||
|
#Mon Oct 02 08:58:11 EDT 2006
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
internal.default.compliance=default
|
|
@ -0,0 +1,68 @@
|
||||||
|
Manifest-Version: 1.0
|
||||||
|
Bundle-ManifestVersion: 2
|
||||||
|
Bundle-Name: WALA Core Plug-in
|
||||||
|
Bundle-SymbolicName: com.ibm.wala.core
|
||||||
|
Bundle-Version: 1.0.0
|
||||||
|
Bundle-Activator: com.ibm.wala.core.plugin.CorePlugin
|
||||||
|
Bundle-Vendor: IBM
|
||||||
|
Bundle-Localization: plugin
|
||||||
|
Require-Bundle: com.ibm.wala.emf;visibility:=reexport,
|
||||||
|
com.ibm.wala.shrike;visibility:=reexport,
|
||||||
|
org.eclipse.core.resources,
|
||||||
|
org.eclipse.jface,
|
||||||
|
org.eclipse.jdt.core
|
||||||
|
Eclipse-LazyStart: true
|
||||||
|
Export-Package: .,
|
||||||
|
com.ibm.wala.analysis.pointers,
|
||||||
|
com.ibm.wala.analysis.reflection,
|
||||||
|
com.ibm.wala.analysis.stackMachine,
|
||||||
|
com.ibm.wala.analysis.typeInference,
|
||||||
|
com.ibm.wala.cfg,
|
||||||
|
com.ibm.wala.cfg.cdg,
|
||||||
|
com.ibm.wala.classLoader,
|
||||||
|
com.ibm.wala.client,
|
||||||
|
com.ibm.wala.client.impl,
|
||||||
|
com.ibm.wala.core.plugin,
|
||||||
|
com.ibm.wala.dataflow.IFDS,
|
||||||
|
com.ibm.wala.dataflow.graph,
|
||||||
|
com.ibm.wala.dataflow.ssa,
|
||||||
|
com.ibm.wala.dynamic,
|
||||||
|
com.ibm.wala.emf.wrappers,
|
||||||
|
com.ibm.wala.escape,
|
||||||
|
com.ibm.wala.fixedpoint.impl,
|
||||||
|
com.ibm.wala.fixpoint,
|
||||||
|
com.ibm.wala.ipa.callgraph,
|
||||||
|
com.ibm.wala.ipa.callgraph.impl,
|
||||||
|
com.ibm.wala.ipa.callgraph.propagation,
|
||||||
|
com.ibm.wala.ipa.callgraph.propagation.cfa,
|
||||||
|
com.ibm.wala.ipa.callgraph.propagation.rta,
|
||||||
|
com.ibm.wala.ipa.cfg,
|
||||||
|
com.ibm.wala.ipa.cha,
|
||||||
|
com.ibm.wala.ipa.modref,
|
||||||
|
com.ibm.wala.ipa.slicer,
|
||||||
|
com.ibm.wala.ipa.summaries,
|
||||||
|
com.ibm.wala.model,
|
||||||
|
com.ibm.wala.model.java.lang,
|
||||||
|
com.ibm.wala.properties,
|
||||||
|
com.ibm.wala.ssa,
|
||||||
|
com.ibm.wala.ssa.analysis,
|
||||||
|
com.ibm.wala.types,
|
||||||
|
com.ibm.wala.util,
|
||||||
|
com.ibm.wala.util.bytecode,
|
||||||
|
com.ibm.wala.util.collections,
|
||||||
|
com.ibm.wala.util.config,
|
||||||
|
com.ibm.wala.util.debug,
|
||||||
|
com.ibm.wala.util.graph,
|
||||||
|
com.ibm.wala.util.graph.impl,
|
||||||
|
com.ibm.wala.util.graph.traverse,
|
||||||
|
com.ibm.wala.util.heapTrace,
|
||||||
|
com.ibm.wala.util.internationalization,
|
||||||
|
com.ibm.wala.util.intset,
|
||||||
|
com.ibm.wala.util.io,
|
||||||
|
com.ibm.wala.util.logging,
|
||||||
|
com.ibm.wala.util.math,
|
||||||
|
com.ibm.wala.util.perf,
|
||||||
|
com.ibm.wala.util.scope,
|
||||||
|
com.ibm.wala.util.system,
|
||||||
|
com.ibm.wala.util.warnings,
|
||||||
|
com.ibm.wala.viz
|
|
@ -0,0 +1,13 @@
|
||||||
|
bin.includes = lib/primordial.jar.model,\
|
||||||
|
plugin.properties,\
|
||||||
|
dat/J2SEClassHierarchyExclusions.xml,\
|
||||||
|
dat/SyntheticJ2SEModel.xml,\
|
||||||
|
dat/benign.xml,\
|
||||||
|
dat/natives.xml,\
|
||||||
|
META-INF/,\
|
||||||
|
.
|
||||||
|
jars.compile.order = .
|
||||||
|
output.. = bin/
|
||||||
|
source.. = dat/,\
|
||||||
|
src/,\
|
||||||
|
lib/
|
|
@ -0,0 +1,202 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project name="com.ibm.wala.core" default="build.jars" basedir=".">
|
||||||
|
|
||||||
|
<property name="basews" value="${ws}"/>
|
||||||
|
<property name="baseos" value="${os}"/>
|
||||||
|
<property name="basearch" value="${arch}"/>
|
||||||
|
<property name="basenl" value="${nl}"/>
|
||||||
|
|
||||||
|
<!-- Compiler settings. -->
|
||||||
|
<property name="javacFailOnError" value="true"/>
|
||||||
|
<property name="javacDebugInfo" value="on"/>
|
||||||
|
<property name="javacVerbose" value="false"/>
|
||||||
|
<property name="logExtension" value=".log"/>
|
||||||
|
<property name="compilerArg" value=""/>
|
||||||
|
<property name="javacSource" value="1.5"/>
|
||||||
|
<property name="javacTarget" value="1.5"/>
|
||||||
|
<path id="path_bootclasspath">
|
||||||
|
<fileset dir="${java.home}/lib">
|
||||||
|
<include name="*.jar"/>
|
||||||
|
</fileset>
|
||||||
|
</path>
|
||||||
|
<property name="bootclasspath" refid="path_bootclasspath"/>
|
||||||
|
<property name="bundleJavacSource" value="${javacSource}"/>
|
||||||
|
<property name="bundleJavacTarget" value="${javacTarget}"/>
|
||||||
|
<property name="bundleBootClasspath" value="${bootclasspath}"/>
|
||||||
|
|
||||||
|
<target name="init" depends="properties">
|
||||||
|
<condition property="pluginTemp" value="${buildTempFolder}/plugins">
|
||||||
|
<isset property="buildTempFolder"/>
|
||||||
|
</condition>
|
||||||
|
<property name="pluginTemp" value="${basedir}"/>
|
||||||
|
<condition property="build.result.folder" value="${pluginTemp}/com.ibm.wala.core">
|
||||||
|
<isset property="buildTempFolder"/>
|
||||||
|
</condition>
|
||||||
|
<property name="build.result.folder" value="${basedir}"/>
|
||||||
|
<property name="temp.folder" value="${basedir}/temp.folder"/>
|
||||||
|
<property name="plugin.destination" value="${basedir}/output"/>
|
||||||
|
<property name="eclipse.root" value="c:/eclipse"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="properties" if="eclipse.running">
|
||||||
|
<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
|
||||||
|
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="build.update.jar" depends="init" description="Build the plug-in: com.ibm.wala.core for an update site.">
|
||||||
|
<delete dir="${temp.folder}"/>
|
||||||
|
<mkdir dir="${temp.folder}"/>
|
||||||
|
<delete dir="${plugin.destination}"/>
|
||||||
|
<mkdir dir="${plugin.destination}"/>
|
||||||
|
<antcall target="build.jars"/>
|
||||||
|
<antcall target="gather.bin.parts">
|
||||||
|
<param name="destination.temp.folder" value="${temp.folder}/"/>
|
||||||
|
</antcall>
|
||||||
|
<copy todir="${temp.folder}/com.ibm.wala.core_1.0.0" failonerror="true" overwrite="false">
|
||||||
|
<fileset dir="src/" includes="**/*.java" />
|
||||||
|
</copy>
|
||||||
|
<zip destfile="${plugin.destination}/com.ibm.wala.core_1.0.0.jar" basedir="${temp.folder}/com.ibm.wala.core_1.0.0" filesonly="false" whenempty="skip" update="false"/>
|
||||||
|
<delete dir="${temp.folder}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="@dot" depends="init" description="Create jar: com.ibm.wala.core @dot.">
|
||||||
|
<delete dir="${temp.folder}/@dot.bin"/>
|
||||||
|
<mkdir dir="${temp.folder}/@dot.bin"/>
|
||||||
|
<path id="@dot.classpath">
|
||||||
|
<pathelement path="../com.ibm.wala.emf/bin/"/>
|
||||||
|
<pathelement path="../com.ibm.wala.emf/@dot"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.runtime_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.osgi_3.2.0.v20060601.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.equinox.common_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.jobs_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.runtime.compatibility.registry_3.2.0.v20060603/runtime_registry_compatibility.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.runtime.compatibility.registry_3.2.0.v20060603"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.equinox.registry_3.2.0.v20060601.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.apache.xerces_2.8.0.v200606131651/resolver.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.apache.xerces_2.8.0.v200606131651/xercesImpl.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.apache.xerces_2.8.0.v200606131651/xml-apis.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.equinox.preferences_3.2.0.v20060601.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.runtime.compatibility.registry_3.2.0.v20060603/@dot"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.contenttype_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.runtime.compatibility.auth_3.2.0.v20060601.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.emf.ecore_2.2.0.v200606271057.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.emf.common_2.2.0.v200606271057.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.resources_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.resources.compatibility_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.resources.win32_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.runtime.compatibility_3.1.100.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.update.configurator_3.2.0.v20060605.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.ant.core_3.1.100.v20060531.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.variables_3.1.100.v20060605.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.expressions_3.2.0.v20060605-1400.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.filesystem_1.0.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.filesystem.win32.x86_1.0.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.emf.ecore.xmi_2.2.0.v200606271057.jar"/>
|
||||||
|
<pathelement path="../com.ibm.wala.shrike/bin/"/>
|
||||||
|
<pathelement path="../com.ibm.wala.shrike/@dot"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.jface_3.2.0.I20060605-1400.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.swt_3.2.0.v3232o.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.swt.win32.win32.x86_3.2.0.v3232m.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.commands_3.2.0.I20060605-1400.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.jdt.core_3.2.0.v_671.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.text_3.2.0.v20060605-1400.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/com.ibm.icu_3.4.4.1.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.team.core_3.2.0.I200606051140.jar"/>
|
||||||
|
</path>
|
||||||
|
<!-- compile the source code -->
|
||||||
|
<javac destdir="${temp.folder}/@dot.bin" failonerror="${javacFailOnError}" verbose="${javacVerbose}" debug="${javacDebugInfo}" includeAntRuntime="no" bootclasspath="${bundleBootClasspath}" source="${bundleJavacSource}" target="${bundleJavacTarget}" >
|
||||||
|
<compilerarg line="${compilerArg}" compiler="${build.compiler}"/>
|
||||||
|
<classpath refid="@dot.classpath" />
|
||||||
|
<src path="dat/" />
|
||||||
|
<src path="src/" />
|
||||||
|
<src path="lib/" />
|
||||||
|
<compilerarg value="@${basedir}/javaCompiler...args" compiler="org.eclipse.jdt.core.JDTCompilerAdapter"/>
|
||||||
|
<compilerarg line="-log '${temp.folder}/@dot.bin${logExtension}'" compiler="org.eclipse.jdt.core.JDTCompilerAdapter"/>
|
||||||
|
</javac>
|
||||||
|
<!-- Copy necessary resources -->
|
||||||
|
<copy todir="${temp.folder}/@dot.bin" failonerror="true" overwrite="false">
|
||||||
|
<fileset dir="dat/" excludes="**/*.java, **/package.htm*" />
|
||||||
|
<fileset dir="src/" excludes="**/*.java, **/package.htm*" />
|
||||||
|
<fileset dir="lib/" excludes="**/*.java, **/package.htm*" />
|
||||||
|
</copy>
|
||||||
|
<mkdir dir="${build.result.folder}"/>
|
||||||
|
<copy todir="${build.result.folder}/@dot" failonerror="true" overwrite="false">
|
||||||
|
<fileset dir="${temp.folder}/@dot.bin" />
|
||||||
|
</copy>
|
||||||
|
<delete dir="${temp.folder}/@dot.bin"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="src.zip" depends="init" unless="src.zip">
|
||||||
|
<mkdir dir="${build.result.folder}"/>
|
||||||
|
<zip destfile="${build.result.folder}/src.zip" filesonly="false" whenempty="skip" update="false">
|
||||||
|
<fileset dir="dat/" includes="**/*.java" />
|
||||||
|
<fileset dir="src/" includes="**/*.java" />
|
||||||
|
<fileset dir="lib/" includes="**/*.java" />
|
||||||
|
</zip>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="build.jars" depends="init" description="Build all the jars for the plug-in: com.ibm.wala.core.">
|
||||||
|
<available property="@dot" file="${build.result.folder}/@dot"/>
|
||||||
|
<antcall target="@dot"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="build.sources" depends="init">
|
||||||
|
<available property="src.zip" file="${build.result.folder}/src.zip"/>
|
||||||
|
<antcall target="src.zip"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="gather.bin.parts" depends="init" if="destination.temp.folder">
|
||||||
|
<mkdir dir="${destination.temp.folder}/com.ibm.wala.core_1.0.0"/>
|
||||||
|
<copy todir="${destination.temp.folder}/com.ibm.wala.core_1.0.0" failonerror="true" overwrite="false">
|
||||||
|
<fileset dir="${build.result.folder}/@dot" includes="**" />
|
||||||
|
</copy>
|
||||||
|
<copy todir="${destination.temp.folder}/com.ibm.wala.core_1.0.0" failonerror="true" overwrite="false">
|
||||||
|
<fileset dir="${basedir}" includes="lib/primordial.jar.model,plugin.properties,lib/extension.jar.model,dat/J2SEClassHierarchyExclusions.xml,dat/SyntheticJ2SEModel.xml,dat/benign.xml,dat/natives.xml,META-INF/" />
|
||||||
|
</copy>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="build.zips" depends="init">
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="gather.sources" depends="init" if="destination.temp.folder">
|
||||||
|
<mkdir dir="${destination.temp.folder}/com.ibm.wala.core_1.0.0"/>
|
||||||
|
<copy file="${build.result.folder}/src.zip" todir="${destination.temp.folder}/com.ibm.wala.core_1.0.0" failonerror="false" overwrite="false"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="gather.logs" depends="init" if="destination.temp.folder">
|
||||||
|
<mkdir dir="${destination.temp.folder}/com.ibm.wala.core_1.0.0"/>
|
||||||
|
<copy file="${temp.folder}/@dot.bin${logExtension}" todir="${destination.temp.folder}/com.ibm.wala.core_1.0.0" failonerror="false" overwrite="false"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="clean" depends="init" description="Clean the plug-in: com.ibm.wala.core of all the zips, jars and logs created.">
|
||||||
|
<delete dir="${build.result.folder}/@dot"/>
|
||||||
|
<delete file="${build.result.folder}/src.zip"/>
|
||||||
|
<delete file="${plugin.destination}/com.ibm.wala.core_1.0.0.jar"/>
|
||||||
|
<delete file="${plugin.destination}/com.ibm.wala.core_1.0.0.zip"/>
|
||||||
|
<delete dir="${temp.folder}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="refresh" depends="init" if="eclipse.running" description="Refresh this folder.">
|
||||||
|
<eclipse.convertPath fileSystemPath="C:/temp/walaWorkspace/com.ibm.wala.core" property="resourcePath"/>
|
||||||
|
<eclipse.refreshLocal resource="${resourcePath}" depth="infinite"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="zip.plugin" depends="init" description="Create a zip containing all the elements for the plug-in: com.ibm.wala.core.">
|
||||||
|
<delete dir="${temp.folder}"/>
|
||||||
|
<mkdir dir="${temp.folder}"/>
|
||||||
|
<antcall target="build.jars"/>
|
||||||
|
<antcall target="build.sources"/>
|
||||||
|
<antcall target="gather.bin.parts">
|
||||||
|
<param name="destination.temp.folder" value="${temp.folder}/"/>
|
||||||
|
</antcall>
|
||||||
|
<antcall target="gather.sources">
|
||||||
|
<param name="destination.temp.folder" value="${temp.folder}/"/>
|
||||||
|
</antcall>
|
||||||
|
<delete>
|
||||||
|
<fileset dir="${temp.folder}" includes="**/*.bin${logExtension}" />
|
||||||
|
</delete>
|
||||||
|
<zip destfile="${plugin.destination}/com.ibm.wala.core_1.0.0.zip" basedir="${temp.folder}" filesonly="true" whenempty="skip" update="false"/>
|
||||||
|
<delete dir="${temp.folder}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="src" path="dat"/>
|
||||||
|
<classpathentry kind="src" path="lib"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>com.ibm.wala.core</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.pde.PluginNature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
|
@ -0,0 +1,7 @@
|
||||||
|
#Tue Nov 21 13:03:57 EST 2006
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||||
|
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
|
@ -0,0 +1,3 @@
|
||||||
|
#Mon Oct 02 08:58:11 EDT 2006
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
internal.default.compliance=default
|
|
@ -0,0 +1,68 @@
|
||||||
|
Manifest-Version: 1.0
|
||||||
|
Bundle-ManifestVersion: 2
|
||||||
|
Bundle-Name: WALA Core Plug-in
|
||||||
|
Bundle-SymbolicName: com.ibm.wala.core
|
||||||
|
Bundle-Version: 1.0.0
|
||||||
|
Bundle-Activator: com.ibm.wala.core.plugin.CorePlugin
|
||||||
|
Bundle-Vendor: IBM
|
||||||
|
Bundle-Localization: plugin
|
||||||
|
Require-Bundle: com.ibm.wala.emf;visibility:=reexport,
|
||||||
|
com.ibm.wala.shrike;visibility:=reexport,
|
||||||
|
org.eclipse.core.resources,
|
||||||
|
org.eclipse.jface,
|
||||||
|
org.eclipse.jdt.core
|
||||||
|
Eclipse-LazyStart: true
|
||||||
|
Export-Package: .,
|
||||||
|
com.ibm.wala.analysis.pointers,
|
||||||
|
com.ibm.wala.analysis.reflection,
|
||||||
|
com.ibm.wala.analysis.stackMachine,
|
||||||
|
com.ibm.wala.analysis.typeInference,
|
||||||
|
com.ibm.wala.cfg,
|
||||||
|
com.ibm.wala.cfg.cdg,
|
||||||
|
com.ibm.wala.classLoader,
|
||||||
|
com.ibm.wala.client,
|
||||||
|
com.ibm.wala.client.impl,
|
||||||
|
com.ibm.wala.core.plugin,
|
||||||
|
com.ibm.wala.dataflow.IFDS,
|
||||||
|
com.ibm.wala.dataflow.graph,
|
||||||
|
com.ibm.wala.dataflow.ssa,
|
||||||
|
com.ibm.wala.dynamic,
|
||||||
|
com.ibm.wala.emf.wrappers,
|
||||||
|
com.ibm.wala.escape,
|
||||||
|
com.ibm.wala.fixedpoint.impl,
|
||||||
|
com.ibm.wala.fixpoint,
|
||||||
|
com.ibm.wala.ipa.callgraph,
|
||||||
|
com.ibm.wala.ipa.callgraph.impl,
|
||||||
|
com.ibm.wala.ipa.callgraph.propagation,
|
||||||
|
com.ibm.wala.ipa.callgraph.propagation.cfa,
|
||||||
|
com.ibm.wala.ipa.callgraph.propagation.rta,
|
||||||
|
com.ibm.wala.ipa.cfg,
|
||||||
|
com.ibm.wala.ipa.cha,
|
||||||
|
com.ibm.wala.ipa.modref,
|
||||||
|
com.ibm.wala.ipa.slicer,
|
||||||
|
com.ibm.wala.ipa.summaries,
|
||||||
|
com.ibm.wala.model,
|
||||||
|
com.ibm.wala.model.java.lang,
|
||||||
|
com.ibm.wala.properties,
|
||||||
|
com.ibm.wala.ssa,
|
||||||
|
com.ibm.wala.ssa.analysis,
|
||||||
|
com.ibm.wala.types,
|
||||||
|
com.ibm.wala.util,
|
||||||
|
com.ibm.wala.util.bytecode,
|
||||||
|
com.ibm.wala.util.collections,
|
||||||
|
com.ibm.wala.util.config,
|
||||||
|
com.ibm.wala.util.debug,
|
||||||
|
com.ibm.wala.util.graph,
|
||||||
|
com.ibm.wala.util.graph.impl,
|
||||||
|
com.ibm.wala.util.graph.traverse,
|
||||||
|
com.ibm.wala.util.heapTrace,
|
||||||
|
com.ibm.wala.util.internationalization,
|
||||||
|
com.ibm.wala.util.intset,
|
||||||
|
com.ibm.wala.util.io,
|
||||||
|
com.ibm.wala.util.logging,
|
||||||
|
com.ibm.wala.util.math,
|
||||||
|
com.ibm.wala.util.perf,
|
||||||
|
com.ibm.wala.util.scope,
|
||||||
|
com.ibm.wala.util.system,
|
||||||
|
com.ibm.wala.util.warnings,
|
||||||
|
com.ibm.wala.viz
|
|
@ -0,0 +1,13 @@
|
||||||
|
bin.includes = lib/primordial.jar.model,\
|
||||||
|
plugin.properties,\
|
||||||
|
dat/J2SEClassHierarchyExclusions.xml,\
|
||||||
|
dat/SyntheticJ2SEModel.xml,\
|
||||||
|
dat/benign.xml,\
|
||||||
|
dat/natives.xml,\
|
||||||
|
META-INF/,\
|
||||||
|
.
|
||||||
|
jars.compile.order = .
|
||||||
|
output.. = bin/
|
||||||
|
source.. = dat/,\
|
||||||
|
src/,\
|
||||||
|
lib/
|
|
@ -0,0 +1,202 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project name="com.ibm.wala.core" default="build.jars" basedir=".">
|
||||||
|
|
||||||
|
<property name="basews" value="${ws}"/>
|
||||||
|
<property name="baseos" value="${os}"/>
|
||||||
|
<property name="basearch" value="${arch}"/>
|
||||||
|
<property name="basenl" value="${nl}"/>
|
||||||
|
|
||||||
|
<!-- Compiler settings. -->
|
||||||
|
<property name="javacFailOnError" value="true"/>
|
||||||
|
<property name="javacDebugInfo" value="on"/>
|
||||||
|
<property name="javacVerbose" value="false"/>
|
||||||
|
<property name="logExtension" value=".log"/>
|
||||||
|
<property name="compilerArg" value=""/>
|
||||||
|
<property name="javacSource" value="1.5"/>
|
||||||
|
<property name="javacTarget" value="1.5"/>
|
||||||
|
<path id="path_bootclasspath">
|
||||||
|
<fileset dir="${java.home}/lib">
|
||||||
|
<include name="*.jar"/>
|
||||||
|
</fileset>
|
||||||
|
</path>
|
||||||
|
<property name="bootclasspath" refid="path_bootclasspath"/>
|
||||||
|
<property name="bundleJavacSource" value="${javacSource}"/>
|
||||||
|
<property name="bundleJavacTarget" value="${javacTarget}"/>
|
||||||
|
<property name="bundleBootClasspath" value="${bootclasspath}"/>
|
||||||
|
|
||||||
|
<target name="init" depends="properties">
|
||||||
|
<condition property="pluginTemp" value="${buildTempFolder}/plugins">
|
||||||
|
<isset property="buildTempFolder"/>
|
||||||
|
</condition>
|
||||||
|
<property name="pluginTemp" value="${basedir}"/>
|
||||||
|
<condition property="build.result.folder" value="${pluginTemp}/com.ibm.wala.core">
|
||||||
|
<isset property="buildTempFolder"/>
|
||||||
|
</condition>
|
||||||
|
<property name="build.result.folder" value="${basedir}"/>
|
||||||
|
<property name="temp.folder" value="${basedir}/temp.folder"/>
|
||||||
|
<property name="plugin.destination" value="${basedir}/output"/>
|
||||||
|
<property name="eclipse.root" value="c:/eclipse"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="properties" if="eclipse.running">
|
||||||
|
<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>
|
||||||
|
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="build.update.jar" depends="init" description="Build the plug-in: com.ibm.wala.core for an update site.">
|
||||||
|
<delete dir="${temp.folder}"/>
|
||||||
|
<mkdir dir="${temp.folder}"/>
|
||||||
|
<delete dir="${plugin.destination}"/>
|
||||||
|
<mkdir dir="${plugin.destination}"/>
|
||||||
|
<antcall target="build.jars"/>
|
||||||
|
<antcall target="gather.bin.parts">
|
||||||
|
<param name="destination.temp.folder" value="${temp.folder}/"/>
|
||||||
|
</antcall>
|
||||||
|
<copy todir="${temp.folder}/com.ibm.wala.core_1.0.0" failonerror="true" overwrite="false">
|
||||||
|
<fileset dir="src/" includes="**/*.java" />
|
||||||
|
</copy>
|
||||||
|
<zip destfile="${plugin.destination}/com.ibm.wala.core_1.0.0.jar" basedir="${temp.folder}/com.ibm.wala.core_1.0.0" filesonly="false" whenempty="skip" update="false"/>
|
||||||
|
<delete dir="${temp.folder}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="@dot" depends="init" description="Create jar: com.ibm.wala.core @dot.">
|
||||||
|
<delete dir="${temp.folder}/@dot.bin"/>
|
||||||
|
<mkdir dir="${temp.folder}/@dot.bin"/>
|
||||||
|
<path id="@dot.classpath">
|
||||||
|
<pathelement path="../com.ibm.wala.emf/bin/"/>
|
||||||
|
<pathelement path="../com.ibm.wala.emf/@dot"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.runtime_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.osgi_3.2.0.v20060601.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.equinox.common_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.jobs_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.runtime.compatibility.registry_3.2.0.v20060603/runtime_registry_compatibility.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.runtime.compatibility.registry_3.2.0.v20060603"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.equinox.registry_3.2.0.v20060601.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.apache.xerces_2.8.0.v200606131651/resolver.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.apache.xerces_2.8.0.v200606131651/xercesImpl.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.apache.xerces_2.8.0.v200606131651/xml-apis.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.equinox.preferences_3.2.0.v20060601.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.runtime.compatibility.registry_3.2.0.v20060603/@dot"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.contenttype_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.runtime.compatibility.auth_3.2.0.v20060601.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.emf.ecore_2.2.0.v200606271057.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.emf.common_2.2.0.v200606271057.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.resources_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.resources.compatibility_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.resources.win32_3.2.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.runtime.compatibility_3.1.100.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.update.configurator_3.2.0.v20060605.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.ant.core_3.1.100.v20060531.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.variables_3.1.100.v20060605.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.expressions_3.2.0.v20060605-1400.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.filesystem_1.0.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.filesystem.win32.x86_1.0.0.v20060603.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.emf.ecore.xmi_2.2.0.v200606271057.jar"/>
|
||||||
|
<pathelement path="../com.ibm.wala.shrike/bin/"/>
|
||||||
|
<pathelement path="../com.ibm.wala.shrike/@dot"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.jface_3.2.0.I20060605-1400.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.swt_3.2.0.v3232o.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.swt.win32.win32.x86_3.2.0.v3232m.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.core.commands_3.2.0.I20060605-1400.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.jdt.core_3.2.0.v_671.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.text_3.2.0.v20060605-1400.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/com.ibm.icu_3.4.4.1.jar"/>
|
||||||
|
<pathelement path="${eclipse.root}/plugins/org.eclipse.team.core_3.2.0.I200606051140.jar"/>
|
||||||
|
</path>
|
||||||
|
<!-- compile the source code -->
|
||||||
|
<javac destdir="${temp.folder}/@dot.bin" failonerror="${javacFailOnError}" verbose="${javacVerbose}" debug="${javacDebugInfo}" includeAntRuntime="no" bootclasspath="${bundleBootClasspath}" source="${bundleJavacSource}" target="${bundleJavacTarget}" >
|
||||||
|
<compilerarg line="${compilerArg}" compiler="${build.compiler}"/>
|
||||||
|
<classpath refid="@dot.classpath" />
|
||||||
|
<src path="dat/" />
|
||||||
|
<src path="src/" />
|
||||||
|
<src path="lib/" />
|
||||||
|
<compilerarg value="@${basedir}/javaCompiler...args" compiler="org.eclipse.jdt.core.JDTCompilerAdapter"/>
|
||||||
|
<compilerarg line="-log '${temp.folder}/@dot.bin${logExtension}'" compiler="org.eclipse.jdt.core.JDTCompilerAdapter"/>
|
||||||
|
</javac>
|
||||||
|
<!-- Copy necessary resources -->
|
||||||
|
<copy todir="${temp.folder}/@dot.bin" failonerror="true" overwrite="false">
|
||||||
|
<fileset dir="dat/" excludes="**/*.java, **/package.htm*" />
|
||||||
|
<fileset dir="src/" excludes="**/*.java, **/package.htm*" />
|
||||||
|
<fileset dir="lib/" excludes="**/*.java, **/package.htm*" />
|
||||||
|
</copy>
|
||||||
|
<mkdir dir="${build.result.folder}"/>
|
||||||
|
<copy todir="${build.result.folder}/@dot" failonerror="true" overwrite="false">
|
||||||
|
<fileset dir="${temp.folder}/@dot.bin" />
|
||||||
|
</copy>
|
||||||
|
<delete dir="${temp.folder}/@dot.bin"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="src.zip" depends="init" unless="src.zip">
|
||||||
|
<mkdir dir="${build.result.folder}"/>
|
||||||
|
<zip destfile="${build.result.folder}/src.zip" filesonly="false" whenempty="skip" update="false">
|
||||||
|
<fileset dir="dat/" includes="**/*.java" />
|
||||||
|
<fileset dir="src/" includes="**/*.java" />
|
||||||
|
<fileset dir="lib/" includes="**/*.java" />
|
||||||
|
</zip>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="build.jars" depends="init" description="Build all the jars for the plug-in: com.ibm.wala.core.">
|
||||||
|
<available property="@dot" file="${build.result.folder}/@dot"/>
|
||||||
|
<antcall target="@dot"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="build.sources" depends="init">
|
||||||
|
<available property="src.zip" file="${build.result.folder}/src.zip"/>
|
||||||
|
<antcall target="src.zip"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="gather.bin.parts" depends="init" if="destination.temp.folder">
|
||||||
|
<mkdir dir="${destination.temp.folder}/com.ibm.wala.core_1.0.0"/>
|
||||||
|
<copy todir="${destination.temp.folder}/com.ibm.wala.core_1.0.0" failonerror="true" overwrite="false">
|
||||||
|
<fileset dir="${build.result.folder}/@dot" includes="**" />
|
||||||
|
</copy>
|
||||||
|
<copy todir="${destination.temp.folder}/com.ibm.wala.core_1.0.0" failonerror="true" overwrite="false">
|
||||||
|
<fileset dir="${basedir}" includes="lib/primordial.jar.model,plugin.properties,lib/extension.jar.model,dat/J2SEClassHierarchyExclusions.xml,dat/SyntheticJ2SEModel.xml,dat/benign.xml,dat/natives.xml,META-INF/" />
|
||||||
|
</copy>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="build.zips" depends="init">
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="gather.sources" depends="init" if="destination.temp.folder">
|
||||||
|
<mkdir dir="${destination.temp.folder}/com.ibm.wala.core_1.0.0"/>
|
||||||
|
<copy file="${build.result.folder}/src.zip" todir="${destination.temp.folder}/com.ibm.wala.core_1.0.0" failonerror="false" overwrite="false"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="gather.logs" depends="init" if="destination.temp.folder">
|
||||||
|
<mkdir dir="${destination.temp.folder}/com.ibm.wala.core_1.0.0"/>
|
||||||
|
<copy file="${temp.folder}/@dot.bin${logExtension}" todir="${destination.temp.folder}/com.ibm.wala.core_1.0.0" failonerror="false" overwrite="false"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="clean" depends="init" description="Clean the plug-in: com.ibm.wala.core of all the zips, jars and logs created.">
|
||||||
|
<delete dir="${build.result.folder}/@dot"/>
|
||||||
|
<delete file="${build.result.folder}/src.zip"/>
|
||||||
|
<delete file="${plugin.destination}/com.ibm.wala.core_1.0.0.jar"/>
|
||||||
|
<delete file="${plugin.destination}/com.ibm.wala.core_1.0.0.zip"/>
|
||||||
|
<delete dir="${temp.folder}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="refresh" depends="init" if="eclipse.running" description="Refresh this folder.">
|
||||||
|
<eclipse.convertPath fileSystemPath="C:/temp/walaWorkspace/com.ibm.wala.core" property="resourcePath"/>
|
||||||
|
<eclipse.refreshLocal resource="${resourcePath}" depth="infinite"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="zip.plugin" depends="init" description="Create a zip containing all the elements for the plug-in: com.ibm.wala.core.">
|
||||||
|
<delete dir="${temp.folder}"/>
|
||||||
|
<mkdir dir="${temp.folder}"/>
|
||||||
|
<antcall target="build.jars"/>
|
||||||
|
<antcall target="build.sources"/>
|
||||||
|
<antcall target="gather.bin.parts">
|
||||||
|
<param name="destination.temp.folder" value="${temp.folder}/"/>
|
||||||
|
</antcall>
|
||||||
|
<antcall target="gather.sources">
|
||||||
|
<param name="destination.temp.folder" value="${temp.folder}/"/>
|
||||||
|
</antcall>
|
||||||
|
<delete>
|
||||||
|
<fileset dir="${temp.folder}" includes="**/*.bin${logExtension}" />
|
||||||
|
</delete>
|
||||||
|
<zip destfile="${plugin.destination}/com.ibm.wala.core_1.0.0.zip" basedir="${temp.folder}" filesonly="true" whenempty="skip" update="false"/>
|
||||||
|
<delete dir="${temp.folder}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1 @@
|
||||||
|
wala.properties
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="ASCII"?>
|
||||||
|
<com.ibm.wala.common:EContainer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:com.ibm.wala.common="http:///com/ibm/wala/wala.ecore.common" xmlns:com.ibm.wala.regex="http:///com/ibm/wala/wala.ecore.regex">
|
||||||
|
<contents xsi:type="com.ibm.wala.regex:EPattern" pattern="java\/awt\/.*"/>
|
||||||
|
<contents xsi:type="com.ibm.wala.regex:EPattern" pattern="java\/lang\/Boolean"/>
|
||||||
|
<contents xsi:type="com.ibm.wala.regex:EPattern" pattern="java\/lang\/Integer"/>
|
||||||
|
<contents xsi:type="com.ibm.wala.regex:EPattern" pattern="java\/lang\/StringBuffer"/>
|
||||||
|
<contents xsi:type="com.ibm.wala.regex:EPattern" pattern="java\/lang\/SecurityManager"/>
|
||||||
|
<contents xsi:type="com.ibm.wala.regex:EPattern" pattern="java\/lang\/Float"/>
|
||||||
|
<contents xsi:type="com.ibm.wala.regex:EPattern" pattern="java\/net\/.*"/>
|
||||||
|
<contents xsi:type="com.ibm.wala.regex:EPattern" pattern="java\/util\/.*"/>
|
||||||
|
<contents xsi:type="com.ibm.wala.regex:EPattern" pattern="javax\/.*"/>
|
||||||
|
<contents xsi:type="com.ibm.wala.regex:EPattern" pattern="sun\/.*"/>
|
||||||
|
</com.ibm.wala.common:EContainer>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<com.ibm.wala.java.scope:EJavaAnalysisScope xmlns:com.ibm.wala.java.scope="http:///com/ibm/wala/wala.ecore.java.scope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<loaders loaderName="Primordial">
|
||||||
|
<modules xsi:type="com.ibm.wala.java.scope:EBuiltInModule" id="primordial_jar_model"/>
|
||||||
|
</loaders>
|
||||||
|
</com.ibm.wala.java.scope:EJavaAnalysisScope>
|
|
@ -0,0 +1,15 @@
|
||||||
|
########## General messages
|
||||||
|
|
||||||
|
########## Error messages
|
||||||
|
|
||||||
|
AbstractPropertyReader.invalid_property_value=Value for property ''{0}'' is invalid.
|
||||||
|
AbstractPropertyReader.location_error=Path for file ''{0}'' do not exist and can''t be constructed.
|
||||||
|
AbstractPropertyReader.no_string_value=Property ''{0}'' is not mapped to a string as expected.
|
||||||
|
AbstractPropertyReader.incorrect_boolean_value=Boolean property ''{0}'' should not be mapped to a string.
|
||||||
|
AbstractPropertyReader.incorrect_int_value=Integer property ''{0}'' should be mapped to an Integer object.
|
||||||
|
AbstractPropertyReader.int_conversion_failed=Integer property ''{0}'' cannot convert ''{1}'' to an integer.
|
||||||
|
|
||||||
|
CancelCHAConstructionException.cancelation_message=ClassHierarchy construction has been cancelled by progress monitor.
|
||||||
|
|
||||||
|
PersistentPropertiesManager.property_file_unreadable=Unable to read property file named ''{0}''.
|
||||||
|
PersistentPropertiesManager.reading_failure=Failed to load ''{0}''.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,42 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?><templates><template autoinsert="true" context="gettercomment_context" deleted="false" description="Comment for getter method" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name="gettercomment">/**
|
||||||
|
* @return the ${bare_field_name}
|
||||||
|
*/</template><template autoinsert="true" context="settercomment_context" deleted="false" description="Comment for setter method" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.settercomment" name="settercomment">/**
|
||||||
|
* @param ${param} the ${bare_field_name} to set
|
||||||
|
*/</template><template autoinsert="true" context="constructorcomment_context" deleted="false" description="Comment for created constructors" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name="constructorcomment">/**
|
||||||
|
* ${tags}
|
||||||
|
*/</template><template autoinsert="true" context="filecomment_context" deleted="false" description="Comment for created Java files" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.filecomment" name="filecomment">/**
|
||||||
|
*
|
||||||
|
*/</template><template autoinsert="true" context="typecomment_context" deleted="false" description="Comment for created types" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.typecomment" name="typecomment">/**
|
||||||
|
* @author ${user}
|
||||||
|
*
|
||||||
|
* ${tags}
|
||||||
|
*/</template><template autoinsert="true" context="fieldcomment_context" deleted="false" description="Comment for fields" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name="fieldcomment">/**
|
||||||
|
*
|
||||||
|
*/</template><template autoinsert="true" context="methodcomment_context" deleted="false" description="Comment for non-overriding methods" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name="methodcomment">/**
|
||||||
|
* ${tags}
|
||||||
|
*/</template><template autoinsert="true" context="overridecomment_context" deleted="false" description="Comment for overriding methods" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name="overridecomment">/* (non-Javadoc)
|
||||||
|
* ${see_to_overridden}
|
||||||
|
*/</template><template autoinsert="true" context="delegatecomment_context" deleted="false" description="Comment for delegate methods" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name="delegatecomment">/**
|
||||||
|
* ${tags}
|
||||||
|
* ${see_to_target}
|
||||||
|
*/</template><template autoinsert="false" context="newtype_context" deleted="false" description="Newly created files" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.newtype" name="newtype">/*******************************************************************************
|
||||||
|
* Copyright (c) 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_declaration}
|
||||||
|
|
||||||
|
${typecomment}
|
||||||
|
${type_declaration}</template><template autoinsert="true" context="classbody_context" deleted="false" description="Code in new class type bodies" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.classbody" name="classbody">
|
||||||
|
</template><template autoinsert="true" context="interfacebody_context" deleted="false" description="Code in new interface type bodies" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name="interfacebody">
|
||||||
|
</template><template autoinsert="true" context="enumbody_context" deleted="false" description="Code in new enum type bodies" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.enumbody" name="enumbody">
|
||||||
|
</template><template autoinsert="true" context="annotationbody_context" deleted="false" description="Code in new annotation type bodies" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name="annotationbody">
|
||||||
|
</template><template autoinsert="true" context="catchblock_context" deleted="false" description="Code in new catch blocks" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.catchblock" name="catchblock">// ${todo} Auto-generated catch block
|
||||||
|
${exception_var}.printStackTrace();</template><template autoinsert="true" context="methodbody_context" deleted="false" description="Code in created method stubs" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.methodbody" name="methodbody">// ${todo} Auto-generated method stub
|
||||||
|
${body_statement}</template><template autoinsert="true" context="constructorbody_context" deleted="false" description="Code in created constructor stubs" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name="constructorbody">${body_statement}
|
||||||
|
// ${todo} Auto-generated constructor stub</template><template autoinsert="true" context="getterbody_context" deleted="false" description="Code in created getters" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.getterbody" name="getterbody">return ${field};</template><template autoinsert="true" context="setterbody_context" deleted="false" description="Code in created setters" enabled="true" id="org.eclipse.jdt.ui.text.codetemplates.setterbody" name="setterbody">${field} = ${param};</template></templates>
|
|
@ -0,0 +1,251 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<profiles version="10">
|
||||||
|
<profile name="WALA" version="10">
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_binary_expression" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_comments" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_binary_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_binary_operator" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="132"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="2"/>
|
||||||
|
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Handlers installed for the root logger
|
||||||
|
handlers= java.util.logging.ConsoleHandler java.util.logging.FileHandler
|
||||||
|
|
||||||
|
### Configure FileHandler
|
||||||
|
# Logging file name in temporary directory of the machine.
|
||||||
|
java.util.logging.FileHandler.pattern = %t/safeLogFile%g.log
|
||||||
|
# Write 100 kbytes before rotating this file
|
||||||
|
java.util.logging.FileHandler.limit = 100000
|
||||||
|
# Number of rotating files to be used
|
||||||
|
java.util.logging.FileHandler.count = 3
|
||||||
|
# Formatter to be used with this FileHandler
|
||||||
|
java.util.logging.FileHandler.formatter = com.ibm.wala.util.logging.SimplifiedFormatter
|
||||||
|
|
||||||
|
# Configure ConsoleHandler
|
||||||
|
java.util.logging.ConsoleHandler.level = WARNING
|
||||||
|
java.util.logging.ConsoleHandler.formatter = com.ibm.wala.util.logging.SimplifiedFormatter
|
|
@ -0,0 +1,784 @@
|
||||||
|
<?xml version="1.0" ?>
|
||||||
|
<!-- native methods in the IBM Windows DK 1.3.1 -->
|
||||||
|
<summary-spec>
|
||||||
|
<classloader name="Primordial">
|
||||||
|
|
||||||
|
<package name="com/ibm/wala/model">
|
||||||
|
<class name="SyntheticFactory">
|
||||||
|
<method name="getObject"
|
||||||
|
descriptor="()Ljava/lang/Object;" factory="true" static="true">
|
||||||
|
<new def="x" class="Lcom/ibm/wala/Malleable" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
</package>
|
||||||
|
|
||||||
|
<package name="com/ibm/jvm">
|
||||||
|
<class name="ExtendedSystem">
|
||||||
|
<method name="isResettableJVM" descriptor="()Z"
|
||||||
|
static="true">
|
||||||
|
</method>
|
||||||
|
<method name="setJVMUnresettableConditionally"
|
||||||
|
descriptor="(ILjava/lang/String;)V" static="true">
|
||||||
|
</method>
|
||||||
|
<method name="resizeArray"
|
||||||
|
descriptor="(ILjava/lang/Object;II)Ljava/lang/Object;"
|
||||||
|
factory="true" static="true">
|
||||||
|
<new def="x" class="Lcom/ibm/wala/Malleable" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
|
||||||
|
</package>
|
||||||
|
|
||||||
|
<package name="java/io">
|
||||||
|
<class name="FileDescriptor">
|
||||||
|
<method name="sync" descriptor="()V"></method>
|
||||||
|
</class>
|
||||||
|
<class name="FileInputStream">
|
||||||
|
<method name="available" descriptor="()I">
|
||||||
|
<constant name="yes" type="int" value="1" />
|
||||||
|
<constant name="no" type="int" value="0" />
|
||||||
|
<return value="yes" />
|
||||||
|
<return value="no" />
|
||||||
|
<new def="x" class="Ljava/io/IOException" />
|
||||||
|
<throw value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="close" descriptor="()V">
|
||||||
|
<new def="x" class="Ljava/io/IOException" />
|
||||||
|
<throw value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="open"
|
||||||
|
descriptor="(Ljava/lang/String;)V">
|
||||||
|
<new def="x" class="Ljava/io/IOException" />
|
||||||
|
<throw value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="read" descriptor="()I">
|
||||||
|
<constant name="yes" type="int" value="1" />
|
||||||
|
<constant name="no" type="int" value="0" />
|
||||||
|
<return value="yes" />
|
||||||
|
<return value="no" />
|
||||||
|
<new def="x" class="Ljava/io/IOException" />
|
||||||
|
<throw value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="readBytes" descriptor="([BII)I">
|
||||||
|
<constant name="yes" type="int" value="1" />
|
||||||
|
<constant name="no" type="int" value="0" />
|
||||||
|
<return value="yes" />
|
||||||
|
<return value="no" />
|
||||||
|
<new def="x" class="Ljava/io/IOException" />
|
||||||
|
<throw value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="readBytes"
|
||||||
|
descriptor="([BIILjava/io/FileDescriptor;)I">
|
||||||
|
<constant name="yes" type="int" value="1" />
|
||||||
|
<constant name="no" type="int" value="0" />
|
||||||
|
<return value="yes" />
|
||||||
|
<return value="no" />
|
||||||
|
<new def="x" class="Ljava/io/IOException" />
|
||||||
|
<throw value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="skip" descriptor="(J)J">
|
||||||
|
<constant name="yes" type="int" value="1" />
|
||||||
|
<constant name="no" type="int" value="0" />
|
||||||
|
<return value="yes" />
|
||||||
|
<return value="no" />
|
||||||
|
<new def="x" class="Ljava/io/IOException" />
|
||||||
|
<throw value="x" />
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
<class name="FileOutputStream">
|
||||||
|
<method name="close" descriptor="()V"></method>
|
||||||
|
<method name="open"
|
||||||
|
descriptor="(Ljava/lang/String;)V">
|
||||||
|
</method>
|
||||||
|
<method name="openAppend"
|
||||||
|
descriptor="(Ljava/lang/String;)V">
|
||||||
|
</method>
|
||||||
|
<method name="write" descriptor="(I)V"></method>
|
||||||
|
<method name="writeBytes" descriptor="([BII)V"></method>
|
||||||
|
</class>
|
||||||
|
<class name="ObjectOutputStream">
|
||||||
|
<method name="doublesToBytes" descriptor="([DI[BII)V"
|
||||||
|
static="true" />
|
||||||
|
<method name="floatsToBytes" descriptor="([FI[BII)V"
|
||||||
|
static="true" />
|
||||||
|
</class>
|
||||||
|
<class name="ObjectStreamClass">
|
||||||
|
<method name="hasStaticInitializer"
|
||||||
|
descriptor="(Ljava/lang/Class;)Z" static="true">
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
<class name="RandomAccessFile">
|
||||||
|
<method name="close" descriptor="()V"></method>
|
||||||
|
<method name="getFilePointer" descriptor="()J"></method>
|
||||||
|
<method name="length" descriptor="()J"></method>
|
||||||
|
<method name="open"
|
||||||
|
descriptor="(Ljava/lang/String;Z)V">
|
||||||
|
</method>
|
||||||
|
<method name="open"
|
||||||
|
descriptor="(Ljava/lang/String;I)V">
|
||||||
|
</method>
|
||||||
|
<method name="read" descriptor="()I"></method>
|
||||||
|
<method name="readBytes"
|
||||||
|
descriptor="([BIILjava/io/FileDescriptor;)I">
|
||||||
|
</method>
|
||||||
|
<method name="seek" descriptor="(J)V"></method>
|
||||||
|
<method name="write" descriptor="(I)V"></method>
|
||||||
|
<method name="writeBytes"
|
||||||
|
descriptor="([BIILjava/io/FileDescriptor;)V">
|
||||||
|
</method>
|
||||||
|
<method name="writeBytes" descriptor="([BII)V"></method>
|
||||||
|
</class>
|
||||||
|
</package>
|
||||||
|
|
||||||
|
<package name="java/lang">
|
||||||
|
<class name="Class">
|
||||||
|
<method name="forName"
|
||||||
|
descriptor="(Ljava/lang/String;)Ljava/lang/Class;"
|
||||||
|
static="true">
|
||||||
|
<new def="x" class="Ljava/lang/Class" />
|
||||||
|
<return value="x" />
|
||||||
|
<new def="y"
|
||||||
|
class="Ljava/lang/ClassNotFoundException" />
|
||||||
|
<throw value="y" />
|
||||||
|
<new def="z" class="Ljava/lang/ClassFormatError" />
|
||||||
|
<throw value="z" />
|
||||||
|
</method>
|
||||||
|
<method name="forName0"
|
||||||
|
descriptor="(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"
|
||||||
|
static="true">
|
||||||
|
<new def="x" class="Ljava/lang/Class" />
|
||||||
|
<return value="x" />
|
||||||
|
<new def="y"
|
||||||
|
class="Ljava/lang/ClassNotFoundException" />
|
||||||
|
<throw value="y" />
|
||||||
|
<new def="z" class="Ljava/lang/ClassFormatError" />
|
||||||
|
<throw value="z" />
|
||||||
|
</method>
|
||||||
|
<method name="forName1"
|
||||||
|
descriptor="(Ljava/lang/String;)Ljava/lang/Class;" static="true">
|
||||||
|
<new def="x" class="Ljava/lang/Class" />
|
||||||
|
<return value="x" />
|
||||||
|
<new def="y"
|
||||||
|
class="Ljava/lang/ClassNotFoundException" />
|
||||||
|
<throw value="y" />
|
||||||
|
<new def="z" class="Ljava/lang/ClassFormatError" />
|
||||||
|
<throw value="z" />
|
||||||
|
</method>
|
||||||
|
<method name="getClassLoader0"
|
||||||
|
descriptor="()Ljava/lang/ClassLoader;">
|
||||||
|
<new def="x" class="Ljava/lang/ClassLoader" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getComponentType"
|
||||||
|
descriptor="()Ljava/lang/Class;">
|
||||||
|
<new def="x" class="Ljava/lang/Class" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getConstructor0"
|
||||||
|
descriptor="([Ljava/lang/Class;I)Ljava/lang/reflect/Constructor;">
|
||||||
|
<new def="x" class="Ljava/lang/reflect/Constructor" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getField0"
|
||||||
|
descriptor="(Ljava/lang/String;I)Ljava/lang/reflect/Field;">
|
||||||
|
<new def="x" class="Ljava/lang/reflect/Field" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getInterfaces"
|
||||||
|
descriptor="()[Ljava/lang/Class;">
|
||||||
|
<constant name="size" type="int" value="1" />
|
||||||
|
<new def="x" class="[Ljava/lang/Class" size="size" />
|
||||||
|
<new def="y" class="Ljava/lang/Class" />
|
||||||
|
<aastore ref="x" value="y" index="0" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getMethod0"
|
||||||
|
descriptor="(Ljava/lang/String;[Ljava/lang/Class;I)Ljava/lang/reflect/Method;">
|
||||||
|
<new def="x" class="Ljava/lang/reflect/Method" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getMethods0"
|
||||||
|
descriptor="(I)[Ljava/lang/reflect/Method;">
|
||||||
|
<constant name="size" type="int" value="1" />
|
||||||
|
<new def="x" class="[Ljava/lang/reflect/Method"
|
||||||
|
size="size" />
|
||||||
|
<new def="y" class="Ljava/lang/reflect/Method" />
|
||||||
|
<aastore ref="x" value="y" index="0" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getModifiers" descriptor="()I"></method>
|
||||||
|
<method name="getName"
|
||||||
|
descriptor="()Ljava/lang/String;">
|
||||||
|
<new def="x" class="Ljava/lang/String" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getPrimitiveClass"
|
||||||
|
descriptor="(Ljava/lang/String;)Ljava/lang/Class;" static="true">
|
||||||
|
<new def="x" class="Ljava/lang/Class" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getSigners"
|
||||||
|
descriptor="()[Ljava/lang/Object;">
|
||||||
|
<constant name="size" type="int" value="1" />
|
||||||
|
<new def="x" class="[Ljava/lang/Object" size="size" />
|
||||||
|
<new def="y" class="Ljava/lang/Class" />
|
||||||
|
<aastore ref="x" value="y" index="0" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getSuperclass"
|
||||||
|
descriptor="()Ljava/lang/Class;">
|
||||||
|
<new def="x" class="Ljava/lang/Class" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getFields"
|
||||||
|
descriptor="()[Ljava/lang/reflect/Field;">
|
||||||
|
<constant name="size" type="int" value="1" />
|
||||||
|
<new def="x" class="[Ljava/lang/reflect/Field" size="size"/>
|
||||||
|
<new def="y" class="Ljava/lang/reflect/Field" />
|
||||||
|
<aastore ref="x" value="y" index="0" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getConstructors"
|
||||||
|
descriptor="()[Ljava/lang/reflect/Constructor;">
|
||||||
|
<constant name="size" type="int" value="1" />
|
||||||
|
<new def="x"
|
||||||
|
class="[Ljava/lang/reflect/Constructor" size="size"/>
|
||||||
|
<new def="y" class="Ljava/lang/reflect/Constructor" />
|
||||||
|
<aastore ref="x" value="y" index="0" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="isAssignableFrom"
|
||||||
|
descriptor="(Ljava/lang/Class;)Z">
|
||||||
|
</method>
|
||||||
|
<method name="isArray" descriptor="()Z"></method>
|
||||||
|
<method name="isInstance"
|
||||||
|
descriptor="(Ljava/lang/Object;)Z">
|
||||||
|
</method>
|
||||||
|
<method name="isInterface" descriptor="()Z"></method>
|
||||||
|
<method name="isPrimitive" descriptor="()Z"></method>
|
||||||
|
<method name="newInstance"
|
||||||
|
descriptor="()Ljava/lang/Object;" factory="true">
|
||||||
|
<new def="x" class="Lcom/ibm/wala/Malleable" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
<class name="ClassLoader" allocatable="true">
|
||||||
|
<method name="findBootstrapClass"
|
||||||
|
descriptor="(Ljava/lang/String;)Ljava/lang/Class;">
|
||||||
|
<new def="x" class="Ljava/lang/Class" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="findLoadedClass"
|
||||||
|
descriptor="(Ljava/lang/String;)Ljava/lang/Class;">
|
||||||
|
<new def="x" class="Ljava/lang/Class" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="getCallerClassLoader"
|
||||||
|
descriptor="()Ljava/lang/ClassLoader;" static="true">
|
||||||
|
<new def="x" class="Ljava/lang/ClassLoader" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
<class name="Double">
|
||||||
|
<method name="doubleToLongBits" descriptor="(D)J"
|
||||||
|
static="true">
|
||||||
|
</method>
|
||||||
|
<method name="longBitsToDouble" descriptor="(J)D"
|
||||||
|
static="true">
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
<class name="Float">
|
||||||
|
<method name="floatToIntBits" descriptor="(F)I"
|
||||||
|
static="true">
|
||||||
|
</method>
|
||||||
|
<method name="intBitsToFloat" descriptor="(I)F"
|
||||||
|
static="true">
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
<class name="Object">
|
||||||
|
<method name="clone"
|
||||||
|
descriptor="()Ljava/lang/Object;">
|
||||||
|
<return value="null" />
|
||||||
|
<!-- Note that propagation-style builders should intercept calls to clone, and this model is OK for RTA -->
|
||||||
|
</method>
|
||||||
|
<method name="getClass"
|
||||||
|
descriptor="()Ljava/lang/Class;">
|
||||||
|
<new def="x" class="Ljava/lang/Class" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="hashCode" descriptor="()I"></method>
|
||||||
|
<method name="notify" descriptor="()V"></method>
|
||||||
|
<method name="notifyAll" descriptor="()V"></method>
|
||||||
|
<method name="wait" descriptor="(J)V"></method>
|
||||||
|
</class>
|
||||||
|
<class name="Runtime">
|
||||||
|
<method name="freeMemory" descriptor="()J"></method>
|
||||||
|
<method name="gc" descriptor="()V"></method>
|
||||||
|
<method name="totalMemory" descriptor="()J"></method>
|
||||||
|
</class>
|
||||||
|
<class name="SecurityManager">
|
||||||
|
<method name="getClassContext"
|
||||||
|
descriptor="()[Ljava/lang/Class;">
|
||||||
|
<constant name="size" type="int" value="1" />
|
||||||
|
<new def="x" class="[Ljava/lang/Class" size="size"/>
|
||||||
|
<new def="y" class="Ljava/lang/Class" />
|
||||||
|
<aastore ref="x" value="y" index="0" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
<class name="StrictMath">
|
||||||
|
<method name="ceil" descriptor="(D)D" static="true"></method>
|
||||||
|
<method name="exp" descriptor="(D)D" static="true"></method>
|
||||||
|
<method name="floor" descriptor="(D)D" static="true"></method>
|
||||||
|
<method name="pow" descriptor="(DD)D" static="true"></method>
|
||||||
|
</class>
|
||||||
|
<class name="String">
|
||||||
|
<method name="intern"
|
||||||
|
descriptor="()Ljava/lang/String;">
|
||||||
|
<new def="x" class="Ljava/lang/String" />
|
||||||
|
<return value="x" />
|
||||||
|
<poison
|
||||||
|
reason="questionable model of java/lang/String/intern()"
|
||||||
|
level="mild" />
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
<class name="System">
|
||||||
|
<method name="arraycopy"
|
||||||
|
descriptor="(Ljava/lang/Object;ILjava/lang/Object;II)V"
|
||||||
|
static="true">
|
||||||
|
<call type="static" name="arraycopy"
|
||||||
|
class="Lcom/ibm/wala/model/java/lang/System"
|
||||||
|
descriptor="(Ljava/lang/Object;Ljava/lang/Object;)V" arg0="arg0"
|
||||||
|
arg1="arg2" />
|
||||||
|
<return />
|
||||||
|
</method>
|
||||||
|
<method name="currentTimeMillis" descriptor="()J"
|
||||||
|
static="true">
|
||||||
|
</method>
|
||||||
|
<method name="getCallerClass"
|
||||||
|
descriptor="()Ljava/lang/Class;" static="true">
|
||||||
|
<new def="x" class="Ljava/lang/Class" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="identityHashCode"
|
||||||
|
descriptor="(Ljava/lang/Object;)I" static="true">
|
||||||
|
</method>
|
||||||
|
<method name="initProperties"
|
||||||
|
descriptor="(Ljava/util/Properties;)Ljava/util/Properties;"
|
||||||
|
static="true">
|
||||||
|
<new def="dummy1" class="Ljava/lang/Object" />
|
||||||
|
<new def="dummy2" class="Ljava/lang/Object" />
|
||||||
|
<call type="virtual" name="put"
|
||||||
|
class="Ljava/util/Properties"
|
||||||
|
descriptor="(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"
|
||||||
|
arg0="arg0" arg1="dummy1" arg2="dummy2" def="ignore" />
|
||||||
|
<new def="x" class="Ljava/util/Properties" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="mapLibraryName"
|
||||||
|
descriptor="(Ljava/lang/String;)Ljava/lang/String;"
|
||||||
|
static="true">
|
||||||
|
<return value="arg0" />
|
||||||
|
</method>
|
||||||
|
<method name="setErr0"
|
||||||
|
descriptor="(Ljava/io/PrintStream;)V" static="true">
|
||||||
|
</method>
|
||||||
|
<method name="setIn0"
|
||||||
|
descriptor="(Ljava/io/InputStream;)V" static="true">
|
||||||
|
</method>
|
||||||
|
<method name="setOut0"
|
||||||
|
descriptor="(Ljava/io/PrintStream;)V" static="true">
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
<class name="Thread">
|
||||||
|
<method name="currentThread"
|
||||||
|
descriptor="()Ljava/lang/Thread;" static="true">
|
||||||
|
<new def="x" class="Ljava/lang/Thread" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="interrupt0" descriptor="()V"></method>
|
||||||
|
<method name="<init>" descriptor="()V">
|
||||||
|
<putfield class="Ljava/lang/Thread" field="runnable"
|
||||||
|
fieldType="Ljava/lang/Runnable" ref="arg0" value="arg0" />
|
||||||
|
<putfield class="Ljava/lang/Thread" field="target"
|
||||||
|
fieldType="Ljava/lang/Runnable" ref="arg0" value="arg0" />
|
||||||
|
</method>
|
||||||
|
<method name="<init>"
|
||||||
|
descriptor="(Ljava/lang/Runnable;)V">
|
||||||
|
<putfield class="Ljava/lang/Thread" field="runnable"
|
||||||
|
fieldType="Ljava/lang/Runnable" ref="arg0" value="arg1" />
|
||||||
|
<putfield class="Ljava/lang/Thread" field="target"
|
||||||
|
fieldType="Ljava/lang/Runnable" ref="arg0" value="arg0" />
|
||||||
|
</method>
|
||||||
|
<method name="isAlive" descriptor="()Z"></method>
|
||||||
|
<method name="resume0" descriptor="()V" />
|
||||||
|
<method name="sleep" descriptor="(J)V" static="true">
|
||||||
|
<new def="x"
|
||||||
|
class="Ljava/lang/InterruptedException" />
|
||||||
|
<throw value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="start" descriptor="()V">
|
||||||
|
<putfield class="Ljava/lang/Thread" field="runnable"
|
||||||
|
fieldType="Ljava/lang/Runnable" ref="arg0" value="arg0" />
|
||||||
|
<getfield class="Ljava/lang/Thread" field="runnable"
|
||||||
|
fieldType="Ljava/lang/Runnable" def="x" ref="arg0" />
|
||||||
|
<call type="interface" name="run"
|
||||||
|
class="Ljava/lang/Runnable" descriptor="()V" arg0="x" />
|
||||||
|
<putfield class="Ljava/lang/Thread" field="target"
|
||||||
|
fieldType="Ljava/lang/Runnable" ref="arg0" value="arg0" />
|
||||||
|
<getfield class="Ljava/lang/Thread" field="target"
|
||||||
|
fieldType="Ljava/lang/Runnable" def="y" ref="arg0" />
|
||||||
|
<call type="interface" name="run"
|
||||||
|
class="Ljava/lang/Runnable" descriptor="()V" arg0="y" />
|
||||||
|
</method>
|
||||||
|
<method name="stop0" descriptor="()V" />
|
||||||
|
<method name="yield" descriptor="()V" static="true" />
|
||||||
|
</class>
|
||||||
|
<class name="Throwable">
|
||||||
|
<method name="fillInStackTrace"
|
||||||
|
descriptor="()Ljava/lang/Throwable;">
|
||||||
|
<return value="arg0" />
|
||||||
|
</method>
|
||||||
|
<method name="getStackTraceElement"
|
||||||
|
descriptor="(I)Ljava/lang/StackTraceElement;">
|
||||||
|
<new def="x" class="Ljava/lang/StackTraceElement" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="printStackTrace0"
|
||||||
|
descriptor="(Ljava/lang/Object;)V" />
|
||||||
|
<method name="getStackTraceDepth" descriptor="()I" />
|
||||||
|
|
||||||
|
</class>
|
||||||
|
</package>
|
||||||
|
<package name="java/lang/reflect">
|
||||||
|
<class name="Array">
|
||||||
|
<method name="get"
|
||||||
|
descriptor="(Ljava/lang/Object;I)Ljava/lang/Object;" static="true"
|
||||||
|
factory="true">
|
||||||
|
<new def="x" class="Lcom/ibm/wala/Malleable" />
|
||||||
|
<return value="x" />
|
||||||
|
<poison
|
||||||
|
reason="bogus model of java/lang/reflect/Array/get"
|
||||||
|
level="severe" />
|
||||||
|
</method>
|
||||||
|
<method name="getByte"
|
||||||
|
descriptor="(Ljava/lang/Object;I)B" static="true">
|
||||||
|
</method>
|
||||||
|
<method name="getLength"
|
||||||
|
descriptor="(Ljava/lang/Object;)I" static="true">
|
||||||
|
</method>
|
||||||
|
<method name="multiNewArray"
|
||||||
|
descriptor="(Ljava/lang/Class;[I)Ljava/lang/Object;" static="true"
|
||||||
|
factory="true">
|
||||||
|
<new def="x" class="Lcom/ibm/wala/Malleable" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="newArray"
|
||||||
|
descriptor="(Ljava/lang/Class;I)Ljava/lang/Object;" static="true"
|
||||||
|
factory="true">
|
||||||
|
<new def="x" class="Lcom/ibm/wala/Malleable" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="newInstance"
|
||||||
|
descriptor="(Ljava/lang/Class;I)Ljava/lang/Object;" static="true"
|
||||||
|
factory="true">
|
||||||
|
<new def="x" class="Lcom/ibm/wala/Malleable" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="set"
|
||||||
|
descriptor="(Ljava/lang/Object;ILjava/lang/Object;)V"
|
||||||
|
static="true">
|
||||||
|
</method>
|
||||||
|
<method name="setByte"
|
||||||
|
descriptor="(Ljava/lang/Object;IB)V" static="true">
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
<class name="Field">
|
||||||
|
<method name="get"
|
||||||
|
descriptor="(Ljava/lang/Object;)Ljava/lang/Object;"
|
||||||
|
factory="true">
|
||||||
|
<new def="x" class="Lcom/ibm/wala/Malleable" />
|
||||||
|
<return value="x" />
|
||||||
|
<poison
|
||||||
|
reason="bogus model of java/lang/reflect/Field/get"
|
||||||
|
level="severe" />
|
||||||
|
</method>
|
||||||
|
<method name="getBoolean"
|
||||||
|
descriptor="(Ljava/lang/Object;)Z">
|
||||||
|
</method>
|
||||||
|
<method name="getByte"
|
||||||
|
descriptor="(Ljava/lang/Object;)B">
|
||||||
|
</method>
|
||||||
|
<method name="getChar"
|
||||||
|
descriptor="(Ljava/lang/Object;)C">
|
||||||
|
</method>
|
||||||
|
<method name="getDouble"
|
||||||
|
descriptor="(Ljava/lang/Object;)D">
|
||||||
|
</method>
|
||||||
|
<method name="getFloat"
|
||||||
|
descriptor="(Ljava/lang/Object;)F">
|
||||||
|
</method>
|
||||||
|
<method name="getInt"
|
||||||
|
descriptor="(Ljava/lang/Object;)I">
|
||||||
|
</method>
|
||||||
|
<method name="getLong"
|
||||||
|
descriptor="(Ljava/lang/Object;)J">
|
||||||
|
</method>
|
||||||
|
<method name="getShort"
|
||||||
|
descriptor="(Ljava/lang/Object;)S">
|
||||||
|
</method>
|
||||||
|
<method name="set"
|
||||||
|
descriptor="(Ljava/lang/Object;Ljava/lang/Object;)V">
|
||||||
|
</method>
|
||||||
|
<method name="setBoolean"
|
||||||
|
descriptor="(Ljava/lang/Object;Z)V">
|
||||||
|
</method>
|
||||||
|
<method name="setByte"
|
||||||
|
descriptor="(Ljava/lang/Object;B)V">
|
||||||
|
</method>
|
||||||
|
<method name="setChar"
|
||||||
|
descriptor="(Ljava/lang/Object;C)V">
|
||||||
|
</method>
|
||||||
|
<method name="setDouble"
|
||||||
|
descriptor="(Ljava/lang/Object;D)V">
|
||||||
|
</method>
|
||||||
|
<method name="setFloat"
|
||||||
|
descriptor="(Ljava/lang/Object;F)V">
|
||||||
|
</method>
|
||||||
|
<method name="setInt"
|
||||||
|
descriptor="(Ljava/lang/Object;I)V">
|
||||||
|
</method>
|
||||||
|
<method name="setLong"
|
||||||
|
descriptor="(Ljava/lang/Object;J)V">
|
||||||
|
</method>
|
||||||
|
<method name="setShort"
|
||||||
|
descriptor="(Ljava/lang/Object;S)V">
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
</package>
|
||||||
|
|
||||||
|
<package name="java/net">
|
||||||
|
<class name="PlainDatagramSocketImpl">
|
||||||
|
<method name="bind"
|
||||||
|
descriptor="(ILjava/net/InetAddress;)V">
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
<class name="PlainSocketImpl">
|
||||||
|
<method name="initProto" descriptor="()V" static="true" />
|
||||||
|
<method name="socketAvailable" descriptor="()I" />
|
||||||
|
<method name="socketBind"
|
||||||
|
descriptor="(Ljava/net/InetAddress;I)V" />
|
||||||
|
<method name="socketClose0" descriptor="(Z)V" />
|
||||||
|
<method name="socketConnect"
|
||||||
|
descriptor="(Ljava/net/InetAddress;II)V" />
|
||||||
|
<method name="socketCreate" descriptor="(Z)V" />
|
||||||
|
<method name="socketGetOption"
|
||||||
|
descriptor="(ILjava/lang/Object;)I" />
|
||||||
|
<method name="socketListen" descriptor="(I)V" />
|
||||||
|
<method name="socketSetOption"
|
||||||
|
descriptor="(IZLjava/lang/Object;)V" />
|
||||||
|
</class>
|
||||||
|
<class name="SocketInputStream">
|
||||||
|
<method name="init" descriptor="()V" static="true" />
|
||||||
|
<method name="socketRead0"
|
||||||
|
descriptor="(Ljava/io/FileDescriptor;[BIII)I" />
|
||||||
|
</class>
|
||||||
|
<class name="SocketOutputStream">
|
||||||
|
<method name="init" descriptor="()V" static="true" />
|
||||||
|
<method name="socketWrite0"
|
||||||
|
descriptor="(Ljava/io/FileDescriptor;[BII)V" />
|
||||||
|
</class>
|
||||||
|
</package>
|
||||||
|
|
||||||
|
<package name="java/security">
|
||||||
|
<class name="AccessControlContext">
|
||||||
|
<method name="getInheritedAccessControlContext"
|
||||||
|
descriptor="()Ljava/security/AccessControlContext;">
|
||||||
|
<new def="x" class="Ljava/lang/Object" />
|
||||||
|
<return value="x" />
|
||||||
|
<poison
|
||||||
|
reason="questionable model of java/security/AccessControlContext/getInheritedAccessControlContext"
|
||||||
|
level="moderate" />
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
<class name="AccessController">
|
||||||
|
<method name="doPrivileged"
|
||||||
|
descriptor="(Ljava/security/PrivilegedAction;)Ljava/lang/Object;"
|
||||||
|
static="true">
|
||||||
|
<call type="interface" name="run"
|
||||||
|
class="Ljava/security/PrivilegedAction"
|
||||||
|
descriptor="()Ljava/lang/Object;" def="x" arg0="arg0" />
|
||||||
|
<return value="x" />
|
||||||
|
<new def="y"
|
||||||
|
class="Ljava/security/PrivilegedActionException" />
|
||||||
|
<throw value="y" />
|
||||||
|
<poison
|
||||||
|
reason="incorrect model of java/security/AccessController/doPrivileged"
|
||||||
|
level="severe" />
|
||||||
|
</method>
|
||||||
|
<method name="doPrivileged"
|
||||||
|
descriptor="(Ljava/security/PrivilegedExceptionAction;)Ljava/lang/Object;"
|
||||||
|
static="true">
|
||||||
|
<call type="interface" name="run"
|
||||||
|
class="Ljava/security/PrivilegedExceptionAction"
|
||||||
|
descriptor="()Ljava/lang/Object;" def="x" arg0="arg0" />
|
||||||
|
<return value="x" />
|
||||||
|
<new def="y"
|
||||||
|
class="Ljava/security/PrivilegedActionException" />
|
||||||
|
<throw value="y" />
|
||||||
|
<poison
|
||||||
|
reason="incorrect model of java/security/AccessController/doPrivileged"
|
||||||
|
level="severe" />
|
||||||
|
</method>
|
||||||
|
<method name="doPrivileged"
|
||||||
|
descriptor="(Ljava/security/PrivilegedAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;"
|
||||||
|
static="true">
|
||||||
|
<call type="interface" name="run"
|
||||||
|
class="Ljava/security/PrivilegedAction"
|
||||||
|
descriptor="()Ljava/lang/Object;" def="x" arg0="arg0" />
|
||||||
|
<return value="x" />
|
||||||
|
<new def="y"
|
||||||
|
class="Ljava/security/PrivilegedActionException" />
|
||||||
|
<throw value="y" />
|
||||||
|
<poison
|
||||||
|
reason="incorrect model of java/security/AccessController/doPrivileged"
|
||||||
|
level="severe" />
|
||||||
|
</method>
|
||||||
|
<method name="doPrivileged"
|
||||||
|
descriptor="(Ljava/security/PrivilegedExceptionAction;Ljava/security/AccessControlContext;)Ljava/lang/Object;"
|
||||||
|
static="true">
|
||||||
|
<call type="interface" name="run"
|
||||||
|
class="Ljava/security/PrivilegedExceptionAction"
|
||||||
|
descriptor="()Ljava/lang/Object;" def="x" arg0="arg0" />
|
||||||
|
<return value="x" />
|
||||||
|
<new def="y"
|
||||||
|
class="Ljava/security/PrivilegedActionException" />
|
||||||
|
<throw value="y" />
|
||||||
|
<poison
|
||||||
|
reason="incorrect model of java/security/AccessController/doPrivileged"
|
||||||
|
level="severe" />
|
||||||
|
</method>
|
||||||
|
<method name="getStackAccessControlContext"
|
||||||
|
descriptor="()Ljava/security/AccessControlContext;"
|
||||||
|
static="true">
|
||||||
|
<new def="x"
|
||||||
|
class="Ljava/security/AccessControlContext" />
|
||||||
|
<return value="x" />
|
||||||
|
<poison
|
||||||
|
reason="questionable model of java/security/AccessController/getStackAccessControlContext"
|
||||||
|
level="moderate" />
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
</package>
|
||||||
|
|
||||||
|
<package name="java/util">
|
||||||
|
<class name="TimeZone">
|
||||||
|
<method name="getSystemTimeZoneID"
|
||||||
|
descriptor="(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"
|
||||||
|
static="true">
|
||||||
|
<new def="x" class="Ljava/lang/String" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
</class>
|
||||||
|
</package>
|
||||||
|
|
||||||
|
<package name="java/util/logging">
|
||||||
|
<class name="FileHandler">
|
||||||
|
<method name="isSetUID" descriptor="()Z" static="true" />
|
||||||
|
</class>
|
||||||
|
</package>
|
||||||
|
|
||||||
|
<package name="java/util/prefs">
|
||||||
|
<class name="FileSystemPreferences">
|
||||||
|
<method name="chmod" descriptor="(Ljava/lang/String;I)I"
|
||||||
|
static="true" />
|
||||||
|
<method name="lockFile0"
|
||||||
|
descriptor="(Ljava/lang/String;IZ)[I" static="true">
|
||||||
|
<constant name="size" type="int" value="1" />
|
||||||
|
<new def="x" class="[I" size="size"/>
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="unlockFile0" descriptor="(I)I"
|
||||||
|
static="true" />
|
||||||
|
</class>
|
||||||
|
</package>
|
||||||
|
|
||||||
|
<package name="sun/misc">
|
||||||
|
<class name="AtomicLongCSImpl">
|
||||||
|
<method name="attemptUpdate" descriptor="(JJ)Z" />
|
||||||
|
</class>
|
||||||
|
<class name="AtomicLong">
|
||||||
|
<method name="VMSupportsCS8" descriptor="()Z"
|
||||||
|
static="true" />
|
||||||
|
</class>
|
||||||
|
<class name="Signal">
|
||||||
|
<method name="handle0" descriptor="(IJ)J" static="true" />
|
||||||
|
<method name="findSignal"
|
||||||
|
descriptor="(Ljava/lang/String;)I" static="true" />
|
||||||
|
</class>
|
||||||
|
<class name="Unsafe" allocatable="true">
|
||||||
|
<method name="getUnsafe" descriptor="()Lsun/misc/Unsafe"
|
||||||
|
static="true">
|
||||||
|
<new def="x" class="Lsun/misc/Unsafe" />
|
||||||
|
<return value="x" />
|
||||||
|
</method>
|
||||||
|
<method name="allocateMemory" descriptor="(J)J" />
|
||||||
|
<method name="copyMemory" descriptor="(JJJ)V" />
|
||||||
|
<method name="freeMemory" descriptor="(J)V" />
|
||||||
|
<method name="objectFieldOffset"
|
||||||
|
descriptor="(Ljava/lang/reflect/Field;)J" />
|
||||||
|
<method name="getBoolean" descriptor="(J)Z" />
|
||||||
|
<method name="getByte" descriptor="(J)B" />
|
||||||
|
<method name="getChar" descriptor="(J)C" />
|
||||||
|
<method name="getDouble" descriptor="(J)D" />
|
||||||
|
<method name="getFloat" descriptor="(J)F" />
|
||||||
|
<method name="getInt" descriptor="(J)I" />
|
||||||
|
<method name="getLong" descriptor="(J)J" />
|
||||||
|
<method name="getShort" descriptor="(J)S" />
|
||||||
|
<method name="getBoolean"
|
||||||
|
descriptor="(Ljava/lang/Object;J)Z" />
|
||||||
|
<method name="getByte"
|
||||||
|
descriptor="(Ljava/lang/Object;J)B" />
|
||||||
|
<method name="getChar"
|
||||||
|
descriptor="(Ljava/lang/Object;J)C" />
|
||||||
|
<method name="getDouble"
|
||||||
|
descriptor="(Ljava/lang/Object;J)D" />
|
||||||
|
<method name="getFloat"
|
||||||
|
descriptor="(Ljava/lang/Object;J)F" />
|
||||||
|
<method name="getInt"
|
||||||
|
descriptor="(Ljava/lang/Object;J)I" />
|
||||||
|
<method name="getLong"
|
||||||
|
descriptor="(Ljava/lang/Object;J)J" />
|
||||||
|
<method name="getShort"
|
||||||
|
descriptor="(Ljava/lang/Object;J)S" />
|
||||||
|
<method name="putBoolean" descriptor="(JZ)V" />
|
||||||
|
<method name="putByte" descriptor="(JB)V" />
|
||||||
|
<method name="putChar" descriptor="(JC)V" />
|
||||||
|
<method name="putDouble" descriptor="(JD)V" />
|
||||||
|
<method name="putFloat" descriptor="(JF)V" />
|
||||||
|
<method name="putInt" descriptor="(JI)V" />
|
||||||
|
<method name="putLong" descriptor="(JJ)V" />
|
||||||
|
<method name="putShort" descriptor="(JS)V" />
|
||||||
|
<method name="registerNatives" descriptor="()V"
|
||||||
|
static="true" />
|
||||||
|
</class>
|
||||||
|
</package>
|
||||||
|
|
||||||
|
<package name="sun/nio/ch">
|
||||||
|
<class name="IOUtil">
|
||||||
|
<method name="initIDs" descriptor="()V" static="true" />
|
||||||
|
</class>
|
||||||
|
<class name="FileDispatcher">
|
||||||
|
<method name="init" descriptor="()V" static="true" />
|
||||||
|
</class>
|
||||||
|
<class name="FileChannelImpl">
|
||||||
|
<method name="lock0"
|
||||||
|
descriptor="(Ljava/io/FileDescriptor;ZJJZ)I" />
|
||||||
|
<method name="initIDs" descriptor="()J" static="true" />
|
||||||
|
</class>
|
||||||
|
</package>
|
||||||
|
|
||||||
|
</classloader>
|
||||||
|
</summary-spec>
|
|
@ -0,0 +1,52 @@
|
||||||
|
###############################################################################
|
||||||
|
# WALA property file
|
||||||
|
# This file defines the default settings for the core WALA Engine
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
################# Mandatory settings without default value ####################
|
||||||
|
|
||||||
|
#####
|
||||||
|
# Identify the directory where Java Runtime libraries are located.
|
||||||
|
# For instance, on a windows OS it's typically C:/Progra~1/Java/j2reYourVersion/lib
|
||||||
|
#
|
||||||
|
# N.B. This directory must contain a valid core.jar (or rt.jar for older VMs)
|
||||||
|
# On IBM 1.4.x SDKs, this means you need to specify Java14x/jre/lib and not
|
||||||
|
# Java14x/lib!
|
||||||
|
#
|
||||||
|
# Info: Location must be absolute.
|
||||||
|
#####
|
||||||
|
java_runtime_dir = Your location
|
||||||
|
|
||||||
|
################### Mandatory settings with default value ######################
|
||||||
|
|
||||||
|
##### Default output dir
|
||||||
|
# Identify directory where all generated files without absolute path will be located.
|
||||||
|
# Default value: results [Non absolute path are relative to WALA home location]
|
||||||
|
# Info: Can be absolute or relative.
|
||||||
|
#####
|
||||||
|
#output_dir = Your location
|
||||||
|
|
||||||
|
############################ Optional settings ################################
|
||||||
|
|
||||||
|
#####
|
||||||
|
# Identify the directory where J2EE standard libraries are located.
|
||||||
|
# Required only if you ask to analyze J2EE code.
|
||||||
|
# No default value.
|
||||||
|
# Info: Location must be absolute.
|
||||||
|
#####
|
||||||
|
#j2ee_runtime_dir = Your location
|
||||||
|
|
||||||
|
#####
|
||||||
|
# Identify the directory where Eclipse plugins are installed
|
||||||
|
# Required only if you ask to analyze Eclipse plugins.
|
||||||
|
# No default value.
|
||||||
|
# Info: Location must be absolute.
|
||||||
|
#####
|
||||||
|
#eclipse_plugins_dir = Your location
|
||||||
|
|
||||||
|
##### Report file
|
||||||
|
# Identify file name where to output WALA trace file.
|
||||||
|
# Default value: wala_report.txt [Non absolute path are relative to 'output.dir' variable value]
|
||||||
|
# Info: Can be absolute or relative.
|
||||||
|
#####
|
||||||
|
#WALA_report = Your file name
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.runtime_3.2.0.v20060603.jar[~org/eclipse/core/internal/preferences/legacy/*;~org/eclipse/core/internal/runtime/*;+org/eclipse/core/runtime/*;?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.osgi_3.2.0.v20060601.jar[+org/eclipse/osgi/event/*;+org/eclipse/osgi/framework/console/*;+org/eclipse/osgi/framework/eventmgr/*;+org/eclipse/osgi/framework/log/*;+org/eclipse/osgi/service/datalocation/*;+org/eclipse/osgi/service/debug/*;+org/eclipse/osgi/service/environment/*;+org/eclipse/osgi/service/localization/*;+org/eclipse/osgi/service/pluginconversion/*;+org/eclipse/osgi/service/resolver/*;+org/eclipse/osgi/service/runnable/*;+org/eclipse/osgi/service/urlconversion/*;+org/eclipse/osgi/storagemanager/*;+org/eclipse/osgi/util/*;+org/osgi/framework/*;+org/osgi/service/condpermadmin/*;+org/osgi/service/packageadmin/*;+org/osgi/service/permissionadmin/*;+org/osgi/service/startlevel/*;+org/osgi/service/url/*;+org/osgi/util/tracker/*;~org/eclipse/core/runtime/adaptor/*;~org/eclipse/core/runtime/internal/adaptor/*;~org/eclipse/core/runtime/internal/stats/*;~org/eclipse/osgi/baseadaptor/*;~org/eclipse/osgi/baseadaptor/bundlefile/*;~org/eclipse/osgi/baseadaptor/hooks/*;~org/eclipse/osgi/baseadaptor/loader/*;~org/eclipse/osgi/framework/adaptor/*;~org/eclipse/osgi/framework/debug/*;~org/eclipse/osgi/framework/internal/core/*;~org/eclipse/osgi/framework/internal/protocol/*;~org/eclipse/osgi/framework/internal/protocol/bundleentry/*;~org/eclipse/osgi/framework/internal/protocol/bundleresource/*;~org/eclipse/osgi/framework/internal/protocol/reference/*;~org/eclipse/osgi/framework/internal/reliablefile/*;~org/eclipse/osgi/framework/launcher/*;~org/eclipse/osgi/framework/util/*;~org/eclipse/osgi/internal/baseadaptor/*;~org/eclipse/osgi/internal/module/*;~org/eclipse/osgi/internal/profile/*;~org/eclipse/osgi/internal/resolver/*;~org/eclipse/osgi/internal/verifier/*;~org/eclipse/osgi/internal/provisional/verifier/*;?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.equinox.common_3.2.0.v20060603.jar[~org/eclipse/core/internal/runtime/*;~org/eclipse/core/internal/boot/*;+org/eclipse/core/runtime/*;?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.jobs_3.2.0.v20060603.jar[~org/eclipse/core/internal/jobs/*;+org/eclipse/core/runtime/jobs/*;?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.runtime.compatibility.registry_3.2.0.v20060603/runtime_registry_compatibility.jar[~org/eclipse/core/internal/registry/*;~org/eclipse/core/internal/registry/osgi/*;~org/eclipse/core/internal/registry/spi/*;+org/eclipse/core/runtime/*;+org/eclipse/core/runtime/dynamichelpers/*;+org/eclipse/core/runtime/spi/*;?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.runtime.compatibility.registry_3.2.0.v20060603[~org/eclipse/core/internal/registry/*;~org/eclipse/core/internal/registry/osgi/*;~org/eclipse/core/internal/registry/spi/*;+org/eclipse/core/runtime/*;+org/eclipse/core/runtime/dynamichelpers/*;+org/eclipse/core/runtime/spi/*;?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.equinox.registry_3.2.0.v20060601.jar[~org/eclipse/core/internal/registry/*;~org/eclipse/core/internal/registry/osgi/*;~org/eclipse/core/internal/registry/spi/*;+org/eclipse/core/runtime/*;+org/eclipse/core/runtime/dynamichelpers/*;+org/eclipse/core/runtime/spi/*;?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.apache.xerces_2.8.0.v200606131651/resolver.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.apache.xerces_2.8.0.v200606131651/xercesImpl.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.apache.xerces_2.8.0.v200606131651/xml-apis.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.equinox.preferences_3.2.0.v20060601.jar[~org/eclipse/core/internal/preferences/*;~org/eclipse/core/internal/preferences/exchange/*;+org/eclipse/core/runtime/preferences/*;+org/osgi/service/prefs/*;?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.runtime.compatibility.registry_3.2.0.v20060603/@dot[~org/eclipse/core/internal/registry/*;~org/eclipse/core/internal/registry/osgi/*;~org/eclipse/core/internal/registry/spi/*;+org/eclipse/core/runtime/*;+org/eclipse/core/runtime/dynamichelpers/*;+org/eclipse/core/runtime/spi/*;?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.contenttype_3.2.0.v20060603.jar[~org/eclipse/core/internal/content/*;+org/eclipse/core/runtime/content/*;?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.runtime.compatibility.auth_3.2.0.v20060601.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.emf.ecore_2.2.0.v200606271057.jar[+org/eclipse/emf/ecore/*;+org/eclipse/emf/ecore/impl/*;+org/eclipse/emf/ecore/plugin/*;+org/eclipse/emf/ecore/resource/*;+org/eclipse/emf/ecore/resource/impl/*;+org/eclipse/emf/ecore/util/*;+org/eclipse/emf/ecore/xml/namespace/*;+org/eclipse/emf/ecore/xml/namespace/impl/*;+org/eclipse/emf/ecore/xml/namespace/util/*;+org/eclipse/emf/ecore/xml/type/*;+org/eclipse/emf/ecore/xml/type/impl/*;+org/eclipse/emf/ecore/xml/type/internal/*;+org/eclipse/emf/ecore/xml/type/util/*;?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.emf.common_2.2.0.v200606271057.jar[+org/eclipse/emf/common/*;+org/eclipse/emf/common/archive/*;+org/eclipse/emf/common/command/*;+org/eclipse/emf/common/notify/*;+org/eclipse/emf/common/notify/impl/*;+org/eclipse/emf/common/util/*;?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.resources_3.2.0.v20060603.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.resources.compatibility_3.2.0.v20060603.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.resources.win32_3.2.0.v20060603.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.runtime.compatibility_3.1.100.v20060603.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.update.configurator_3.2.0.v20060605.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.ant.core_3.1.100.v20060531.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.variables_3.1.100.v20060605.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.expressions_3.2.0.v20060605-1400.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.filesystem_1.0.0.v20060603.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.core.filesystem.win32.x86_1.0.0.v20060603.jar[?**/*]
|
||||||
|
#ADAPTER#ACCESS#eclipse/plugins/org.eclipse.emf.ecore.xmi_2.2.0.v200606271057.jar[+org/eclipse/emf/ecore/xmi/*;+org/eclipse/emf/ecore/xmi/impl/*;+org/eclipse/emf/ecore/xmi/util/*;?**/*]
|
Binary file not shown.
|
@ -0,0 +1,6 @@
|
||||||
|
PLUGINNAME=core WALA analysis engine
|
||||||
|
VENDORNAME=IBMproviderName = www.example.org
|
||||||
|
pluginName = PatternSet Model
|
||||||
|
# ====================================================================
|
||||||
|
providerName = www.example.org
|
||||||
|
|
|
@ -0,0 +1,561 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.pointers;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.analysis.reflection.Malleable;
|
||||||
|
import com.ibm.wala.classLoader.IClass;
|
||||||
|
import com.ibm.wala.classLoader.IField;
|
||||||
|
import com.ibm.wala.ipa.callgraph.CallGraph;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.CompoundIterator;
|
||||||
|
import com.ibm.wala.util.IntFunction;
|
||||||
|
import com.ibm.wala.util.IntMapIterator;
|
||||||
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.graph.AbstractNumberedGraph;
|
||||||
|
import com.ibm.wala.util.graph.EdgeManager;
|
||||||
|
import com.ibm.wala.util.graph.NodeManager;
|
||||||
|
import com.ibm.wala.util.graph.NumberedGraph;
|
||||||
|
import com.ibm.wala.util.graph.NumberedNodeManager;
|
||||||
|
import com.ibm.wala.util.graph.impl.NumberedNodeIterator;
|
||||||
|
import com.ibm.wala.util.intset.BasicNonNegativeIntRelation;
|
||||||
|
import com.ibm.wala.util.intset.IBinaryNonNegativeIntRelation;
|
||||||
|
import com.ibm.wala.util.intset.IntSet;
|
||||||
|
import com.ibm.wala.util.intset.MutableMapping;
|
||||||
|
import com.ibm.wala.util.intset.MutableSparseIntSet;
|
||||||
|
import com.ibm.wala.util.intset.OrdinalSet;
|
||||||
|
import com.ibm.wala.util.intset.OrdinalSetMapping;
|
||||||
|
import com.ibm.wala.util.intset.SparseIntSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class BasicHeapGraph extends HeapGraph {
|
||||||
|
|
||||||
|
private final static boolean VERBOSE = true;
|
||||||
|
|
||||||
|
private final static int VERBOSE_INTERVAL = 10000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pointer analysis solution
|
||||||
|
*/
|
||||||
|
private final PointerAnalysis pointerAnalysis;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The backing graph
|
||||||
|
*/
|
||||||
|
private final NumberedGraph<Object> G;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* governing call graph
|
||||||
|
*/
|
||||||
|
private final CallGraph callGraph;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param P
|
||||||
|
* governing pointer analysis
|
||||||
|
*/
|
||||||
|
public BasicHeapGraph(final PointerAnalysis P, final CallGraph callGraph) {
|
||||||
|
super(P.getHeapModel());
|
||||||
|
this.pointerAnalysis = P;
|
||||||
|
this.callGraph = callGraph;
|
||||||
|
|
||||||
|
final OrdinalSetMapping<PointerKey> pointerKeys = getPointerKeys(P);
|
||||||
|
final NumberedNodeManager<Object> nodeMgr = new NumberedNodeManager<Object>() {
|
||||||
|
public Iterator<Object> iterateNodes() {
|
||||||
|
return new CompoundIterator<Object>(pointerKeys.iterator(), P.getInstanceKeyMapping().iterator());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfNodes() {
|
||||||
|
return pointerKeys.getMappingSize() + P.getInstanceKeyMapping().getMappingSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addNode(Object n) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeNode(Object n) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumber(Object N) {
|
||||||
|
if (N instanceof PointerKey) {
|
||||||
|
return pointerKeys.getMappedIndex((PointerKey) N);
|
||||||
|
} else {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
if (!(N instanceof InstanceKey)) {
|
||||||
|
Assertions.UNREACHABLE(N.getClass().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int inumber = P.getInstanceKeyMapping().getMappedIndex((InstanceKey) N);
|
||||||
|
return (inumber == -1) ? -1 : inumber + pointerKeys.getMappingSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getNode(int number) {
|
||||||
|
if (number >= pointerKeys.getMappingSize()) {
|
||||||
|
return P.getInstanceKeyMapping().getMappedObject(number - pointerKeys.getMappingSize());
|
||||||
|
} else {
|
||||||
|
return pointerKeys.getMappedObject(number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxNumber() {
|
||||||
|
return getNumberOfNodes() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean containsNode(Object n) {
|
||||||
|
return getNumber(n) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Object> iterateNodes(IntSet s) {
|
||||||
|
return new NumberedNodeIterator<Object>(s, this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final IBinaryNonNegativeIntRelation pred = computePredecessors(nodeMgr);
|
||||||
|
final IntFunction<Object> toNode = new IntFunction<Object>() {
|
||||||
|
public Object apply(int i) {
|
||||||
|
return nodeMgr.getNode(i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.G = new AbstractNumberedGraph<Object>() {
|
||||||
|
private final EdgeManager<Object> edgeMgr = new EdgeManager<Object>() {
|
||||||
|
public Iterator<Object> getPredNodes(Object N) {
|
||||||
|
int n = nodeMgr.getNumber(N);
|
||||||
|
IntSet p = pred.getRelated(n);
|
||||||
|
if (p == null) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
} else {
|
||||||
|
return new IntMapIterator<Object>(p.intIterator(), toNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPredNodeCount(Object N) {
|
||||||
|
int n = nodeMgr.getNumber(N);
|
||||||
|
return pred.getRelatedCount(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<? extends Object> getSuccNodes(Object N) {
|
||||||
|
int[] succ = computeSuccNodeNumbers(N, nodeMgr);
|
||||||
|
if (succ == null) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
SparseIntSet s = new MutableSparseIntSet(succ);
|
||||||
|
return new IntMapIterator<Object>(s.intIterator(), toNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSuccNodeCount(Object N) {
|
||||||
|
int[] succ = computeSuccNodeNumbers(N, nodeMgr);
|
||||||
|
return succ == null ? 0 : succ.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEdge(Object src, Object dst) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeEdge(Object src, Object dst) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllIncidentEdges(Object node) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeIncomingEdges(Object node) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeOutgoingEdges(Object node) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasEdge(Object src, Object dst) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected NodeManager<Object> getNodeManager() {
|
||||||
|
return nodeMgr;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EdgeManager<Object> getEdgeManager() {
|
||||||
|
return edgeMgr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private OrdinalSetMapping<PointerKey> getPointerKeys(PointerAnalysis pointerAnalysis) {
|
||||||
|
MutableMapping<PointerKey> result = new MutableMapping<PointerKey>();
|
||||||
|
|
||||||
|
for (Iterator it = pointerAnalysis.getPointerKeys().iterator(); it.hasNext();) {
|
||||||
|
PointerKey p = (PointerKey) it.next();
|
||||||
|
result.add(p);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] computeSuccNodeNumbers(Object N, NumberedNodeManager<Object> nodeManager) {
|
||||||
|
if (N instanceof PointerKey) {
|
||||||
|
PointerKey P = (PointerKey) N;
|
||||||
|
OrdinalSet S = pointerAnalysis.getPointsToSet(P);
|
||||||
|
int[] result = new int[S.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (Iterator it = S.iterator(); it.hasNext();) {
|
||||||
|
result[i] = nodeManager.getNumber(it.next());
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} else if (N instanceof InstanceKey) {
|
||||||
|
InstanceKey I = (InstanceKey) N;
|
||||||
|
TypeReference T = I.getConcreteType().getReference();
|
||||||
|
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
if (T == null) {
|
||||||
|
Assertions._assert(T != null, "null concrete type from " + I.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (T.isArrayType()) {
|
||||||
|
PointerKey p = getHeapModel().getPointerKeyForArrayContents(I);
|
||||||
|
if (p == null || !nodeManager.containsNode(p)) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return new int[] { nodeManager.getNumber(p) };
|
||||||
|
}
|
||||||
|
} else if (!Malleable.isMalleable(T)) {
|
||||||
|
IClass klass = getHeapModel().getClassHierarchy().lookupClass(T);
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
if (klass == null) {
|
||||||
|
Assertions._assert(klass != null, "null klass for type " + T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MutableSparseIntSet result = new MutableSparseIntSet();
|
||||||
|
try {
|
||||||
|
for (Iterator<IField> it = klass.getAllInstanceFields().iterator(); it.hasNext();) {
|
||||||
|
IField f = it.next();
|
||||||
|
if (!f.getFieldReference().getFieldType().isPrimitiveType()) {
|
||||||
|
PointerKey p = getHeapModel().getPointerKeyForInstanceField(I, f);
|
||||||
|
if (p != null && nodeManager.containsNode(p)) {
|
||||||
|
result.add(nodeManager.getNumber(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ClassHierarchyException e) {
|
||||||
|
// uh oh. skip it for now.
|
||||||
|
}
|
||||||
|
return result.toIntArray();
|
||||||
|
} else {
|
||||||
|
Assertions._assert(Malleable.isMalleable(T));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Assertions.UNREACHABLE("Unexpected type: " + N.getClass());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return R, y \in R(x,y) if the node y is a predecessor of node x
|
||||||
|
*/
|
||||||
|
private IBinaryNonNegativeIntRelation computePredecessors(NumberedNodeManager<Object> nodeManager) {
|
||||||
|
BasicNonNegativeIntRelation R = new BasicNonNegativeIntRelation(new byte[] { BasicNonNegativeIntRelation.SIMPLE },
|
||||||
|
BasicNonNegativeIntRelation.SIMPLE);
|
||||||
|
|
||||||
|
// we split the following loops to improve temporal locality,
|
||||||
|
// particularly for locals
|
||||||
|
computePredecessorsForNonLocals(nodeManager, R);
|
||||||
|
computePredecessorsForLocals(nodeManager, R);
|
||||||
|
|
||||||
|
return R;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void computePredecessorsForNonLocals(NumberedNodeManager<Object> nodeManager, BasicNonNegativeIntRelation R) {
|
||||||
|
// Note: we run this loop backwards on purpose, to avoid lots of resizing of
|
||||||
|
// bitvectors
|
||||||
|
// in the backing relation. i.e., we will add the biggest bits first.
|
||||||
|
// pretty damn tricky.
|
||||||
|
for (int i = nodeManager.getMaxNumber(); i >= 0; i--) {
|
||||||
|
if (VERBOSE) {
|
||||||
|
if (i % VERBOSE_INTERVAL == 0) {
|
||||||
|
System.err.println("Building HeapGraph: " + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object n = nodeManager.getNode(i);
|
||||||
|
if (!(n instanceof LocalPointerKey)) {
|
||||||
|
int[] succ = computeSuccNodeNumbers(n, nodeManager);
|
||||||
|
if (succ != null) {
|
||||||
|
for (int z = 0; z < succ.length; z++) {
|
||||||
|
int j = succ[z];
|
||||||
|
R.add(j, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* traverse locals in order, first by node, then by value number: attempt to
|
||||||
|
* improve locality
|
||||||
|
*/
|
||||||
|
private void computePredecessorsForLocals(NumberedNodeManager<Object> nodeManager, BasicNonNegativeIntRelation R) {
|
||||||
|
|
||||||
|
ArrayList<LocalPointerKey> list = new ArrayList<LocalPointerKey>();
|
||||||
|
for (Iterator it = nodeManager.iterateNodes(); it.hasNext();) {
|
||||||
|
Object n = it.next();
|
||||||
|
if (n instanceof LocalPointerKey) {
|
||||||
|
list.add((LocalPointerKey) n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object[] arr = list.toArray();
|
||||||
|
Arrays.sort(arr, new LocalPointerComparator());
|
||||||
|
|
||||||
|
for (int i = 0; i < arr.length; i++) {
|
||||||
|
if (VERBOSE) {
|
||||||
|
if (i % VERBOSE_INTERVAL == 0) {
|
||||||
|
System.err.println("Building HeapGraph: " + i + " of " + arr.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LocalPointerKey n = (LocalPointerKey) arr[i];
|
||||||
|
int num = nodeManager.getNumber(n);
|
||||||
|
int[] succ = computeSuccNodeNumbers(n, nodeManager);
|
||||||
|
if (succ != null) {
|
||||||
|
for (int z = 0; z < succ.length; z++) {
|
||||||
|
int j = succ[z];
|
||||||
|
R.add(j, num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sorts local pointers by node, then value number
|
||||||
|
*/
|
||||||
|
private final class LocalPointerComparator implements Comparator<Object> {
|
||||||
|
public int compare(Object arg1, Object arg2) {
|
||||||
|
LocalPointerKey o1 = (LocalPointerKey)arg1;
|
||||||
|
LocalPointerKey o2 = (LocalPointerKey)arg2;
|
||||||
|
if (o1.getNode().equals(o2.getNode())) {
|
||||||
|
return o1.getValueNumber() - o2.getValueNumber();
|
||||||
|
} else {
|
||||||
|
return callGraph.getNumber(o1.getNode()) - callGraph.getNumber(o2.getNode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NumberedNodeManager#getNumber(com.ibm.wala.util.graph.Node)
|
||||||
|
*/
|
||||||
|
public int getNumber(Object N) {
|
||||||
|
return G.getNumber(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NumberedNodeManager#getNode(int)
|
||||||
|
*/
|
||||||
|
public Object getNode(int number) {
|
||||||
|
return G.getNode(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NumberedNodeManager#getMaxNumber()
|
||||||
|
*/
|
||||||
|
public int getMaxNumber() {
|
||||||
|
return G.getMaxNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NodeManager#iterateNodes()
|
||||||
|
*/
|
||||||
|
public Iterator<? extends Object> iterateNodes() {
|
||||||
|
return G.iterateNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes()
|
||||||
|
*/
|
||||||
|
public int getNumberOfNodes() {
|
||||||
|
return G.getNumberOfNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(com.ibm.wala.util.graph.Node)
|
||||||
|
*/
|
||||||
|
public Iterator<? extends Object> getPredNodes(Object N) {
|
||||||
|
return G.getPredNodes(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(com.ibm.wala.util.graph.Node)
|
||||||
|
*/
|
||||||
|
public int getPredNodeCount(Object N) {
|
||||||
|
return G.getPredNodeCount(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(com.ibm.wala.util.graph.Node)
|
||||||
|
*/
|
||||||
|
public Iterator<? extends Object> getSuccNodes(Object N) {
|
||||||
|
return G.getSuccNodes(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(com.ibm.wala.util.graph.Node)
|
||||||
|
*/
|
||||||
|
public int getSuccNodeCount(Object N) {
|
||||||
|
return G.getSuccNodeCount(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NodeManager#addNode(com.ibm.wala.util.graph.Node)
|
||||||
|
*/
|
||||||
|
public void addNode(Object n) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NodeManager#remove(com.ibm.wala.util.graph.Node)
|
||||||
|
*/
|
||||||
|
public void removeNode(Object n) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void addEdge(Object from, Object to) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeEdge(Object from, Object to) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean hasEdge(Object from, Object to) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllIncidentEdges(Object node) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NodeManager#containsNode(com.ibm.wala.util.graph.Node)
|
||||||
|
*/
|
||||||
|
public boolean containsNode(Object N) {
|
||||||
|
return G.containsNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer result = new StringBuffer();
|
||||||
|
result.append("Nodes:\n");
|
||||||
|
for (int i = 0; i < getMaxNumber(); i++) {
|
||||||
|
Object node = getNode(i);
|
||||||
|
if (node != null) {
|
||||||
|
result.append(i).append(" ").append(node).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.append("Edges:\n");
|
||||||
|
for (int i = 0; i < getMaxNumber(); i++) {
|
||||||
|
Object node = getNode(i);
|
||||||
|
if (node != null) {
|
||||||
|
result.append(i).append(" -> ");
|
||||||
|
for (Iterator it = getSuccNodes(node); it.hasNext();) {
|
||||||
|
Object s = it.next();
|
||||||
|
result.append(getNumber(s)).append(" ");
|
||||||
|
}
|
||||||
|
result.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void removeIncomingEdges(Object node) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*/
|
||||||
|
public void removeOutgoingEdges(Object node) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntSet getSuccNodeNumbers(Object node) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntSet getPredNodeNumbers(Object node) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.pointers;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.HeapModel;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
||||||
|
import com.ibm.wala.util.collections.Filter;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.graph.NumberedGraph;
|
||||||
|
import com.ibm.wala.util.graph.impl.NumberedNodeIterator;
|
||||||
|
import com.ibm.wala.util.graph.traverse.DFS;
|
||||||
|
import com.ibm.wala.util.intset.IntSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Graph view of a pointer analysis solution.
|
||||||
|
*
|
||||||
|
* Nodes in the Graph are PointerKeys and InstanceKeys.
|
||||||
|
*
|
||||||
|
* There is an edge from a PointerKey P to an InstanceKey I iff the PointerAnalysis
|
||||||
|
* indicates that P may point to I.
|
||||||
|
*
|
||||||
|
* There is an edge from an InstanceKey I to a PointerKey P iff
|
||||||
|
* - P represents a field of an object instance modelled by I, or
|
||||||
|
* - P represents the array contents of array instance I.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class HeapGraph implements NumberedGraph<Object> {
|
||||||
|
|
||||||
|
private final HeapModel hm;
|
||||||
|
|
||||||
|
protected HeapGraph(HeapModel hm) {
|
||||||
|
this.hm = hm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.util.graph.NumberedNodeManager#iterateNodes(com.ibm.wala.util.intset.IntSet)
|
||||||
|
*/
|
||||||
|
public Iterator<Object> iterateNodes(IntSet s) {
|
||||||
|
return new NumberedNodeIterator<Object>(s,this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Object> getReachableInstances(Set<Object> roots) {
|
||||||
|
Filter f = new Filter() {
|
||||||
|
public boolean accepts(Object o) {
|
||||||
|
return (o instanceof InstanceKey);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return DFS.getReachableNodes(this, roots, f);
|
||||||
|
}
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.util.graph.Graph#removeNode(com.ibm.wala.util.graph.Node)
|
||||||
|
*/
|
||||||
|
public void removeNodeAndEdges(Object N) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the heap model used in this pointer analysis.
|
||||||
|
*/
|
||||||
|
public HeapModel getHeapModel() {
|
||||||
|
return hm;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<HTML>
|
||||||
|
<BODY>
|
||||||
|
This package defines utilities to help navigate pointer analysis results.
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.reflection;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.CallSiteReference;
|
||||||
|
import com.ibm.wala.ssa.IR;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInvokeInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction.Visitor;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A mapping from CallSiteReference to SSA InvokeInstruction.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class CallSiteMap {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* f: CallSiteReference -> InvokeInstruction
|
||||||
|
*/
|
||||||
|
private final Map<CallSiteReference, SSAInvokeInstruction> map = HashMapFactory.make();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ir
|
||||||
|
*/
|
||||||
|
public CallSiteMap(final IR ir) {
|
||||||
|
Visitor v = new Visitor() {
|
||||||
|
public void visitInvoke(SSAInvokeInstruction instruction) {
|
||||||
|
CallSiteReference site = instruction.getCallSite();
|
||||||
|
map.put(site, instruction);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
SSAInstruction[] instructions = ir.getInstructions();
|
||||||
|
for (int i = 0; i < instructions.length; i++) {
|
||||||
|
if (instructions[i] != null) {
|
||||||
|
instructions[i].visit(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param site
|
||||||
|
* @return the InvokeInstruction corresponding to the call site.
|
||||||
|
*/
|
||||||
|
public SSAInvokeInstruction getInstructionForSite(CallSiteReference site) {
|
||||||
|
SSAInvokeInstruction result = map.get(site);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.analysis.reflection;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.CallSiteReference;
|
||||||
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||||
|
import com.ibm.wala.ipa.callgraph.Context;
|
||||||
|
import com.ibm.wala.ipa.callgraph.ContextItem;
|
||||||
|
import com.ibm.wala.ipa.callgraph.ContextKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A context which is a <CGNode, CallSiteReference> pair
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class CallerSiteContext implements Context {
|
||||||
|
private final CGNode caller;
|
||||||
|
private final CallSiteReference site;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param caller
|
||||||
|
* @param site
|
||||||
|
*/
|
||||||
|
public CallerSiteContext(CGNode caller, CallSiteReference site) {
|
||||||
|
this.caller = caller;
|
||||||
|
this.site = site;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.Context#get(com.ibm.wala.ipa.callgraph.ContextKey)
|
||||||
|
*/
|
||||||
|
public ContextItem get(ContextKey name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "[CallerSiteContext: " + caller + "," + site.getProgramCounter() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public CGNode getCaller() {
|
||||||
|
return caller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CallSiteReference getSite() {
|
||||||
|
return site;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object arg0) {
|
||||||
|
if (getClass().equals(arg0.getClass())) {
|
||||||
|
CallerSiteContext other = (CallerSiteContext) arg0;
|
||||||
|
return caller.equals(other.caller) && (site.equals(other.site));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return site.hashCode() + 839 * caller.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,362 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.reflection;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.ibm.wala.cfg.ControlFlowGraph;
|
||||||
|
import com.ibm.wala.cfg.InducedCFG;
|
||||||
|
import com.ibm.wala.classLoader.CallSiteReference;
|
||||||
|
import com.ibm.wala.classLoader.CodeScanner;
|
||||||
|
import com.ibm.wala.classLoader.IClass;
|
||||||
|
import com.ibm.wala.classLoader.IField;
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.classLoader.NewSiteReference;
|
||||||
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||||
|
import com.ibm.wala.ipa.callgraph.Context;
|
||||||
|
import com.ibm.wala.ipa.callgraph.ContextUtil;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||||
|
import com.ibm.wala.ipa.summaries.SyntheticIR;
|
||||||
|
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
||||||
|
import com.ibm.wala.ssa.DefUse;
|
||||||
|
import com.ibm.wala.ssa.IR;
|
||||||
|
import com.ibm.wala.ssa.SSAArrayLengthInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAGetInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInvokeInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSANewInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAOptions;
|
||||||
|
import com.ibm.wala.ssa.SSAPutInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAReturnInstruction;
|
||||||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
|
import com.ibm.wala.types.Descriptor;
|
||||||
|
import com.ibm.wala.types.MethodReference;
|
||||||
|
import com.ibm.wala.types.TypeName;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.Atom;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A context interpreter for java.lang.Object.clone
|
||||||
|
*
|
||||||
|
* TODO: The current implementation does not model CloneNotSupportedExceptions
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class CloneInterpreter implements SSAContextInterpreter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comment for <code>cloneAtom</code>
|
||||||
|
*/
|
||||||
|
public final static Atom cloneAtom = Atom.findOrCreateUnicodeAtom("clone");
|
||||||
|
|
||||||
|
private final static Descriptor cloneDesc = Descriptor.findOrCreateUTF8("()Ljava/lang/Object;");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comment for <code>CLONE</code>
|
||||||
|
*/
|
||||||
|
public final static MethodReference CLONE = MethodReference.findOrCreate(TypeReference.JavaLangObject, cloneAtom, cloneDesc);
|
||||||
|
|
||||||
|
private final static TypeReference SYNTHETIC_SYSTEM = TypeReference.findOrCreate(ClassLoaderReference.Primordial, TypeName
|
||||||
|
.string2TypeName("Lcom/ibm/wala/model/java/lang/System"));
|
||||||
|
|
||||||
|
private final static Atom arraycopyAtom = Atom.findOrCreateUnicodeAtom("arraycopy");
|
||||||
|
|
||||||
|
private final static Descriptor arraycopyDesc = Descriptor.findOrCreateUTF8("(Ljava/lang/Object;Ljava/lang/Object;)V");
|
||||||
|
|
||||||
|
private final static MethodReference SYNTHETIC_ARRAYCOPY = MethodReference.findOrCreate(SYNTHETIC_SYSTEM, arraycopyAtom,
|
||||||
|
arraycopyDesc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the type is an array, the program counter of the synthesized call to
|
||||||
|
* arraycopy. Doesn't really matter what it is.
|
||||||
|
*/
|
||||||
|
private final static int ARRAYCOPY_PC = 3;
|
||||||
|
|
||||||
|
private final static CallSiteReference ARRAYCOPY_SITE = CallSiteReference.make(ARRAYCOPY_PC, SYNTHETIC_ARRAYCOPY,
|
||||||
|
IInvokeInstruction.Dispatch.STATIC);
|
||||||
|
|
||||||
|
private final static int NEW_PC = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping from TypeReference -> IR TODO: Soft references?
|
||||||
|
*/
|
||||||
|
private Map<TypeReference, IR> IRCache = HashMapFactory.make();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.cfa.CFAContextInterpreter#getIR(com.ibm.wala.classLoader.IMethod,
|
||||||
|
* com.ibm.detox.ipa.callgraph.Context,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public IR getIR(CGNode node, WarningSet warnings) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(understands(node));
|
||||||
|
}
|
||||||
|
IClass cls = ContextUtil.getConcreteClassFromContext(node.getContext());
|
||||||
|
IR result = IRCache.get(cls.getReference());
|
||||||
|
if (result == null) {
|
||||||
|
result = makeIR(node.getMethod(), node.getContext(), cls, warnings);
|
||||||
|
IRCache.put(cls.getReference(), result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.cfa.CFAContextInterpreter#getNumberOfStatements(com.ibm.wala.classLoader.IMethod,
|
||||||
|
* com.ibm.detox.ipa.callgraph.Context,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public int getNumberOfStatements(CGNode node, WarningSet warnings) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(understands(node));
|
||||||
|
}
|
||||||
|
return getIR(node, warnings).getInstructions().length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.rta.RTAContextInterpreter#understands(com.ibm.wala.classLoader.IMethod,
|
||||||
|
* com.ibm.detox.ipa.callgraph.Context)
|
||||||
|
*/
|
||||||
|
public boolean understands(CGNode node) {
|
||||||
|
return (node.getMethod().getReference().equals(CLONE) && ContextUtil.getConcreteClassFromContext(node.getContext()) != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.rta.RTAContextInterpreter#getAllocatedTypes(com.ibm.wala.classLoader.IMethod,
|
||||||
|
* com.ibm.detox.ipa.callgraph.Context,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public Iterator<NewSiteReference> iterateNewSites(CGNode node, WarningSet warnings) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(understands(node));
|
||||||
|
}
|
||||||
|
IClass cls = ContextUtil.getConcreteClassFromContext(node.getContext());
|
||||||
|
return new NonNullSingletonIterator<NewSiteReference>(NewSiteReference.make(NEW_PC, cls.getReference()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.rta.RTAContextInterpreter#getCallSites(com.ibm.wala.classLoader.IMethod,
|
||||||
|
* com.ibm.detox.ipa.callgraph.Context,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public Iterator<CallSiteReference> iterateCallSites(CGNode node, WarningSet warnings) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(understands(node));
|
||||||
|
}
|
||||||
|
return new NonNullSingletonIterator<CallSiteReference>(ARRAYCOPY_SITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an array of statements that encode the behavior of the clone method
|
||||||
|
* for a given type.
|
||||||
|
*/
|
||||||
|
private SSAInstruction[] makeStatements(IClass klass) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(klass != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<SSAInstruction> statements = new ArrayList<SSAInstruction>();
|
||||||
|
// value number 1 is "this".
|
||||||
|
int nextLocal = 2;
|
||||||
|
|
||||||
|
int retValue = nextLocal++;
|
||||||
|
// value number of the result of the clone()
|
||||||
|
NewSiteReference ref = NewSiteReference.make(NEW_PC, klass.getReference());
|
||||||
|
SSANewInstruction N = null;
|
||||||
|
if (klass.isArrayClass()) {
|
||||||
|
int length = nextLocal++;
|
||||||
|
statements.add(new SSAArrayLengthInstruction(length, 1));
|
||||||
|
int[] sizes = new int[klass.getReference().getDimensionality()];
|
||||||
|
Arrays.fill(sizes,length);
|
||||||
|
N = new SSANewInstruction(retValue, ref, sizes);
|
||||||
|
} else {
|
||||||
|
N = new SSANewInstruction(retValue, ref);
|
||||||
|
}
|
||||||
|
statements.add(N);
|
||||||
|
|
||||||
|
int exceptionValue = nextLocal++;
|
||||||
|
|
||||||
|
if (klass.getReference().isArrayType()) {
|
||||||
|
// generate a synthetic arraycopy from this (v.n. 1) to the clone
|
||||||
|
int[] params = new int[2];
|
||||||
|
params[0] = 1;
|
||||||
|
params[1] = retValue;
|
||||||
|
SSAInvokeInstruction S = new SSAInvokeInstruction(params, exceptionValue, ARRAYCOPY_SITE);
|
||||||
|
statements.add(S);
|
||||||
|
} else {
|
||||||
|
// copy the fields over, one by one.
|
||||||
|
// TODO:
|
||||||
|
IClass k = klass;
|
||||||
|
while (k != null) {
|
||||||
|
for (Iterator<IField> it = klass.getDeclaredInstanceFields().iterator(); it.hasNext();) {
|
||||||
|
IField f = it.next();
|
||||||
|
int tempValue = nextLocal++;
|
||||||
|
SSAGetInstruction G = new SSAGetInstruction(tempValue, 1, f.getFieldReference());
|
||||||
|
statements.add(G);
|
||||||
|
SSAPutInstruction P = new SSAPutInstruction(retValue, tempValue, f.getFieldReference());
|
||||||
|
statements.add(P);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
k = k.getSuperclass();
|
||||||
|
} catch (ClassHierarchyException e) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
SSAReturnInstruction R = new SSAReturnInstruction(retValue, false);
|
||||||
|
statements.add(R);
|
||||||
|
|
||||||
|
SSAInstruction[] result = new SSAInstruction[statements.size()];
|
||||||
|
Iterator<SSAInstruction> it = statements.iterator();
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
result[i] = it.next();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an IR that encodes the behavior of the clone method for a given
|
||||||
|
* type.
|
||||||
|
*/
|
||||||
|
private IR makeIR(IMethod method, Context context, IClass klass, WarningSet warnings) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(klass != null);
|
||||||
|
}
|
||||||
|
SSAInstruction instrs[] = makeStatements(klass);
|
||||||
|
return new SyntheticIR(method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), null,
|
||||||
|
warnings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.cfa.CFAContextInterpreter#recordFactoryType(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
|
* com.ibm.wala.classLoader.IClass)
|
||||||
|
*/
|
||||||
|
public boolean recordFactoryType(CGNode node, IClass klass) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.rta.RTAContextInterpreter#setWarnings(com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public void setWarnings(WarningSet newWarnings) {
|
||||||
|
// this object is not bound to a WarningSet
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.xta.XTAContextInterpreter#iterateFieldsRead(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public Iterator iterateFieldsRead(CGNode node, WarningSet warnings) {
|
||||||
|
SSAInstruction[] statements = getIR(node, warnings).getInstructions();
|
||||||
|
return CodeScanner.getFieldsRead(statements).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.xta.XTAContextInterpreter#iterateFieldsWritten(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public Iterator iterateFieldsWritten(CGNode node, WarningSet warnings) {
|
||||||
|
SSAInstruction[] statements = getIR(node, warnings).getInstructions();
|
||||||
|
return CodeScanner.getFieldsWritten(statements).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.xta.XTAContextInterpreter#getCaughtExceptions(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public Set getCaughtExceptions(CGNode node, WarningSet warnings) {
|
||||||
|
SSAInstruction[] statements = getIR(node, warnings).getInstructions();
|
||||||
|
return CodeScanner.getCaughtExceptions(statements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.xta.XTAContextInterpreter#hasObjectArrayLoad(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public boolean hasObjectArrayLoad(CGNode node, WarningSet warnings) {
|
||||||
|
SSAInstruction[] statements = getIR(node, warnings).getInstructions();
|
||||||
|
return CodeScanner.hasObjectArrayLoad(statements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.xta.XTAContextInterpreter#hasObjectArrayStore(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public boolean hasObjectArrayStore(CGNode node, WarningSet warnings) {
|
||||||
|
SSAInstruction[] statements = getIR(node, warnings).getInstructions();
|
||||||
|
return CodeScanner.hasObjectArrayStore(statements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.xta.XTAContextInterpreter#iterateCastTypes(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public Iterator iterateCastTypes(CGNode node, WarningSet warnings) {
|
||||||
|
SSAInstruction[] statements = getIR(node, warnings).getInstructions();
|
||||||
|
return CodeScanner.iterateCastTypes(statements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.cfg.CFGProvider#getCFG(com.ibm.wala.ipa.callgraph.CGNode)
|
||||||
|
*/
|
||||||
|
public ControlFlowGraph getCFG(CGNode N, WarningSet warnings) {
|
||||||
|
return getIR(N, warnings).getControlFlowGraph();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getDU(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public DefUse getDU(CGNode node, WarningSet warnings) {
|
||||||
|
return new DefUse(getIR(node, warnings));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,809 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.reflection;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.ibm.wala.analysis.typeInference.ConeType;
|
||||||
|
import com.ibm.wala.analysis.typeInference.PointType;
|
||||||
|
import com.ibm.wala.analysis.typeInference.SetType;
|
||||||
|
import com.ibm.wala.analysis.typeInference.TypeAbstraction;
|
||||||
|
import com.ibm.wala.cfg.ControlFlowGraph;
|
||||||
|
import com.ibm.wala.cfg.InducedCFG;
|
||||||
|
import com.ibm.wala.classLoader.CallSiteReference;
|
||||||
|
import com.ibm.wala.classLoader.CodeScanner;
|
||||||
|
import com.ibm.wala.classLoader.IClass;
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.classLoader.NewSiteReference;
|
||||||
|
import com.ibm.wala.classLoader.SyntheticMethod;
|
||||||
|
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
||||||
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||||
|
import com.ibm.wala.ipa.callgraph.Context;
|
||||||
|
import com.ibm.wala.ipa.callgraph.ReflectionSpecification;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.ipa.summaries.ReflectionSummary;
|
||||||
|
import com.ibm.wala.ipa.summaries.SummarizedMethod;
|
||||||
|
import com.ibm.wala.ipa.summaries.SyntheticIR;
|
||||||
|
import com.ibm.wala.ipa.summaries.XMLReflectionReader;
|
||||||
|
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
||||||
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||||
|
import com.ibm.wala.ssa.ConstantValue;
|
||||||
|
import com.ibm.wala.ssa.DefUse;
|
||||||
|
import com.ibm.wala.ssa.IR;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInvokeInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSANewInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAOptions;
|
||||||
|
import com.ibm.wala.ssa.SSAReturnInstruction;
|
||||||
|
import com.ibm.wala.types.MethodReference;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.collections.HashSetFactory;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.debug.Trace;
|
||||||
|
import com.ibm.wala.util.warnings.Warning;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Logic to interpret "factory" methods in context.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class FactoryBypassInterpreter implements RTAContextInterpreter, SSAContextInterpreter {
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
|
private final static int CONE_BOUND = 10;
|
||||||
|
|
||||||
|
private int indexLocal = 100;
|
||||||
|
|
||||||
|
private final Map<TypeReference, Integer> typeIndexMap = HashMapFactory.make();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Map from CallerSiteContext -> Set <TypeReference>represents the types a
|
||||||
|
* factory method might create in a particular context
|
||||||
|
*/
|
||||||
|
private final Map<Context, Set<TypeReference>> map = HashMapFactory.make();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cache of synthetic method implementations, indexed by Context
|
||||||
|
*/
|
||||||
|
private final Map<Context, SpecializedFactoryMethod> syntheticMethodCache = HashMapFactory.make();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Governing analysis options
|
||||||
|
*/
|
||||||
|
private final AnalysisOptions options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Governing class hierarchy
|
||||||
|
*/
|
||||||
|
private final ClassHierarchy cha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep track of analysis warnings
|
||||||
|
*/
|
||||||
|
private WarningSet warnings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User-defined reflection specification
|
||||||
|
*/
|
||||||
|
private final ReflectionSpecification userSpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param options
|
||||||
|
* governing analysis options
|
||||||
|
* @param cha
|
||||||
|
* governing class hierarchy
|
||||||
|
* @param userSpec
|
||||||
|
* @param warnings
|
||||||
|
* object to track analysis warnings
|
||||||
|
*/
|
||||||
|
public FactoryBypassInterpreter(AnalysisOptions options, ClassHierarchy cha, ReflectionSpecification userSpec, WarningSet warnings) {
|
||||||
|
this.options = options;
|
||||||
|
this.cha = cha;
|
||||||
|
this.warnings = warnings;
|
||||||
|
this.userSpec = userSpec;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getLocalForType(TypeReference T) {
|
||||||
|
Integer I = typeIndexMap.get(T);
|
||||||
|
if (I == null) {
|
||||||
|
typeIndexMap.put(T, I = new Integer(indexLocal += 2));
|
||||||
|
}
|
||||||
|
return I.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getExceptionsForType(TypeReference T) {
|
||||||
|
return getLocalForType(T) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getCallSiteForType(TypeReference T) {
|
||||||
|
return getLocalForType(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getNewSiteForType(TypeReference T) {
|
||||||
|
return getLocalForType(T) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.cfa.CFAContextInterpreter#getIR(com.ibm.wala.classLoader.IMethod,
|
||||||
|
* com.ibm.wala.ipa.callgraph.Context,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public IR getIR(CGNode node, WarningSet warnings) {
|
||||||
|
SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node);
|
||||||
|
return options.getSSACache().findOrCreateIR(m, node.getContext(), cha, options.getSSAOptions(), warnings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set getTypesForContext(Context context) {
|
||||||
|
// first try user spec
|
||||||
|
XMLReflectionReader spec = (XMLReflectionReader) userSpec;
|
||||||
|
if (spec != null && context instanceof CallerSiteContext) {
|
||||||
|
CallerSiteContext site = (CallerSiteContext) context;
|
||||||
|
MethodReference m = site.getCaller().getMethod().getReference();
|
||||||
|
ReflectionSummary summary = spec.getSummary(m);
|
||||||
|
if (summary != null) {
|
||||||
|
Set types = summary.getTypesForProgramLocation(site.getSite().getProgramCounter());
|
||||||
|
if (types != null) {
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Set types = map.get(context);
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.cfa.CFAContextInterpreter#getNumberOfStatements(com.ibm.wala.classLoader.IMethod,
|
||||||
|
* com.ibm.wala.ipa.callgraph.Context,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public int getNumberOfStatements(CGNode node, WarningSet warnings) {
|
||||||
|
SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node);
|
||||||
|
return m.allInstructions.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.rta.RTAContextInterpreter#understands(com.ibm.wala.classLoader.IMethod,
|
||||||
|
* com.ibm.wala.ipa.callgraph.Context)
|
||||||
|
*/
|
||||||
|
public boolean understands(CGNode node) {
|
||||||
|
return getTypesForContext(node.getContext()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.rta.RTAContextInterpreter#getNewSites(com.ibm.wala.classLoader.IMethod,
|
||||||
|
* com.ibm.wala.ipa.callgraph.Context,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public Iterator<NewSiteReference> iterateNewSites(CGNode node, WarningSet warnings) {
|
||||||
|
SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node);
|
||||||
|
HashSet<NewSiteReference> result = HashSetFactory.make(5);
|
||||||
|
for (Iterator<SSAInstruction> it = m.getAllocationStatements().iterator(); it.hasNext();) {
|
||||||
|
SSANewInstruction s = (SSANewInstruction) it.next();
|
||||||
|
result.add(s.getNewSite());
|
||||||
|
}
|
||||||
|
return result.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<SSAInstruction> getInvokeStatements(CGNode node) {
|
||||||
|
SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node);
|
||||||
|
return m.getInvokeStatements().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.rta.RTAContextInterpreter#getCallSites(com.ibm.wala.classLoader.IMethod,
|
||||||
|
* com.ibm.detox.ipa.callgraph.Context,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public Iterator<CallSiteReference> iterateCallSites(CGNode node, WarningSet warnings) {
|
||||||
|
final Iterator<SSAInstruction> I = getInvokeStatements(node);
|
||||||
|
return new Iterator<CallSiteReference>() {
|
||||||
|
public boolean hasNext() {
|
||||||
|
return I.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CallSiteReference next() {
|
||||||
|
SSAInvokeInstruction s = (SSAInvokeInstruction) I.next();
|
||||||
|
return s.getCallSite();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected class SpecializedFactoryMethod extends SyntheticMethod {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of synthetic allocation statements we model for this specialized
|
||||||
|
* instance
|
||||||
|
*/
|
||||||
|
private ArrayList<SSAInstruction> allocations = new ArrayList<SSAInstruction>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of synthetic invoke instructions we model for this specialized
|
||||||
|
* instance.
|
||||||
|
*/
|
||||||
|
private ArrayList<SSAInstruction> calls = new ArrayList<SSAInstruction>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of all instructions
|
||||||
|
*/
|
||||||
|
private ArrayList<SSAInstruction> allInstructions = new ArrayList<SSAInstruction>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The method being modelled
|
||||||
|
*/
|
||||||
|
private final IMethod method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context being modelled
|
||||||
|
*/
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* next free local value number;
|
||||||
|
*/
|
||||||
|
private int nextLocal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* value number for integer constant 1
|
||||||
|
*/
|
||||||
|
private int valueNumberForConstantOne = -1;
|
||||||
|
|
||||||
|
private void initValueNumberForConstantOne() {
|
||||||
|
if (valueNumberForConstantOne == -1) {
|
||||||
|
valueNumberForConstantOne = nextLocal++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final HashSet<TypeReference> types = HashSetFactory.make(5);
|
||||||
|
|
||||||
|
private SpecializedFactoryMethod(final SummarizedMethod m, Context context, final Set S) {
|
||||||
|
super(m, m.getDeclaringClass(), m.isStatic(), true);
|
||||||
|
|
||||||
|
this.context = context;
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Create SpecializedFactoryMethod " + m + S);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.method = m;
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(S != null);
|
||||||
|
Assertions._assert(m.getDeclaringClass() != null, "null declaring class for " + m);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add original statements from the method summary
|
||||||
|
nextLocal = addOriginalStatements(m);
|
||||||
|
|
||||||
|
for (Iterator it = S.iterator(); it.hasNext();) {
|
||||||
|
TypeReference type = (TypeReference) it.next();
|
||||||
|
TypeAbstraction T = typeRef2TypeAbstraction(type);
|
||||||
|
addStatementsForTypeAbstraction(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addStatementsForTypeAbstraction(TypeAbstraction T) {
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("adding " + T + " to " + method);
|
||||||
|
}
|
||||||
|
T = interceptType(T);
|
||||||
|
if (T == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((T instanceof PointType) || (T instanceof ConeType)) {
|
||||||
|
TypeReference ref = T.getType().getReference();
|
||||||
|
NewSiteReference site = NewSiteReference.make(0, ref);
|
||||||
|
IClass klass = options.getClassTargetSelector().getAllocatedTarget(null, site);
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Selected allocated target: " + klass + " for " + T);
|
||||||
|
}
|
||||||
|
if (T instanceof PointType) {
|
||||||
|
addStatementsForConcreteType(ref);
|
||||||
|
} else if (T instanceof ConeType) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Cone clause for " + T);
|
||||||
|
}
|
||||||
|
if (((ConeType) T).isInterface()) {
|
||||||
|
Set implementors = cha.getImplementors(ref);
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Implementors for " + T + " " + implementors);
|
||||||
|
}
|
||||||
|
if (implementors.isEmpty()) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Found no implementors of type " + T);
|
||||||
|
}
|
||||||
|
warnings.add(NoSubtypesWarning.create(T));
|
||||||
|
}
|
||||||
|
if (implementors.size() > CONE_BOUND) {
|
||||||
|
warnings.add(ManySubtypesWarning.create(T, implementors.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
addStatementsForSetOfTypes(implementors.iterator());
|
||||||
|
} else {
|
||||||
|
Collection subclasses = cha.computeSubClasses(ref);
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Subclasses for " + T + " " + subclasses);
|
||||||
|
}
|
||||||
|
if (subclasses.isEmpty()) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Found no subclasses of type " + T);
|
||||||
|
}
|
||||||
|
warnings.add(NoSubtypesWarning.create(T));
|
||||||
|
}
|
||||||
|
if (subclasses.size() > CONE_BOUND) {
|
||||||
|
warnings.add(ManySubtypesWarning.create(T, subclasses.size()));
|
||||||
|
}
|
||||||
|
addStatementsForSetOfTypes(subclasses.iterator());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Assertions.UNREACHABLE("Unexpected type " + T.getClass());
|
||||||
|
}
|
||||||
|
} else if (T instanceof SetType) {
|
||||||
|
addStatementsForSetOfTypes(((SetType) T).iteratePoints());
|
||||||
|
} else {
|
||||||
|
Assertions.UNREACHABLE("Unexpected type " + T.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeAbstraction interceptType(TypeAbstraction T) {
|
||||||
|
TypeReference type = T.getType().getReference();
|
||||||
|
if (type.equals(TypeReference.JavaIoSerializable)) {
|
||||||
|
warnings.add(IgnoreSerializableWarning.create());
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up a method summary which allocates and returns an instance of
|
||||||
|
* concrete type T.
|
||||||
|
*
|
||||||
|
* @param T
|
||||||
|
*/
|
||||||
|
private void addStatementsForConcreteType(final TypeReference T) {
|
||||||
|
if (types.contains(T))
|
||||||
|
return;
|
||||||
|
types.add(T);
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("addStatementsForConcreteType: " + T);
|
||||||
|
}
|
||||||
|
NewSiteReference ref = NewSiteReference.make(getNewSiteForType(T), T);
|
||||||
|
int alloc = getLocalForType(T);
|
||||||
|
SSANewInstruction a = new SSANewInstruction(alloc, ref);
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Added allocation: " + a);
|
||||||
|
}
|
||||||
|
|
||||||
|
allocations.add(a);
|
||||||
|
allInstructions.add(a);
|
||||||
|
SSAReturnInstruction r = new SSAReturnInstruction(alloc, false);
|
||||||
|
allInstructions.add(r);
|
||||||
|
if (T.isArrayType()) {
|
||||||
|
MethodReference init = MethodReference.findOrCreate(T, MethodReference.initAtom, MethodReference.defaultInitDesc);
|
||||||
|
CallSiteReference site = CallSiteReference.make(getCallSiteForType(T), init, IInvokeInstruction.Dispatch.SPECIAL);
|
||||||
|
int[] params = new int[1];
|
||||||
|
params[0] = alloc;
|
||||||
|
int exc = getExceptionsForType(T);
|
||||||
|
SSAInvokeInstruction s = new SSAInvokeInstruction(params, exc, site);
|
||||||
|
calls.add(s);
|
||||||
|
allInstructions.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int addOriginalStatements(SummarizedMethod m) {
|
||||||
|
SSAInstruction[] original = m.getStatements(options.getSSAOptions(), warnings);
|
||||||
|
// local value number 1 is "this", so the next free value number is 2
|
||||||
|
int nextLocal = 2;
|
||||||
|
for (int i = 0; i < original.length; i++) {
|
||||||
|
SSAInstruction s = original[i];
|
||||||
|
allInstructions.add(s);
|
||||||
|
if (s instanceof SSAInvokeInstruction) {
|
||||||
|
calls.add(s);
|
||||||
|
}
|
||||||
|
if (s instanceof SSANewInstruction) {
|
||||||
|
allocations.add(s);
|
||||||
|
}
|
||||||
|
for (int j = 0; j < s.getNumberOfDefs(); j++) {
|
||||||
|
int def = s.getDef(j);
|
||||||
|
if (def >= nextLocal) {
|
||||||
|
nextLocal = def + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int j = 0; j < s.getNumberOfUses(); j++) {
|
||||||
|
int use = s.getUse(j);
|
||||||
|
if (use >= nextLocal) {
|
||||||
|
nextLocal = use + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nextLocal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addStatementsForSetOfTypes(Iterator it) {
|
||||||
|
|
||||||
|
if (!it.hasNext()) { // Uh. No types. Hope the caller reported a warning.
|
||||||
|
SSAReturnInstruction r = new SSAReturnInstruction(nextLocal, false);
|
||||||
|
allInstructions.add(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; it.hasNext();) {
|
||||||
|
IClass klass = (IClass) it.next();
|
||||||
|
TypeReference T = klass.getReference();
|
||||||
|
if (klass.isAbstract() || types.contains(T)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
types.add(T);
|
||||||
|
int i = getLocalForType(T);
|
||||||
|
NewSiteReference ref = NewSiteReference.make(getNewSiteForType(T), T);
|
||||||
|
SSANewInstruction a = null;
|
||||||
|
if (T.isArrayType()) {
|
||||||
|
int[] sizes = new int[T.getDimensionality()];
|
||||||
|
initValueNumberForConstantOne();
|
||||||
|
Arrays.fill(sizes, valueNumberForConstantOne);
|
||||||
|
a = new SSANewInstruction(i, ref, sizes);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
a = new SSANewInstruction(i, ref);
|
||||||
|
}
|
||||||
|
allocations.add(a);
|
||||||
|
allInstructions.add(a);
|
||||||
|
SSAReturnInstruction r = new SSAReturnInstruction(i, false);
|
||||||
|
allInstructions.add(r);
|
||||||
|
MethodReference init = MethodReference.findOrCreate(T, MethodReference.initAtom, MethodReference.defaultInitDesc);
|
||||||
|
CallSiteReference site = CallSiteReference.make(getCallSiteForType(T), init, IInvokeInstruction.Dispatch.SPECIAL);
|
||||||
|
int[] params = new int[1];
|
||||||
|
params[0] = i;
|
||||||
|
SSAInvokeInstruction s = new SSAInvokeInstruction(params, getExceptionsForType(T), site);
|
||||||
|
calls.add(s);
|
||||||
|
allInstructions.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SSAInstruction> getAllocationStatements() {
|
||||||
|
return allocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SSAInstruction> getInvokeStatements() {
|
||||||
|
return calls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two specialized methods can be different, even if they represent the same
|
||||||
|
* source method. So, revert to object identity for testing equality. TODO:
|
||||||
|
* this is non-optimal; could try to re-use specialized methods that have
|
||||||
|
* the same context.
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return this == obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() { // TODO: change this to avoid non-determinism!
|
||||||
|
return System.identityHashCode(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return super.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SSAInstruction[] getStatements(WarningSet warnings) {
|
||||||
|
SSAInstruction[] result = new SSAInstruction[allInstructions.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (Iterator<SSAInstruction> it = allInstructions.iterator(); it.hasNext();) {
|
||||||
|
result[i++] = it.next();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IClass getDeclaringClass() {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
if (method.getDeclaringClass() == null) {
|
||||||
|
Assertions._assert(method.getDeclaringClass() != null, "null declaring class for original method " + method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return method.getDeclaringClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfParameters() {
|
||||||
|
return method.getNumberOfParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeReference getParameterType(int i) {
|
||||||
|
return method.getParameterType(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getIR(com.ibm.wala.util.WarningSet)
|
||||||
|
*/
|
||||||
|
public IR makeIR(SSAOptions options, WarningSet warnings) {
|
||||||
|
SSAInstruction[] instrs = getStatements(warnings);
|
||||||
|
Map<Integer, ConstantValue> constants = null;
|
||||||
|
if (valueNumberForConstantOne > -1) {
|
||||||
|
constants = HashMapFactory.make(1);
|
||||||
|
constants.put(new Integer(valueNumberForConstantOne), new ConstantValue(new Integer(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SyntheticIR(this, context, new InducedCFG(instrs, this, context), instrs, options, constants, warnings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean recordType(Context context, TypeReference type) {
|
||||||
|
Set<TypeReference> types = map.get(context);
|
||||||
|
if (types == null) {
|
||||||
|
types = HashSetFactory.make(2);
|
||||||
|
map.put(context, types);
|
||||||
|
}
|
||||||
|
if (types.contains(type)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
types.add(type);
|
||||||
|
// update any extant synthetic method
|
||||||
|
SpecializedFactoryMethod m = syntheticMethodCache.get(context);
|
||||||
|
if (m != null) {
|
||||||
|
TypeAbstraction T = typeRef2TypeAbstraction(type);
|
||||||
|
m.addStatementsForTypeAbstraction(T);
|
||||||
|
options.getSSACache().invalidate(m, context);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param type
|
||||||
|
* @return a TypeAbstraction object representing this type. We just use
|
||||||
|
* ConeTypes by default, since we don't propagate information allowing
|
||||||
|
* us to distinguish between points and cones yet.
|
||||||
|
*/
|
||||||
|
private TypeAbstraction typeRef2TypeAbstraction(TypeReference type) {
|
||||||
|
IClass klass = cha.lookupClass(type);
|
||||||
|
if (klass != null) {
|
||||||
|
return new ConeType(klass, cha);
|
||||||
|
// if (klass.isAbstract() || klass.isInterface()) {
|
||||||
|
// return new ConeType(klass, cha);
|
||||||
|
// } else {
|
||||||
|
// return new PointType(klass, cha);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
Assertions.UNREACHABLE(type.toString());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#recordFactoryType(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
|
* com.ibm.wala.classLoader.IClass)
|
||||||
|
*/
|
||||||
|
public boolean recordFactoryType(CGNode node, IClass klass) {
|
||||||
|
return recordType(node.getContext(), klass.getReference());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#setWarnings(com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public void setWarnings(WarningSet newWarnings) {
|
||||||
|
this.warnings = newWarnings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#iterateFieldsRead(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public Iterator iterateFieldsRead(CGNode node, WarningSet warnings) {
|
||||||
|
SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node);
|
||||||
|
try {
|
||||||
|
return CodeScanner.iterateFieldsRead(m, warnings);
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#iterateFieldsWritten(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public Iterator iterateFieldsWritten(CGNode node, WarningSet warnings) {
|
||||||
|
SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node);
|
||||||
|
try {
|
||||||
|
return CodeScanner.iterateFieldsWritten(m, warnings);
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SpecializedFactoryMethod findOrCreateSpecializedFactoryMethod(CGNode node) {
|
||||||
|
SpecializedFactoryMethod m = syntheticMethodCache.get(node.getContext());
|
||||||
|
if (m == null) {
|
||||||
|
Set types = getTypesForContext(node.getContext());
|
||||||
|
m = new SpecializedFactoryMethod((SummarizedMethod) node.getMethod(), node.getContext(), types);
|
||||||
|
syntheticMethodCache.put(node.getContext(), m);
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set getCaughtExceptions(CGNode node, WarningSet warnings) {
|
||||||
|
SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node);
|
||||||
|
try {
|
||||||
|
return CodeScanner.getCaughtExceptions(m, warnings);
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasObjectArrayLoad(CGNode node, WarningSet warnings) {
|
||||||
|
SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node);
|
||||||
|
try {
|
||||||
|
return CodeScanner.hasObjectArrayLoad(m, warnings);
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasObjectArrayStore(CGNode node, WarningSet warnings) {
|
||||||
|
SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node);
|
||||||
|
try {
|
||||||
|
return CodeScanner.hasObjectArrayStore(m, warnings);
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator iterateCastTypes(CGNode node, WarningSet warnings) {
|
||||||
|
SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node);
|
||||||
|
try {
|
||||||
|
return CodeScanner.iterateCastTypes(m, warnings);
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.cfg.CFGProvider#getCFG(com.ibm.wala.ipa.callgraph.CGNode)
|
||||||
|
*/
|
||||||
|
public ControlFlowGraph getCFG(CGNode N, WarningSet warnings) {
|
||||||
|
return getIR(N, warnings).getControlFlowGraph();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
* A waring when we expect excessive pollution from a factory method
|
||||||
|
*/
|
||||||
|
private static class ManySubtypesWarning extends Warning {
|
||||||
|
|
||||||
|
final int nImplementors;
|
||||||
|
|
||||||
|
final TypeAbstraction T;
|
||||||
|
|
||||||
|
ManySubtypesWarning(TypeAbstraction T, int nImplementors) {
|
||||||
|
super(Warning.MODERATE);
|
||||||
|
this.T = T;
|
||||||
|
this.nImplementors = nImplementors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsg() {
|
||||||
|
return getClass().toString() + " : " + T + " " + nImplementors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ManySubtypesWarning create(TypeAbstraction T, int n) {
|
||||||
|
return new ManySubtypesWarning(T, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
* A warning when we fail to find subtypes for a factory method
|
||||||
|
*/
|
||||||
|
private static class NoSubtypesWarning extends Warning {
|
||||||
|
|
||||||
|
final TypeAbstraction T;
|
||||||
|
|
||||||
|
NoSubtypesWarning(TypeAbstraction T) {
|
||||||
|
super(Warning.SEVERE);
|
||||||
|
this.T = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsg() {
|
||||||
|
return getClass().toString() + " : " + T;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NoSubtypesWarning create(TypeAbstraction T) {
|
||||||
|
return new NoSubtypesWarning(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
* A waring when we find flow of a factory allocation to a cast to
|
||||||
|
* serializable
|
||||||
|
*/
|
||||||
|
private static class IgnoreSerializableWarning extends Warning {
|
||||||
|
|
||||||
|
private static IgnoreSerializableWarning instance = new IgnoreSerializableWarning();
|
||||||
|
|
||||||
|
public String getMsg() {
|
||||||
|
return getClass().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IgnoreSerializableWarning create() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getDU(com.ibm.wala.ipa.callgraph.CGNode,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public DefUse getDU(CGNode node, WarningSet warnings) {
|
||||||
|
SpecializedFactoryMethod m = findOrCreateSpecializedFactoryMethod(node);
|
||||||
|
return options.getSSACache().findOrCreateDU(m, node.getContext(), cha, options.getSSAOptions(), warnings);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.reflection;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.CallSiteReference;
|
||||||
|
import com.ibm.wala.classLoader.IClass;
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.classLoader.SyntheticMethod;
|
||||||
|
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.MethodTargetSelector;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For synthetic methods marked as "Factories", we analyze in a context defined by the caller.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class FactoryContextSelector implements ContextSelector {
|
||||||
|
|
||||||
|
|
||||||
|
private final MethodTargetSelector methodTargetSelector;
|
||||||
|
|
||||||
|
private final ClassHierarchy cha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param methodTargetSelector
|
||||||
|
*/
|
||||||
|
public FactoryContextSelector(ClassHierarchy cha, MethodTargetSelector methodTargetSelector) {
|
||||||
|
this.cha = cha;
|
||||||
|
this.methodTargetSelector = methodTargetSelector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.ContextSelector#getCalleeTarget(com.ibm.wala.ipa.callgraph.CGNode, com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod)
|
||||||
|
*/
|
||||||
|
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey receiver) {
|
||||||
|
if (callee.isSynthetic()) {
|
||||||
|
SyntheticMethod s = (SyntheticMethod) callee;
|
||||||
|
if (s.isFactoryMethod()) {
|
||||||
|
return new CallerSiteContext(caller, site);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.ContextSelector#mayUnderstand(com.ibm.wala.ipa.callgraph.CGNode, com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod, com.ibm.wala.ipa.callgraph.propagation.InstanceKey)
|
||||||
|
*/
|
||||||
|
public boolean mayUnderstand(CGNode caller, CallSiteReference site, IMethod targetMethod, InstanceKey instance) {
|
||||||
|
if (targetMethod.isSynthetic()) {
|
||||||
|
SyntheticMethod s = (SyntheticMethod) targetMethod;
|
||||||
|
if (s.isFactoryMethod()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.ContextSelector#getBoundOnNumberOfTargets(com.ibm.wala.ipa.callgraph.CGNode, com.ibm.wala.classLoader.CallSiteReference, com.ibm.wala.classLoader.IMethod)
|
||||||
|
*/
|
||||||
|
public int getBoundOnNumberOfTargets(CGNode caller, CallSiteReference site, IMethod callee) {
|
||||||
|
if (callee.isSynthetic()) {
|
||||||
|
SyntheticMethod s = (SyntheticMethod) callee;
|
||||||
|
if (s.isFactoryMethod()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.rta.RTAContextInterpreter#setWarnings(com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public void setWarnings(WarningSet newWarnings) {
|
||||||
|
// this object is not bound to a WarningSet
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.ContextSelector#contextIsIrrelevant(com.ibm.wala.classLoader.CallSiteReference)
|
||||||
|
*/
|
||||||
|
public boolean contextIsIrrelevant(CGNode node, CallSiteReference site) {
|
||||||
|
boolean result = methodTargetSelector.mightReturnSyntheticMethod(node,site);
|
||||||
|
if (result) {
|
||||||
|
IMethod callee = methodTargetSelector.getCalleeTarget(node, site, null);
|
||||||
|
if (callee != null && callee.isSynthetic()) {
|
||||||
|
SyntheticMethod s = (SyntheticMethod) callee;
|
||||||
|
if (s.isFactoryMethod()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.ipa.callgraph.ContextSelector#contextIsIrrelevant(com.ibm.wala.types.MethodReference)
|
||||||
|
*/
|
||||||
|
public boolean allSitesDispatchIdentically(CGNode node, CallSiteReference site) {
|
||||||
|
boolean result = methodTargetSelector.mightReturnSyntheticMethod(node,site);
|
||||||
|
if (result) {
|
||||||
|
IClass recv = cha.lookupClass(site.getDeclaredTarget().getDeclaringClass());
|
||||||
|
if (recv == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
IMethod callee = methodTargetSelector.getCalleeTarget(node, site, recv);
|
||||||
|
if (callee != null && callee.isSynthetic()) {
|
||||||
|
SyntheticMethod s = (SyntheticMethod) callee;
|
||||||
|
if (s.isFactoryMethod()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.analysis.reflection;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||||
|
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* An instance key which has an associated node
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public interface InstanceKeyWithNode extends InstanceKey {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the node which created this instance.
|
||||||
|
*/
|
||||||
|
CGNode getNode();
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.reflection;
|
||||||
|
|
||||||
|
import com.ibm.wala.analysis.typeInference.TypeAbstraction;
|
||||||
|
import com.ibm.wala.ipa.callgraph.Context;
|
||||||
|
import com.ibm.wala.ipa.callgraph.ContextItem;
|
||||||
|
import com.ibm.wala.ipa.callgraph.ContextKey;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Implement a Context which corresponds to a given type abstraction.
|
||||||
|
* Thus, this maps the name "TYPE" to a JavaTypeAbstraction.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class JavaTypeContext implements Context {
|
||||||
|
|
||||||
|
private final TypeAbstraction type;
|
||||||
|
|
||||||
|
public JavaTypeContext(TypeAbstraction type) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(type != null);
|
||||||
|
}
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ContextItem get(ContextKey name) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(name == ContextKey.RECEIVER);
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "JavaTypeContext<" + type + ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return 6367 * type.hashCode();
|
||||||
|
}
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (getClass().equals(obj.getClass())) {
|
||||||
|
JavaTypeContext other = (JavaTypeContext)obj;
|
||||||
|
return type.equals(other.type);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.reflection;
|
||||||
|
|
||||||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
|
import com.ibm.wala.types.TypeName;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* some utility support for dealing with "malleable" reflection allocations
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class Malleable {
|
||||||
|
private final static TypeName MalleableName = TypeName.string2TypeName("Lcom/ibm/wala/Malleable");
|
||||||
|
public final static TypeReference Malleable = TypeReference.findOrCreate(ClassLoaderReference.Primordial, MalleableName);
|
||||||
|
public final static TypeReference ExtMalleable = TypeReference.findOrCreate(ClassLoaderReference.Extension, MalleableName);
|
||||||
|
|
||||||
|
public final static TypeReference MalleableCollection = TypeReference.findOrCreate(ClassLoaderReference.Primordial,
|
||||||
|
"Lcom/ibm/wala/model/java/util/MalleableCollection");
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean isMalleable(TypeReference T) {
|
||||||
|
return T.equals(Malleable) || T.equals(ExtMalleable);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<HTML>
|
||||||
|
<BODY>
|
||||||
|
This package provides functions to deal with reflection.
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
||||||
|
<HTML>
|
||||||
|
<BODY>
|
||||||
|
This package provides a layer to perform abstract interpretation over
|
||||||
|
the JVM stack machine.
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.typeInference;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IClass;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Absraction of a Java type. These are immutable.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class ConeType extends TypeAbstraction {
|
||||||
|
|
||||||
|
private final IClass type;
|
||||||
|
private final ClassHierarchy cha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default constructor
|
||||||
|
*/
|
||||||
|
public ConeType(IClass type, ClassHierarchy cha) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(type != null);
|
||||||
|
Assertions._assert(type.getReference().isReferenceType());
|
||||||
|
}
|
||||||
|
this.type = type;
|
||||||
|
this.cha = cha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeAbstraction meet(TypeAbstraction rhs) {
|
||||||
|
if (rhs == TOP) {
|
||||||
|
return this;
|
||||||
|
} else if (rhs instanceof ConeType) {
|
||||||
|
ConeType other = (ConeType) rhs;
|
||||||
|
if (type.equals(other.type)) {
|
||||||
|
return this;
|
||||||
|
} else if (type.isArrayClass() || other.type.isArrayClass()) {
|
||||||
|
// give up on arrays. We don't care anyway.
|
||||||
|
return new ConeType(cha.getRootClass(), cha);
|
||||||
|
} else {
|
||||||
|
return new ConeType(cha.getLeastCommonSuperclass(this.type, other.type), cha);
|
||||||
|
}
|
||||||
|
} else if (rhs instanceof PointType) {
|
||||||
|
return rhs.meet(this);
|
||||||
|
} else if (rhs instanceof PrimitiveType) {
|
||||||
|
return TOP;
|
||||||
|
} else {
|
||||||
|
Assertions.UNREACHABLE("unexpected type " + rhs.getClass());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "cone:" + type.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getType.
|
||||||
|
* @return TypeReference
|
||||||
|
*/
|
||||||
|
public IClass getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#equals(Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof ConeType))
|
||||||
|
return false;
|
||||||
|
ConeType other = (ConeType) obj;
|
||||||
|
if (other == TOP)
|
||||||
|
return false;
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
if (!cha.equals(other.cha)) {
|
||||||
|
Assertions._assert(cha.equals(other.cha), "different chas " + this +" " + other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return type.equals(other.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return 39 * type.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isArrayType() {
|
||||||
|
return getType().isArrayClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInterface() {
|
||||||
|
return getType().isInterface();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an Iteration of IClass that implement this interface
|
||||||
|
*/
|
||||||
|
public Iterator iterateImplementors() {
|
||||||
|
return cha.getImplementors(getType().getReference()).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassHierarchy getClassHierarchy() {
|
||||||
|
return cha;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.typeInference;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IClass;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Abstraction of a Java type. These are immutable.
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class PointType extends TypeAbstraction {
|
||||||
|
|
||||||
|
private final IClass type;
|
||||||
|
private final ClassHierarchy cha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private constructor ... only for internal use.
|
||||||
|
*/
|
||||||
|
public PointType(IClass type, ClassHierarchy cha) {
|
||||||
|
this.type = type;
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(type != null);
|
||||||
|
Assertions._assert(type.getReference().isReferenceType());
|
||||||
|
}
|
||||||
|
this.cha = cha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeAbstraction meet(TypeAbstraction rhs) {
|
||||||
|
if (rhs == TOP) {
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
if (rhs instanceof PointType) {
|
||||||
|
PointType other = (PointType) rhs;
|
||||||
|
if (type.equals(other.type)) {
|
||||||
|
return this;
|
||||||
|
} else if (type.isArrayClass() || other.type.isArrayClass()) {
|
||||||
|
// give up on arrays. We don't care anyway.
|
||||||
|
return new ConeType(cha.getRootClass(), cha);
|
||||||
|
} else {
|
||||||
|
return new ConeType(cha.getLeastCommonSuperclass(this.type, other.type), cha);
|
||||||
|
}
|
||||||
|
} else if (rhs instanceof ConeType) {
|
||||||
|
ConeType other = (ConeType) rhs;
|
||||||
|
TypeReference T = other.getType().getReference();
|
||||||
|
if (type.isArrayClass() || T.isArrayType()) {
|
||||||
|
// give up on arrays. We don't care anyway.
|
||||||
|
return new ConeType(cha.getRootClass(), cha);
|
||||||
|
}
|
||||||
|
IClass typeKlass = type;
|
||||||
|
if (cha.isSubclassOf(typeKlass, other.getType())) {
|
||||||
|
return other;
|
||||||
|
} else if (other.isInterface()) {
|
||||||
|
if (cha.implementsInterface(typeKlass, T)) {
|
||||||
|
return other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if we get here, we need to do cha-based superclass and return a cone.
|
||||||
|
// TODO: avoid the allocation
|
||||||
|
return other.meet(new ConeType(other.getType(), cha));
|
||||||
|
} else {
|
||||||
|
Assertions.UNREACHABLE("Unexpected type: " + rhs.getClass());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "point: " + type.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getType.
|
||||||
|
*
|
||||||
|
* @return TypeReference
|
||||||
|
*/
|
||||||
|
public IClass getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#equals(Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof PointType)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PointType other = (PointType) obj;
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
if (!cha.equals(other.cha)) {
|
||||||
|
Assertions._assert(cha.equals(other.cha), "different chas " + this + " " + other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return type.equals(other.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return 37 * type.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isArrayType() {
|
||||||
|
return getType().isArrayClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IClass getIClass() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.analysis.typeInference;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IClass;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
|
||||||
|
public class PrimitiveType extends TypeAbstraction {
|
||||||
|
|
||||||
|
private static Map<TypeReference, PrimitiveType> refernceToType = new HashMap<TypeReference, PrimitiveType>();
|
||||||
|
|
||||||
|
public static final PrimitiveType BOOLEAN = makePrimitive(TypeReference.Boolean);
|
||||||
|
|
||||||
|
public static final PrimitiveType CHAR = makePrimitive(TypeReference.Char);
|
||||||
|
|
||||||
|
public static final PrimitiveType BYTE = makePrimitive(TypeReference.Byte);
|
||||||
|
|
||||||
|
public static final PrimitiveType SHORT = makePrimitive(TypeReference.Short);
|
||||||
|
|
||||||
|
public static final PrimitiveType INT = makePrimitive(TypeReference.Int);
|
||||||
|
|
||||||
|
public static final PrimitiveType LONG = makePrimitive(TypeReference.Long);
|
||||||
|
|
||||||
|
public static final PrimitiveType FLOAT = makePrimitive(TypeReference.Float);
|
||||||
|
|
||||||
|
public static final PrimitiveType DOUBLE = makePrimitive(TypeReference.Double);
|
||||||
|
|
||||||
|
private static HashMap<String, String> primitiveNameMap;
|
||||||
|
static {
|
||||||
|
primitiveNameMap = HashMapFactory.make(9);
|
||||||
|
primitiveNameMap.put("I", "int");
|
||||||
|
primitiveNameMap.put("J", "long");
|
||||||
|
primitiveNameMap.put("S", "short");
|
||||||
|
primitiveNameMap.put("B", "byte");
|
||||||
|
primitiveNameMap.put("C", "char");
|
||||||
|
primitiveNameMap.put("D", "double");
|
||||||
|
primitiveNameMap.put("F", "float");
|
||||||
|
primitiveNameMap.put("Z", "boolean");
|
||||||
|
primitiveNameMap.put("V", "void");
|
||||||
|
}
|
||||||
|
|
||||||
|
private final TypeReference reference;
|
||||||
|
|
||||||
|
private PrimitiveType(TypeReference reference) {
|
||||||
|
this.reference = reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeAbstraction meet(TypeAbstraction rhs) {
|
||||||
|
if (rhs == TOP) {
|
||||||
|
return this;
|
||||||
|
} else if (rhs == this) {
|
||||||
|
return this;
|
||||||
|
} else if (this == BOOLEAN) {
|
||||||
|
return rhs;
|
||||||
|
} else if (rhs == BOOLEAN) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return TOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return reference.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
return this == other;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IClass getType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PrimitiveType getPrimitive(TypeReference reference) {
|
||||||
|
return refernceToType.get(reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PrimitiveType makePrimitive(TypeReference reference) {
|
||||||
|
PrimitiveType newType = new PrimitiveType(reference);
|
||||||
|
refernceToType.put(reference, newType);
|
||||||
|
return newType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
String result = primitiveNameMap.get(reference.getName().toString());
|
||||||
|
return (result != null) ? result : "PrimitiveType";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.typeInference;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.CallSiteReference;
|
||||||
|
import com.ibm.wala.classLoader.CodeScanner;
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||||
|
import com.ibm.wala.ssa.IR;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInvokeInstruction;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Holds results of type inference for call site receivers.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class ReceiverTypeInference {
|
||||||
|
|
||||||
|
private TypeInference ti;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping from call site reference to InvokeInstruction. TODO: this kind of
|
||||||
|
* sucks. Redesign?
|
||||||
|
*/
|
||||||
|
private HashMap<CallSiteReference, SSAInvokeInstruction> invokeMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object to track analysis warnings
|
||||||
|
*/
|
||||||
|
private WarningSet warnings;
|
||||||
|
|
||||||
|
public ReceiverTypeInference(TypeInference ti, WarningSet warnings) {
|
||||||
|
this.ti = ti;
|
||||||
|
this.warnings = warnings;
|
||||||
|
|
||||||
|
try {
|
||||||
|
setupInvokeMap();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method setupInvokeMap. TODO: redesign stuff so that all this is not
|
||||||
|
* necessary. TODO: has that time come .. is this unnecesary yet?
|
||||||
|
*
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
private void setupInvokeMap() throws InvalidClassFileException {
|
||||||
|
|
||||||
|
invokeMap = HashMapFactory.make(5);
|
||||||
|
IR ir = ti.getIR();
|
||||||
|
IMethod method = ir.getMethod();
|
||||||
|
// set up mapping from Integer (program counter) -> CallSiteReference
|
||||||
|
HashMap<Integer, CallSiteReference> intMap = HashMapFactory.make(5);
|
||||||
|
for (Iterator it = CodeScanner.iterateCallSites(method, warnings); it.hasNext();) {
|
||||||
|
CallSiteReference site = (CallSiteReference) it.next();
|
||||||
|
int pc = site.getProgramCounter();
|
||||||
|
intMap.put(new Integer(pc), site);
|
||||||
|
}
|
||||||
|
// now set up mapping from CallSiteReference -> InvokeInstruction
|
||||||
|
SSAInstruction[] instructions = ir.getInstructions();
|
||||||
|
for (int i = 0; i < instructions.length; i++) {
|
||||||
|
SSAInstruction s = instructions[i];
|
||||||
|
if (s instanceof SSAInvokeInstruction) {
|
||||||
|
SSAInvokeInstruction call = (SSAInvokeInstruction) s;
|
||||||
|
int pc = call.getProgramCounter();
|
||||||
|
CallSiteReference site = intMap.get(new Integer(pc));
|
||||||
|
invokeMap.put(site, call);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeAbstraction getReceiverType(CallSiteReference site) {
|
||||||
|
SSAInvokeInstruction instruction = getInvokeInstruction(site);
|
||||||
|
if (instruction == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int def = instruction.getReceiver();
|
||||||
|
if (def == -1) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return ti.getType(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getInvokeInstruction.
|
||||||
|
*
|
||||||
|
* @param site
|
||||||
|
* @return InvokeInstruction
|
||||||
|
*/
|
||||||
|
private SSAInvokeInstruction getInvokeInstruction(CallSiteReference site) {
|
||||||
|
return invokeMap.get(site);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.typeInference;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
||||||
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.ssa.IR;
|
||||||
|
import com.ibm.wala.ssa.SSAOptions;
|
||||||
|
import com.ibm.wala.util.CacheReference;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A soft cache of results of type inference
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class ReceiverTypeInferenceCache {
|
||||||
|
|
||||||
|
private final WarningSet warnings;
|
||||||
|
|
||||||
|
private final ClassHierarchy cha;
|
||||||
|
|
||||||
|
private final AnalysisOptions options;
|
||||||
|
|
||||||
|
public ReceiverTypeInferenceCache(ClassHierarchy cha, AnalysisOptions options, WarningSet warnings) {
|
||||||
|
this.warnings = warnings;
|
||||||
|
this.options = options;
|
||||||
|
this.cha = cha;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cache of TypeInference results; a mapping from CGNode ->
|
||||||
|
* ReceiverTypeInference
|
||||||
|
*/
|
||||||
|
private final Map<CGNode, Object> typeInferenceMap = HashMapFactory.make();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param n
|
||||||
|
* node
|
||||||
|
* @return null if unable to perform type inference
|
||||||
|
*/
|
||||||
|
public ReceiverTypeInference findOrCreate(CGNode n) {
|
||||||
|
Object ref = typeInferenceMap.get(n);
|
||||||
|
ReceiverTypeInference result = (ReceiverTypeInference) CacheReference.get(ref);
|
||||||
|
try {
|
||||||
|
if (result == null) {
|
||||||
|
SSAOptions options = SSAOptions.defaultOptions();
|
||||||
|
options.setUsePiNodes(true);
|
||||||
|
IR ir = this.options.getSSACache().findOrCreateIR(n.getMethod(), n.getContext(), cha, options, warnings);
|
||||||
|
TypeInference T = new TypeInference(ir, cha);
|
||||||
|
T.solve();
|
||||||
|
|
||||||
|
result = new ReceiverTypeInference(T, warnings);
|
||||||
|
ref = CacheReference.make(result);
|
||||||
|
typeInferenceMap.put(n, ref);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
// this might happen if it's not a ShrikeCTMethodWrapper
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.typeInference;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.collections.HashSetFactory;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Abstraction of a set of PointTypes. These are immutable.
|
||||||
|
* TODO: fix for efficiency if needed.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SetType extends TypeAbstraction {
|
||||||
|
|
||||||
|
private final HashSet<TypeReference> types;
|
||||||
|
private final int hashCode;
|
||||||
|
|
||||||
|
public SetType(PointType[] points) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(points != null);
|
||||||
|
Assertions._assert(points.length > 0);
|
||||||
|
}
|
||||||
|
types = HashSetFactory.make(points.length);
|
||||||
|
int h = 0;
|
||||||
|
for (int i = 0; i< points.length; i++) {
|
||||||
|
TypeReference T = points[i].getType().getReference();
|
||||||
|
h ^= T.hashCode();
|
||||||
|
types.add(T);
|
||||||
|
}
|
||||||
|
hashCode = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.analysis.typeInference.TypeAbstraction#meet(com.ibm.wala.analysis.typeInference.TypeAbstraction)
|
||||||
|
*/
|
||||||
|
public TypeAbstraction meet(TypeAbstraction rhs) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.analysis.typeInference.TypeAbstraction#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
// TODO: make SetTypes of size 1 equal PointTypes.
|
||||||
|
// need a factory facade for this.
|
||||||
|
|
||||||
|
// TODO: canonicalize?? How to improve this?
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj instanceof SetType) {
|
||||||
|
if (hashCode() != obj.hashCode()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
SetType other = (SetType)obj;
|
||||||
|
return (types.equals(other.types));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.analysis.typeInference.TypeAbstraction#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Iterator of the TypeReferences which compose this Set.
|
||||||
|
*/
|
||||||
|
public Iterator iteratePoints() {
|
||||||
|
return types.iterator();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.analysis.typeInference;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IClass;
|
||||||
|
import com.ibm.wala.ipa.callgraph.ContextItem;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Absraction of a Java type. These are immutable.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public abstract class TypeAbstraction implements ContextItem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Canonical element representing TOP for a dataflow lattice
|
||||||
|
*/
|
||||||
|
public final static TypeAbstraction TOP = new TypeAbstraction() {
|
||||||
|
public TypeAbstraction meet(TypeAbstraction rhs) {
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
public String toString() {
|
||||||
|
return "JavaTypeAbstraction.TOP";
|
||||||
|
}
|
||||||
|
public int hashCode() {
|
||||||
|
return 17;
|
||||||
|
}
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
return this == other;
|
||||||
|
}
|
||||||
|
public IClass getType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public abstract TypeAbstraction meet(TypeAbstraction rhs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#equals(Object)
|
||||||
|
*/
|
||||||
|
public abstract boolean equals(Object obj);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public abstract int hashCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is here for convenience; it makes sense for Point and Cone Dispatch.
|
||||||
|
* TODO: probably should get rid of it.
|
||||||
|
*/
|
||||||
|
public IClass getType() {
|
||||||
|
Assertions.UNREACHABLE("getType not implemented for " + getClass());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,766 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.analysis.typeInference;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IClass;
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.dataflow.ssa.SSAInference;
|
||||||
|
import com.ibm.wala.fixedpoint.impl.AbstractOperator;
|
||||||
|
import com.ibm.wala.fixedpoint.impl.AbstractVariable;
|
||||||
|
import com.ibm.wala.fixedpoint.impl.NullaryOperator;
|
||||||
|
import com.ibm.wala.fixpoint.FixedPointConstants;
|
||||||
|
import com.ibm.wala.fixpoint.IVariable;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.ssa.IR;
|
||||||
|
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAArrayLengthInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAArrayLoadInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSABinaryOpInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSACheckCastInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAConversionInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAGetInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInvokeInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSANewInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAPhiInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAPiInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAUnaryOpInstruction;
|
||||||
|
import com.ibm.wala.ssa.SymbolTable;
|
||||||
|
import com.ibm.wala.ssa.SSACFG.ExceptionHandlerBasicBlock;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This class performs intraprocedural type propagation on an SSA IR.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class TypeInference extends SSAInference implements FixedPointConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The governing SSA form
|
||||||
|
*/
|
||||||
|
protected IR ir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The governing class hierarchy
|
||||||
|
*/
|
||||||
|
protected ClassHierarchy cha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A singleton instance of the phi operator.
|
||||||
|
*/
|
||||||
|
private final static AbstractOperator phiOp = new PhiOperator();
|
||||||
|
|
||||||
|
private final static AbstractOperator primitivePropagateOp = new PrimitivePropagateOperator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cone type for java.lang.Object
|
||||||
|
*/
|
||||||
|
protected final TypeAbstraction BOTTOM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A singleton instance of the pi operator.
|
||||||
|
*/
|
||||||
|
private final static PiOperator piOp = new PiOperator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* should type inference track primitive types?
|
||||||
|
*/
|
||||||
|
protected final boolean doPrimitives;
|
||||||
|
|
||||||
|
public TypeInference(IR ir, ClassHierarchy cha, boolean doPrimitives) {
|
||||||
|
this.cha = cha;
|
||||||
|
this.ir = ir;
|
||||||
|
this.doPrimitives = doPrimitives;
|
||||||
|
this.BOTTOM = new ConeType(cha.getRootClass(), cha);
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeInference(IR ir, ClassHierarchy cha) {
|
||||||
|
this(ir, cha, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initialize() {
|
||||||
|
init(ir, this.new TypeVarFactory(), this.new TypeOperatorFactory());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initializeVariables() {
|
||||||
|
int[] parameterValueNumbers = ir.getParameterValueNumbers();
|
||||||
|
for (int i = 0; i < parameterValueNumbers.length; i++) {
|
||||||
|
TypeVariable v = (TypeVariable) getVariable(parameterValueNumbers[i]);
|
||||||
|
TypeReference t = ir.getParameterType(i);
|
||||||
|
|
||||||
|
if (t.isReferenceType()) {
|
||||||
|
IClass klass = cha.lookupClass(t);
|
||||||
|
if (klass != null) {
|
||||||
|
v.setType(new ConeType(klass, cha));
|
||||||
|
} else {
|
||||||
|
v.setType(ConeType.TOP);
|
||||||
|
// v.setType(BOTTOM);
|
||||||
|
}
|
||||||
|
} else if (doPrimitives) {
|
||||||
|
v.setType(PrimitiveType.getPrimitive(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolTable st = ir.getSymbolTable();
|
||||||
|
if (st != null) {
|
||||||
|
for(int i = 0; i < st.getMaxValueNumber(); i++ ) {
|
||||||
|
if (st.isConstant(i)) {
|
||||||
|
TypeVariable v = (TypeVariable) getVariable(i);
|
||||||
|
v.setType(getConstantType(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Iterator it = ir.iterateNormalInstructions(); it.hasNext();) {
|
||||||
|
SSAInstruction s = (SSAInstruction) it.next();
|
||||||
|
if (s instanceof SSAAbstractInvokeInstruction) {
|
||||||
|
SSAAbstractInvokeInstruction call = (SSAAbstractInvokeInstruction) s;
|
||||||
|
TypeVariable v = (TypeVariable) getVariable(call.getException());
|
||||||
|
Collection defaultExceptions = call.getExceptionTypes();
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(defaultExceptions.size() == 1);
|
||||||
|
}
|
||||||
|
// t should be NullPointerException
|
||||||
|
TypeReference t = (TypeReference) defaultExceptions.iterator().next();
|
||||||
|
IClass klass = cha.lookupClass(t);
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(klass != null);
|
||||||
|
}
|
||||||
|
v.setType(new PointType(klass, cha));
|
||||||
|
|
||||||
|
IMethod m = cha.resolveMethod(call.getDeclaredTarget());
|
||||||
|
if (m != null) {
|
||||||
|
TypeReference[] x = m.getDeclaredExceptions();
|
||||||
|
if (x != null) {
|
||||||
|
for (int i = 0; i < x.length; i++) {
|
||||||
|
TypeReference tx = x[i];
|
||||||
|
IClass tc = cha.lookupClass(tx);
|
||||||
|
if (tc != null) {
|
||||||
|
v.setType(v.getType().meet(new ConeType(tc, cha)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void initializeWorkList() {
|
||||||
|
addAllStatementsToWorkList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
* An operator which initializes a type to a declared type.
|
||||||
|
*/
|
||||||
|
protected final class DeclaredTypeOperator extends NullaryOperator {
|
||||||
|
private final TypeAbstraction type;
|
||||||
|
|
||||||
|
public DeclaredTypeOperator(TypeAbstraction type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that we need evalute this operator at most once
|
||||||
|
*/
|
||||||
|
public byte evaluate(IVariable lhs) {
|
||||||
|
TypeVariable t = (TypeVariable) lhs;
|
||||||
|
if (t.type.equals(type)) {
|
||||||
|
return NOT_CHANGED_AND_FIXED;
|
||||||
|
} else {
|
||||||
|
t.setType(type);
|
||||||
|
return CHANGED_AND_FIXED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "delared type := " + type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNullary() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.dataflow.Operator#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return 9931 * type.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.dataflow.Operator#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o instanceof DeclaredTypeOperator) {
|
||||||
|
DeclaredTypeOperator d = (DeclaredTypeOperator) o;
|
||||||
|
return type.equals(d.type);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final class PhiOperator extends AbstractOperator {
|
||||||
|
|
||||||
|
private PhiOperator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: work on efficiency shortcuts for this.
|
||||||
|
*/
|
||||||
|
public byte evaluate(IVariable lhs, IVariable[] rhs) {
|
||||||
|
TypeVariable L = (TypeVariable) lhs;
|
||||||
|
TypeAbstraction lhsType = L.getType();
|
||||||
|
TypeAbstraction meet = TypeAbstraction.TOP;
|
||||||
|
for (int i = 0; i < rhs.length; i++) {
|
||||||
|
if (rhs[i] != null) {
|
||||||
|
TypeVariable r = (TypeVariable) rhs[i];
|
||||||
|
meet = meet.meet(r.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lhsType.equals(meet)) {
|
||||||
|
return NOT_CHANGED;
|
||||||
|
} else {
|
||||||
|
L.setType(meet);
|
||||||
|
return CHANGED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "phi meet";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.dataflow.Operator#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return 9929;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.dataflow.Operator#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return (o instanceof PhiOperator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final class PiOperator extends AbstractOperator {
|
||||||
|
|
||||||
|
private PiOperator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: work on efficiency shortcuts for this.
|
||||||
|
*/
|
||||||
|
public byte evaluate(IVariable lhsOperand, IVariable[] rhsOperands) {
|
||||||
|
TypeVariable lhs = (TypeVariable) lhsOperand;
|
||||||
|
TypeAbstraction lhsType = lhs.getType();
|
||||||
|
|
||||||
|
TypeVariable rhs = (TypeVariable) rhsOperands[0];
|
||||||
|
TypeAbstraction rhsType = rhs.getType();
|
||||||
|
|
||||||
|
if (lhsType.equals(rhsType)) {
|
||||||
|
return NOT_CHANGED;
|
||||||
|
} else {
|
||||||
|
lhs.setType(rhsType);
|
||||||
|
return CHANGED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "pi";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.dataflow.Operator#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return 9929 * 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.dataflow.Operator#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return (o instanceof PiOperator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final class PrimitivePropagateOperator extends AbstractOperator {
|
||||||
|
|
||||||
|
private PrimitivePropagateOperator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte evaluate(IVariable lhs, IVariable[] rhs) {
|
||||||
|
TypeVariable L = (TypeVariable) lhs;
|
||||||
|
TypeAbstraction lhsType = L.getType();
|
||||||
|
TypeAbstraction meet = TypeAbstraction.TOP;
|
||||||
|
for (int i = 0; i < rhs.length; i++) {
|
||||||
|
if (rhs[i] != null) {
|
||||||
|
TypeVariable r = (TypeVariable) rhs[i];
|
||||||
|
meet = meet.meet(r.getType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lhsType.equals(meet)) {
|
||||||
|
return NOT_CHANGED;
|
||||||
|
} else {
|
||||||
|
L.setType(meet);
|
||||||
|
return CHANGED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "propagate";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.dataflow.Operator#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return 99292;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.dataflow.Operator#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return (o instanceof PrimitivePropagateOperator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This operator will extract the element type from an arrayref in an array
|
||||||
|
* access instruction
|
||||||
|
*
|
||||||
|
* TODO: why isn't this a nullary operator?
|
||||||
|
*/
|
||||||
|
private final class GetElementType extends AbstractOperator {
|
||||||
|
private final SSAArrayLoadInstruction load;
|
||||||
|
|
||||||
|
GetElementType(SSAArrayLoadInstruction load) {
|
||||||
|
this.load = load;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte evaluate(IVariable lhs, IVariable[] rhs) {
|
||||||
|
TypeVariable t = (TypeVariable) lhs;
|
||||||
|
TypeAbstraction arrayType = getType(load.getArrayRef());
|
||||||
|
if (arrayType.equals(TypeAbstraction.TOP)) {
|
||||||
|
return NOT_CHANGED;
|
||||||
|
}
|
||||||
|
TypeReference elementType = null;
|
||||||
|
|
||||||
|
if (arrayType instanceof PointType) {
|
||||||
|
elementType = ((PointType) arrayType).getType().getReference().getArrayElementType();
|
||||||
|
} else if (arrayType instanceof ConeType) {
|
||||||
|
elementType = ((ConeType) arrayType).getType().getReference().getArrayElementType();
|
||||||
|
} else {
|
||||||
|
Assertions.UNREACHABLE("Unexpected type " + arrayType.getClass());
|
||||||
|
}
|
||||||
|
if (elementType.isPrimitiveType()) {
|
||||||
|
if (doPrimitives && t.getType() == TypeAbstraction.TOP) {
|
||||||
|
t.setType(PrimitiveType.getPrimitive(elementType));
|
||||||
|
return CHANGED;
|
||||||
|
}
|
||||||
|
return NOT_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t.getType() != TypeAbstraction.TOP) {
|
||||||
|
TypeReference tType = null;
|
||||||
|
if (t.getType() instanceof PointType) {
|
||||||
|
tType = ((PointType) t.getType()).getType().getReference();
|
||||||
|
} else if (t.getType() instanceof ConeType) {
|
||||||
|
tType = ((ConeType) t.getType()).getType().getReference();
|
||||||
|
} else {
|
||||||
|
Assertions.UNREACHABLE("Unexpected type " + t.getType().getClass());
|
||||||
|
}
|
||||||
|
if (tType.equals(elementType)) {
|
||||||
|
return NOT_CHANGED;
|
||||||
|
} else {
|
||||||
|
IClass klass = cha.lookupClass(elementType);
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(klass != null);
|
||||||
|
}
|
||||||
|
t.setType(new ConeType(klass, cha));
|
||||||
|
return CHANGED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
IClass klass = cha.lookupClass(elementType);
|
||||||
|
// if (Assertions.verifyAssertions) {
|
||||||
|
// Assertions._assert(klass != null);
|
||||||
|
// }
|
||||||
|
if (klass != null) {
|
||||||
|
t.setType(new ConeType(klass, cha));
|
||||||
|
} else {
|
||||||
|
t.setType(ConeType.TOP);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CHANGED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "getElementType " + load;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.dataflow.Operator#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return 9923 * load.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.dataflow.Operator#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o instanceof GetElementType) {
|
||||||
|
GetElementType other = (GetElementType) o;
|
||||||
|
return load.equals(other.load);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class TypeOperatorFactory extends SSAInstruction.Visitor implements OperatorFactory {
|
||||||
|
|
||||||
|
protected AbstractOperator result = null;
|
||||||
|
|
||||||
|
public AbstractOperator get(SSAInstruction instruction) {
|
||||||
|
instruction.visit(this);
|
||||||
|
AbstractOperator temp = result;
|
||||||
|
result = null;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitArrayLoad(SSAArrayLoadInstruction instruction) {
|
||||||
|
result = new GetElementType(instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitArrayLength(SSAArrayLengthInstruction instruction) {
|
||||||
|
if (!doPrimitives) {
|
||||||
|
result = null;
|
||||||
|
} else {
|
||||||
|
result = new DeclaredTypeOperator(PrimitiveType.INT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitGet(SSAGetInstruction instruction) {
|
||||||
|
TypeReference type = instruction.getDeclaredFieldType();
|
||||||
|
|
||||||
|
if (doPrimitives && type.isPrimitiveType()) {
|
||||||
|
result = new DeclaredTypeOperator(PrimitiveType.getPrimitive(type));
|
||||||
|
} else {
|
||||||
|
IClass klass = cha.lookupClass(type);
|
||||||
|
if (klass == null) {
|
||||||
|
// get from a field of a type that cannot be loaded.
|
||||||
|
// be pessimistic
|
||||||
|
result = new DeclaredTypeOperator(BOTTOM);
|
||||||
|
} else {
|
||||||
|
result = new DeclaredTypeOperator(new ConeType(klass, cha));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitInvoke(SSAInvokeInstruction instruction) {
|
||||||
|
TypeReference type = instruction.getDeclaredResultType();
|
||||||
|
if (type.isReferenceType()) {
|
||||||
|
IClass klass = cha.lookupClass(type);
|
||||||
|
if (klass == null) {
|
||||||
|
// a type that cannot be loaded.
|
||||||
|
// be pessimistic
|
||||||
|
result = new DeclaredTypeOperator(BOTTOM);
|
||||||
|
} else {
|
||||||
|
result = new DeclaredTypeOperator(new ConeType(klass, cha));
|
||||||
|
}
|
||||||
|
} else if (doPrimitives && type.isPrimitiveType()) {
|
||||||
|
result = new DeclaredTypeOperator(PrimitiveType.getPrimitive(type));
|
||||||
|
} else {
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitNew(SSANewInstruction instruction) {
|
||||||
|
TypeReference type = instruction.getConcreteType();
|
||||||
|
IClass klass = cha.lookupClass(type);
|
||||||
|
if (klass == null) {
|
||||||
|
// a type that cannot be loaded.
|
||||||
|
// be pessimistic
|
||||||
|
result = new DeclaredTypeOperator(BOTTOM);
|
||||||
|
} else {
|
||||||
|
result = new DeclaredTypeOperator(new PointType(klass, cha));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitCheckCast(SSACheckCastInstruction instruction) {
|
||||||
|
TypeReference type = instruction.getDeclaredResultType();
|
||||||
|
IClass klass = cha.lookupClass(type);
|
||||||
|
if (klass == null) {
|
||||||
|
// a type that cannot be loaded.
|
||||||
|
// be pessimistic
|
||||||
|
result = new DeclaredTypeOperator(BOTTOM);
|
||||||
|
} else {
|
||||||
|
result = new DeclaredTypeOperator(new ConeType(klass, cha));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitConversion(SSAConversionInstruction instruction) {
|
||||||
|
if (doPrimitives) {
|
||||||
|
result = new DeclaredTypeOperator(PrimitiveType.getPrimitive(instruction.getToType()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitBinaryOp(SSABinaryOpInstruction instruction) {
|
||||||
|
if (doPrimitives) {
|
||||||
|
result = primitivePropagateOp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitUnaryOp(SSAUnaryOpInstruction instruction) {
|
||||||
|
if (doPrimitives) {
|
||||||
|
result = primitivePropagateOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) {
|
||||||
|
TypeAbstraction type = meetDeclaredExceptionTypes(instruction, cha);
|
||||||
|
result = new DeclaredTypeOperator(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitPhi(SSAPhiInstruction instruction) {
|
||||||
|
result = phiOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitPi(SSAPiInstruction instruction) {
|
||||||
|
result = piOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TypeAbstraction meetDeclaredExceptionTypes(SSAGetCaughtExceptionInstruction s, ClassHierarchy cha) {
|
||||||
|
ExceptionHandlerBasicBlock bb = (ExceptionHandlerBasicBlock) ir.getControlFlowGraph().getNode(s.getBasicBlockNumber());
|
||||||
|
Iterator it = bb.getCaughtExceptionTypes();
|
||||||
|
TypeReference t = (TypeReference) it.next();
|
||||||
|
IClass klass = cha.lookupClass(t);
|
||||||
|
TypeAbstraction result = null;
|
||||||
|
if (klass == null) {
|
||||||
|
// a type that cannot be loaded.
|
||||||
|
// be pessimistic
|
||||||
|
result = BOTTOM;
|
||||||
|
} else {
|
||||||
|
result = new ConeType(klass, cha);
|
||||||
|
}
|
||||||
|
while (it.hasNext()) {
|
||||||
|
t = (TypeReference) it.next();
|
||||||
|
IClass tClass = cha.lookupClass(t);
|
||||||
|
if (tClass == null) {
|
||||||
|
result = BOTTOM;
|
||||||
|
} else {
|
||||||
|
result = result.meet(new ConeType(tClass, cha));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type variable in the dataflow system.
|
||||||
|
*/
|
||||||
|
protected static class TypeVariable extends AbstractVariable {
|
||||||
|
|
||||||
|
private TypeAbstraction type;
|
||||||
|
|
||||||
|
private final int hash;
|
||||||
|
|
||||||
|
public TypeVariable(TypeAbstraction type, int hashCode) {
|
||||||
|
this.type = type;
|
||||||
|
this.hash = hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void copyState(IVariable v) {
|
||||||
|
TypeVariable other = (TypeVariable) v;
|
||||||
|
this.type = other.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type.
|
||||||
|
*
|
||||||
|
* @return TypeAbstraction
|
||||||
|
*/
|
||||||
|
public TypeAbstraction getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the type.
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* The type to set
|
||||||
|
*/
|
||||||
|
public void setType(TypeAbstraction type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return type.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.dataflow.AbstractVariable#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TypeVarFactory implements VariableFactory {
|
||||||
|
|
||||||
|
public IVariable makeVariable(int valueNumber) {
|
||||||
|
SymbolTable st = ir.getSymbolTable();
|
||||||
|
if (doPrimitives) {
|
||||||
|
if (st.isConstant(valueNumber)) {
|
||||||
|
if (st.isBooleanConstant(valueNumber)) {
|
||||||
|
return new TypeVariable(PrimitiveType.BOOLEAN, 797 * valueNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if (st.isStringConstant(valueNumber)) {
|
||||||
|
// IClass klass = cha.lookupClass(TypeReference.JavaLangString);
|
||||||
|
// TypeAbstraction stringTypeAbs = new PointType(klass,cha);
|
||||||
|
// return new TypeVariable(stringTypeAbs, 797 * valueNumber);
|
||||||
|
// }
|
||||||
|
return new TypeVariable(TypeAbstraction.TOP, 797 * valueNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ir.
|
||||||
|
*
|
||||||
|
* @return IR
|
||||||
|
*/
|
||||||
|
public IR getIR() {
|
||||||
|
return ir;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getType.
|
||||||
|
*
|
||||||
|
* @param valueNumber
|
||||||
|
* @return JavaTypeAbstraction
|
||||||
|
*/
|
||||||
|
public TypeAbstraction getType(int valueNumber) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
if (getVariable(valueNumber) == null) {
|
||||||
|
Assertions._assert(getVariable(valueNumber) != null, "null variable for value number " + valueNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ((TypeVariable) getVariable(valueNumber)).getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeAbstraction getConstantType(int valueNumber) {
|
||||||
|
if (ir.getSymbolTable().isStringConstant(valueNumber)) {
|
||||||
|
return new PointType(cha.lookupClass(TypeReference.JavaLangString), cha);
|
||||||
|
} else {
|
||||||
|
return getConstantPrimitiveType(valueNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeAbstraction getConstantPrimitiveType(int valueNumber) {
|
||||||
|
SymbolTable st = ir.getSymbolTable();
|
||||||
|
if (!st.isConstant(valueNumber)) {
|
||||||
|
return TypeAbstraction.TOP;
|
||||||
|
}
|
||||||
|
if (st.isIntegerConstant(valueNumber)) {
|
||||||
|
return PrimitiveType.INT;
|
||||||
|
} else if (st.isFloatConstant(valueNumber)) {
|
||||||
|
return PrimitiveType.FLOAT;
|
||||||
|
} else if (st.isDoubleConstant(valueNumber)) {
|
||||||
|
return PrimitiveType.DOUBLE;
|
||||||
|
}
|
||||||
|
return TypeAbstraction.TOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUndefined(int valueNumber) {
|
||||||
|
// TODO: Julian, you seem to be using BOTTOM in the European style.
|
||||||
|
// Steve's code assumes American style (god forbid), so what you're getting
|
||||||
|
// here
|
||||||
|
// is not undefined, but java.lang.Object [NR/EY]
|
||||||
|
if (getVariable(valueNumber) == null)
|
||||||
|
return true;
|
||||||
|
TypeAbstraction ta = ((TypeVariable) getVariable(valueNumber)).getType();
|
||||||
|
return ta == BOTTOM || ta.getType() == null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<HTML>
|
||||||
|
<BODY>
|
||||||
|
This package provides intraprocedural type inference over the SSA form.
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
|
@ -0,0 +1,656 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.cfg;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.shrikeBT.Constants;
|
||||||
|
import com.ibm.wala.util.CompoundIterator;
|
||||||
|
import com.ibm.wala.util.IteratorPlusOne;
|
||||||
|
import com.ibm.wala.util.IteratorPlusTwo;
|
||||||
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||||||
|
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.collections.NonNullSingletonIterator;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.graph.impl.DelegatingNumberedNodeManager;
|
||||||
|
import com.ibm.wala.util.graph.impl.NumberedNodeIterator;
|
||||||
|
import com.ibm.wala.util.graph.impl.SparseNumberedEdgeManager;
|
||||||
|
import com.ibm.wala.util.intset.BasicNonNegativeIntRelation;
|
||||||
|
import com.ibm.wala.util.intset.BitVector;
|
||||||
|
import com.ibm.wala.util.intset.FixedSizeBitVector;
|
||||||
|
import com.ibm.wala.util.intset.IntSet;
|
||||||
|
import com.ibm.wala.util.intset.MutableSparseIntSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A graph of basic blocks.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public abstract class AbstractCFG implements ControlFlowGraph, Constants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The method this AbstractCFG represents
|
||||||
|
*/
|
||||||
|
private final IMethod method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object to track nodes in this cfg
|
||||||
|
*/
|
||||||
|
private DelegatingNumberedNodeManager<IBasicBlock> nodeManager = new DelegatingNumberedNodeManager<IBasicBlock>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object to track most normal edges in this cfg
|
||||||
|
*/
|
||||||
|
private SparseNumberedEdgeManager<IBasicBlock> normalEdgeManager = new SparseNumberedEdgeManager<IBasicBlock>(nodeManager, 2,
|
||||||
|
BasicNonNegativeIntRelation.SIMPLE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object to track not-to-exit exceptional edges in this cfg
|
||||||
|
*/
|
||||||
|
private SparseNumberedEdgeManager<IBasicBlock> exceptionalEdgeManager = new SparseNumberedEdgeManager<IBasicBlock>(nodeManager,
|
||||||
|
0, BasicNonNegativeIntRelation.SIMPLE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which basic blocks have a normal edge to exit()?
|
||||||
|
*/
|
||||||
|
private FixedSizeBitVector normalToExit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which basic blocks have an exceptional edge to exit()?
|
||||||
|
*/
|
||||||
|
private FixedSizeBitVector exceptionalToExit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which basic blocks have a fall-through?
|
||||||
|
*/
|
||||||
|
private FixedSizeBitVector fallThru;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which basic blocks are catch blocks?
|
||||||
|
*/
|
||||||
|
private BitVector catchBlocks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache here for efficiency
|
||||||
|
*/
|
||||||
|
private IBasicBlock exit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param method
|
||||||
|
*/
|
||||||
|
protected AbstractCFG(IMethod method) {
|
||||||
|
this.method = method;
|
||||||
|
this.catchBlocks = new BitVector(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subclasses must call this before calling addEdge, but after creating the
|
||||||
|
* nodes
|
||||||
|
*/
|
||||||
|
protected void init() {
|
||||||
|
normalToExit = new FixedSizeBitVector(getMaxNumber() + 1);
|
||||||
|
exceptionalToExit = new FixedSizeBitVector(getMaxNumber() + 1);
|
||||||
|
fallThru = new FixedSizeBitVector(getMaxNumber() + 1);
|
||||||
|
exit = (IBasicBlock) getNode(getMaxNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean equals(Object o);
|
||||||
|
|
||||||
|
public abstract int hashCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the entry basic block for the CFG.
|
||||||
|
*
|
||||||
|
* @return the entry basic block for the CFG.
|
||||||
|
*/
|
||||||
|
public IBasicBlock entry() {
|
||||||
|
return (IBasicBlock) getNode(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the exit basic block for the CFG.
|
||||||
|
*
|
||||||
|
* @return the exit basic block for the CFG.
|
||||||
|
*/
|
||||||
|
public IBasicBlock exit() {
|
||||||
|
return exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public int getPredNodeCount(IBasicBlock N) {
|
||||||
|
if (N.equals(exit())) {
|
||||||
|
// TODO: cache if necessary
|
||||||
|
FixedSizeBitVector x = FixedSizeBitVector.or(normalToExit, exceptionalToExit);
|
||||||
|
return x.populationCount();
|
||||||
|
} else {
|
||||||
|
boolean normalIn = getNumberOfNormalIn(N) > 0;
|
||||||
|
boolean exceptionalIn = getNumberOfExceptionalIn(N) > 0;
|
||||||
|
if (normalIn) {
|
||||||
|
if (exceptionalIn) {
|
||||||
|
return new Iterator2Collection<IBasicBlock>(getPredNodes(N)).size();
|
||||||
|
} else {
|
||||||
|
return getNumberOfNormalIn(N);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return getNumberOfExceptionalIn(N);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfNormalIn(IBasicBlock N) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(!N.equals(exit()));
|
||||||
|
}
|
||||||
|
int number = getNumber(N);
|
||||||
|
int xtra = 0;
|
||||||
|
if (number > 0) {
|
||||||
|
if (fallThru.get(number - 1)) {
|
||||||
|
xtra++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return normalEdgeManager.getPredNodeCount(N) + xtra;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfExceptionalIn(IBasicBlock N) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(!N.equals(exit()));
|
||||||
|
}
|
||||||
|
return exceptionalEdgeManager.getPredNodeCount(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param number
|
||||||
|
* number of a basic block in this cfg
|
||||||
|
*/
|
||||||
|
boolean hasAnyNormalOut(int number) {
|
||||||
|
return (fallThru.get(number) || normalEdgeManager.getSuccNodeCount(number) > 0 || normalToExit.get(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param number
|
||||||
|
* number of a basic block in this cfg
|
||||||
|
*/
|
||||||
|
private int getNumberOfNormalOut(int number) {
|
||||||
|
int xtra = 0;
|
||||||
|
if (fallThru.get(number)) {
|
||||||
|
xtra++;
|
||||||
|
}
|
||||||
|
if (normalToExit.get(number)) {
|
||||||
|
xtra++;
|
||||||
|
}
|
||||||
|
return normalEdgeManager.getSuccNodeCount(number) + xtra;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param number
|
||||||
|
* number of a basic block in this cfg
|
||||||
|
*/
|
||||||
|
public int getNumberOfExceptionalOut(int number) {
|
||||||
|
int xtra = 0;
|
||||||
|
if (exceptionalToExit.get(number)) {
|
||||||
|
xtra++;
|
||||||
|
}
|
||||||
|
return exceptionalEdgeManager.getSuccNodeCount(number) + xtra;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfNormalOut(IBasicBlock N) {
|
||||||
|
return getNumberOfNormalOut(getNumber(N));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfExceptionalOut(IBasicBlock N) {
|
||||||
|
return getNumberOfExceptionalOut(getNumber(N));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<IBasicBlock> getPredNodes(IBasicBlock N) {
|
||||||
|
if (N.equals(exit())) {
|
||||||
|
return new FilterIterator<IBasicBlock>(iterateNodes(), new Filter() {
|
||||||
|
public boolean accepts(Object o) {
|
||||||
|
int i = getNumber((IBasicBlock) o);
|
||||||
|
return normalToExit.get(i) || exceptionalToExit.get(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
int number = getNumber(N);
|
||||||
|
boolean normalIn = getNumberOfNormalIn(N) > 0;
|
||||||
|
boolean exceptionalIn = getNumberOfExceptionalIn(N) > 0;
|
||||||
|
if (normalIn) {
|
||||||
|
if (exceptionalIn) {
|
||||||
|
HashSet<IBasicBlock> result = new HashSet<IBasicBlock>(getNumberOfNormalIn(N) + getNumberOfExceptionalIn(N));
|
||||||
|
result.addAll(new Iterator2Collection<IBasicBlock>(normalEdgeManager.getPredNodes(N)));
|
||||||
|
result.addAll(new Iterator2Collection<IBasicBlock>(exceptionalEdgeManager.getPredNodes(N)));
|
||||||
|
if (fallThru.get(number - 1)) {
|
||||||
|
result.add(getNode(number - 1));
|
||||||
|
}
|
||||||
|
return result.iterator();
|
||||||
|
} else {
|
||||||
|
if (number > 0 && fallThru.get(number - 1)) {
|
||||||
|
return new IteratorPlusOne<IBasicBlock>(normalEdgeManager.getPredNodes(N), getNode(number - 1));
|
||||||
|
} else {
|
||||||
|
return normalEdgeManager.getPredNodes(N);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// !normalIn
|
||||||
|
if (exceptionalIn) {
|
||||||
|
return exceptionalEdgeManager.getPredNodes(N);
|
||||||
|
} else {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSuccNodeCount(IBasicBlock N) {
|
||||||
|
if (N.equals(exit())) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int nNormal = getNumberOfNormalOut(N);
|
||||||
|
int nExc = getNumberOfExceptionalOut(N);
|
||||||
|
if (nNormal > 0) {
|
||||||
|
if (nExc > 0) {
|
||||||
|
if (nExc == 1) {
|
||||||
|
int number = getNumber(N);
|
||||||
|
if (exceptionalToExit.get(number)) {
|
||||||
|
if (normalToExit.get(number)) {
|
||||||
|
return nNormal + nExc - 1;
|
||||||
|
} else {
|
||||||
|
return nNormal + nExc;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return slowCountSuccNodes(N);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return slowCountSuccNodes(N);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return nNormal;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// nNormal == 0
|
||||||
|
return nExc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int slowCountSuccNodes(IBasicBlock N) {
|
||||||
|
return new Iterator2Collection<IBasicBlock>(getSuccNodes(N)).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<IBasicBlock> getSuccNodes(IBasicBlock N) {
|
||||||
|
int number = getNumber(N);
|
||||||
|
if (normalToExit.get(number) && exceptionalToExit.get(number)) {
|
||||||
|
return new CompoundIterator<IBasicBlock>(iterateNormalSuccessorsWithoutExit(number), iterateExceptionalSuccessors(number));
|
||||||
|
} else {
|
||||||
|
return new CompoundIterator<IBasicBlock>(iterateNormalSuccessors(number), iterateExceptionalSuccessors(number));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterator<IBasicBlock> iterateExceptionalSuccessors(int number) {
|
||||||
|
if (exceptionalEdgeManager.hasAnySuccessor(number)) {
|
||||||
|
if (exceptionalToExit.get(number)) {
|
||||||
|
return new IteratorPlusOne<IBasicBlock>(exceptionalEdgeManager.getSuccNodes(number), exit());
|
||||||
|
} else {
|
||||||
|
return exceptionalEdgeManager.getSuccNodes(number);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (exceptionalToExit.get(number)) {
|
||||||
|
return new NonNullSingletonIterator<IBasicBlock>(exit());
|
||||||
|
} else {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<IBasicBlock> iterateExceptionalPredecessors(IBasicBlock N) {
|
||||||
|
if (N.equals(exit())) {
|
||||||
|
return new FilterIterator<IBasicBlock>(iterateNodes(), new Filter() {
|
||||||
|
public boolean accepts(Object o) {
|
||||||
|
int i = getNumber((IBasicBlock) o);
|
||||||
|
return exceptionalToExit.get(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return exceptionalEdgeManager.getPredNodes(N);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<IBasicBlock> iterateNormalPredecessors(IBasicBlock N) {
|
||||||
|
if (N.equals(exit())) {
|
||||||
|
return new FilterIterator<IBasicBlock>(iterateNodes(), new Filter() {
|
||||||
|
public boolean accepts(Object o) {
|
||||||
|
int i = getNumber((IBasicBlock) o);
|
||||||
|
return normalToExit.get(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
int number = getNumber(N);
|
||||||
|
if (number > 0 && fallThru.get(number - 1)) {
|
||||||
|
return new IteratorPlusOne<IBasicBlock>(normalEdgeManager.getPredNodes(N), getNode(number - 1));
|
||||||
|
} else {
|
||||||
|
return normalEdgeManager.getPredNodes(N);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterator<IBasicBlock> iterateNormalSuccessors(int number) {
|
||||||
|
if (fallThru.get(number)) {
|
||||||
|
if (normalToExit.get(number)) {
|
||||||
|
return new IteratorPlusTwo<IBasicBlock>(normalEdgeManager.getSuccNodes(number), getNode(number + 1), exit());
|
||||||
|
} else {
|
||||||
|
return new IteratorPlusOne<IBasicBlock>(normalEdgeManager.getSuccNodes(number), getNode(number + 1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (normalToExit.get(number)) {
|
||||||
|
return new IteratorPlusOne<IBasicBlock>(normalEdgeManager.getSuccNodes(number), exit());
|
||||||
|
} else {
|
||||||
|
return normalEdgeManager.getSuccNodes(number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterator<IBasicBlock> iterateNormalSuccessorsWithoutExit(int number) {
|
||||||
|
if (fallThru.get(number)) {
|
||||||
|
return new IteratorPlusOne<IBasicBlock>(normalEdgeManager.getSuccNodes(number), getNode(number + 1));
|
||||||
|
} else {
|
||||||
|
return normalEdgeManager.getSuccNodes(number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param n
|
||||||
|
*/
|
||||||
|
public void addNode(IBasicBlock n) {
|
||||||
|
nodeManager.addNode(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxNumber() {
|
||||||
|
return nodeManager.getMaxNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IBasicBlock getNode(int number) {
|
||||||
|
return nodeManager.getNode(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumber(IBasicBlock N) {
|
||||||
|
return nodeManager.getNumber(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfNodes() {
|
||||||
|
return nodeManager.getNumberOfNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<IBasicBlock> iterateNodes() {
|
||||||
|
return nodeManager.iterateNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param src
|
||||||
|
* @param dst
|
||||||
|
*/
|
||||||
|
public void addEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
Assertions.UNREACHABLE("Don't call me .. use addNormalEdge or addExceptionalEdge");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean hasEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
int x = getNumber(src);
|
||||||
|
if (dst.equals(exit())) {
|
||||||
|
return normalToExit.get(x) || exceptionalToExit.get(x);
|
||||||
|
} else if (getNumber(dst) == (x + 1) && fallThru.get(x)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return normalEdgeManager.hasEdge(src, dst) || exceptionalEdgeManager.hasEdge(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasExceptionalEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
int x = getNumber(src);
|
||||||
|
if (dst.equals(exit())) {
|
||||||
|
return exceptionalToExit.get(x);
|
||||||
|
}
|
||||||
|
return exceptionalEdgeManager.hasEdge(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNormalEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
int x = getNumber(src);
|
||||||
|
if (dst.equals(exit())) {
|
||||||
|
return normalToExit.get(x);
|
||||||
|
} else if (getNumber(dst) == (x + 1) && fallThru.get(x)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return normalEdgeManager.hasEdge(src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param src
|
||||||
|
* @param dst
|
||||||
|
*/
|
||||||
|
public void addNormalEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
if (dst.equals(exit())) {
|
||||||
|
normalToExit.set(getNumber(src));
|
||||||
|
} else if (getNumber(dst) == (getNumber(src) + 1)) {
|
||||||
|
fallThru.set(getNumber(src));
|
||||||
|
} else {
|
||||||
|
normalEdgeManager.addEdge(src, dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param src
|
||||||
|
* @param dst
|
||||||
|
*/
|
||||||
|
public void addExceptionalEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
if (dst.equals(exit())) {
|
||||||
|
exceptionalToExit.set(getNumber(src));
|
||||||
|
} else {
|
||||||
|
exceptionalEdgeManager.addEdge(src, dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.Graph#removeNode(com.ibm.wala.util.graph.Node)
|
||||||
|
*/
|
||||||
|
public void removeNodeAndEdges(IBasicBlock N) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NodeManager#remove(com.ibm.wala.util.graph.Node)
|
||||||
|
*/
|
||||||
|
public void removeNode(IBasicBlock n) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NodeManager#containsNode(com.ibm.wala.util.graph.Node)
|
||||||
|
*/
|
||||||
|
public boolean containsNode(IBasicBlock N) {
|
||||||
|
return nodeManager.containsNode(N);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer s = new StringBuffer("");
|
||||||
|
for (Iterator it = iterateNodes(); it.hasNext();) {
|
||||||
|
IBasicBlock bb = (IBasicBlock) it.next();
|
||||||
|
s.append("BB").append(getNumber(bb)).append("\n");
|
||||||
|
|
||||||
|
Iterator<IBasicBlock> succNodes = getSuccNodes(bb);
|
||||||
|
while (succNodes.hasNext()) {
|
||||||
|
s.append(" -> BB").append(getNumber(succNodes.next())).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* record that basic block i is a catch block
|
||||||
|
*
|
||||||
|
* @param i
|
||||||
|
*/
|
||||||
|
protected void setCatchBlock(int i) {
|
||||||
|
catchBlocks.set(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param i
|
||||||
|
* @return true iff block i is a catch block
|
||||||
|
*/
|
||||||
|
public boolean isCatchBlock(int i) {
|
||||||
|
return catchBlocks.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the catchBlocks.
|
||||||
|
*
|
||||||
|
* @return BitVector
|
||||||
|
*/
|
||||||
|
public BitVector getCatchBlocks() {
|
||||||
|
return catchBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMethod getMethod() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.EdgeManager#removeEdges(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public void removeAllIncidentEdges(IBasicBlock node) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getExceptionalSuccessors(com.ibm.wala.cfg.IBasicBlock)
|
||||||
|
*/
|
||||||
|
public Collection<IBasicBlock> getExceptionalSuccessors(IBasicBlock b) {
|
||||||
|
return new Iterator2Collection<IBasicBlock>(iterateExceptionalSuccessors(b.getNumber()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getNormalSuccessors(com.ibm.wala.cfg.IBasicBlock)
|
||||||
|
*/
|
||||||
|
public Collection<IBasicBlock> getNormalSuccessors(IBasicBlock b) {
|
||||||
|
return new Iterator2Collection<IBasicBlock>(iterateNormalSuccessors(b.getNumber()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NumberedNodeManager#iterateNodes(com.ibm.wala.util.intset.IntSet)
|
||||||
|
*/
|
||||||
|
public Iterator<IBasicBlock> iterateNodes(IntSet s) {
|
||||||
|
return new NumberedNodeIterator<IBasicBlock>(s, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void removeIncomingEdges(IBasicBlock node) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void removeOutgoingEdges(IBasicBlock node) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FixedSizeBitVector getExceptionalToExit() {
|
||||||
|
return exceptionalToExit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FixedSizeBitVector getNormalToExit() {
|
||||||
|
return normalToExit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getExceptionalPredecessors(com.ibm.wala.cfg.IBasicBlock)
|
||||||
|
*/
|
||||||
|
public Collection<IBasicBlock> getExceptionalPredecessors(IBasicBlock b) {
|
||||||
|
return new Iterator2Collection<IBasicBlock>(iterateExceptionalPredecessors(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getNormalPredecessors(com.ibm.wala.cfg.IBasicBlock)
|
||||||
|
*/
|
||||||
|
public Collection<IBasicBlock> getNormalPredecessors(IBasicBlock b) {
|
||||||
|
return new Iterator2Collection<IBasicBlock>(iterateNormalPredecessors(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public IntSet getPredNodeNumbers(IBasicBlock node) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: optimize this. (non-Javadoc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public IntSet getSuccNodeNumbers(IBasicBlock node) {
|
||||||
|
int number = getNumber(node);
|
||||||
|
IntSet s = normalEdgeManager.getSuccNodeNumbers(node);
|
||||||
|
MutableSparseIntSet result = s == null ? new MutableSparseIntSet() : new MutableSparseIntSet(s);
|
||||||
|
s = exceptionalEdgeManager.getSuccNodeNumbers(node);
|
||||||
|
if (s != null) {
|
||||||
|
result.addAll(s);
|
||||||
|
}
|
||||||
|
if (normalToExit.get(number) || exceptionalToExit.get(number)) {
|
||||||
|
result.add(exit.getNumber());
|
||||||
|
}
|
||||||
|
if (fallThru.get(number)) {
|
||||||
|
result.add(number + 1);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.cfg;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.ipa.callgraph.Context;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.ssa.IRFactory;
|
||||||
|
import com.ibm.wala.util.CacheReference;
|
||||||
|
import com.ibm.wala.util.collections.Pair;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A mapping from IMethod -> SoftReference -> ShrikeCFG
|
||||||
|
*
|
||||||
|
* This doesn't work very well ... GCs don't do such a great job with
|
||||||
|
* SoftReferences ... revamp it.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class CFGCache {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Help out the garbage collector: periodically "reset" this cache
|
||||||
|
*/
|
||||||
|
final private static int RESET_INTERVAL = 10000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapping from ShrikeCTMethodWrapper -> SoftReference -> IR
|
||||||
|
*/
|
||||||
|
private HashMap<Object, Object> dictionary = new HashMap<Object, Object>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count accesses between resets.
|
||||||
|
*/
|
||||||
|
private int resetCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The factory that actually creates new IR objects
|
||||||
|
*/
|
||||||
|
private final IRFactory factory;
|
||||||
|
|
||||||
|
public CFGCache(IRFactory factory) {
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param m
|
||||||
|
* a "normal" (bytecode-based) method
|
||||||
|
* @param warnings
|
||||||
|
* an option to track analysis warnings
|
||||||
|
* @return an IR for m, built according to the specified options. null if m is
|
||||||
|
* abstract or native.
|
||||||
|
*/
|
||||||
|
public synchronized ControlFlowGraph findOrCreate(IMethod m, Context C, ClassHierarchy cha, WarningSet warnings) {
|
||||||
|
|
||||||
|
if (m.isAbstract() || m.isNative()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
processResetLogic(m);
|
||||||
|
|
||||||
|
Pair<IMethod,Context> p = new Pair<IMethod,Context>(m, C);
|
||||||
|
Object ref = dictionary.get(p);
|
||||||
|
if (ref == null || CacheReference.get(ref) == null) {
|
||||||
|
ControlFlowGraph cfg = factory.makeCFG(m, C, cha, warnings);
|
||||||
|
ref = CacheReference.make(cfg);
|
||||||
|
dictionary.put(p, ref);
|
||||||
|
return cfg;
|
||||||
|
} else {
|
||||||
|
ControlFlowGraph cfg = (ControlFlowGraph) CacheReference.get(ref);
|
||||||
|
return (cfg == null) ? findOrCreate(m, C, cha, warnings) : cfg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processResetLogic(IMethod m) {
|
||||||
|
resetCount++;
|
||||||
|
if (resetCount == RESET_INTERVAL) {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The existence of this is unfortunate.
|
||||||
|
*/
|
||||||
|
public void wipe() {
|
||||||
|
dictionary = new HashMap<Object, Object>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clear out null refs
|
||||||
|
*/
|
||||||
|
private void reset() {
|
||||||
|
resetCount = 0;
|
||||||
|
Map<Object, Object> oldDictionary = dictionary;
|
||||||
|
dictionary = new HashMap<Object, Object>();
|
||||||
|
|
||||||
|
for (Iterator it = oldDictionary.entrySet().iterator(); it.hasNext();) {
|
||||||
|
Map.Entry e = (Map.Entry) it.next();
|
||||||
|
Object key = e.getKey();
|
||||||
|
Object val = e.getValue();
|
||||||
|
if (CacheReference.get(val) != null) {
|
||||||
|
dictionary.put(key, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidate cached information relating to a method
|
||||||
|
*
|
||||||
|
* @param method
|
||||||
|
*/
|
||||||
|
public void invalidate(IMethod method, Context C) {
|
||||||
|
dictionary.remove(new Pair<IMethod,Context>(method, C));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.cfg;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IClass;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.ssa.IR;
|
||||||
|
import com.ibm.wala.ssa.SSACFG;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInvokeInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAReturnInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAThrowInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSACFG.ExceptionHandlerBasicBlock;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.Exceptions;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.graph.Graph;
|
||||||
|
import com.ibm.wala.util.graph.impl.SlowSparseNumberedGraph;
|
||||||
|
import com.ibm.wala.util.warnings.WalaException;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class to remove edges to exit() from a CFG
|
||||||
|
*
|
||||||
|
* @author Stephen Fink
|
||||||
|
*/
|
||||||
|
public class CFGSanitizer {
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
public static Graph<IBasicBlock> sanitize(IR ir, ClassHierarchy cha) throws WalaException {
|
||||||
|
|
||||||
|
Assertions._assert(ir != null, "IR is null");
|
||||||
|
|
||||||
|
ControlFlowGraph cfg = ir.getControlFlowGraph();
|
||||||
|
Graph<IBasicBlock> G = new SlowSparseNumberedGraph<IBasicBlock>();
|
||||||
|
// add all nodes to the graph
|
||||||
|
for (Iterator<? extends IBasicBlock> it = cfg.iterateNodes(); it.hasNext();) {
|
||||||
|
G.addNode(it.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
// add all edges to the graph, except those that go to exit
|
||||||
|
for (Iterator it = cfg.iterateNodes(); it.hasNext();) {
|
||||||
|
IBasicBlock b = (IBasicBlock) it.next();
|
||||||
|
for (Iterator it2 = cfg.getSuccNodes(b); it2.hasNext();) {
|
||||||
|
IBasicBlock b2 = (IBasicBlock) it2.next();
|
||||||
|
|
||||||
|
if (!b2.isExitBlock()) {
|
||||||
|
G.addEdge(b, b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now add edges to exit, ignoring undeclared exceptions
|
||||||
|
IBasicBlock exit = cfg.exit();
|
||||||
|
|
||||||
|
for (Iterator it = cfg.getPredNodes(exit); it.hasNext();) {
|
||||||
|
// for each predecessor of exit ...
|
||||||
|
IBasicBlock b = (IBasicBlock) it.next();
|
||||||
|
|
||||||
|
SSAInstruction s = ir.getInstructions()[b.getLastInstructionIndex()];
|
||||||
|
if (s == null) {
|
||||||
|
// TODO: this shouldn't happen?
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (s instanceof SSAReturnInstruction || s instanceof SSAThrowInstruction) {
|
||||||
|
// return or athrow: add edge to exit
|
||||||
|
G.addEdge(b, exit);
|
||||||
|
} else {
|
||||||
|
// compute types of exceptions the pei may throw
|
||||||
|
TypeReference[] exceptions = computeExceptions(cha, s);
|
||||||
|
// remove any exceptions that are caught by catch blocks
|
||||||
|
for (Iterator it2 = cfg.getSuccNodes(b); it2.hasNext();) {
|
||||||
|
IBasicBlock c = (IBasicBlock) it2.next();
|
||||||
|
|
||||||
|
if (c.isCatchBlock()) {
|
||||||
|
SSACFG.ExceptionHandlerBasicBlock cb = (ExceptionHandlerBasicBlock) c;
|
||||||
|
|
||||||
|
for (Iterator it3 = cb.getCaughtExceptionTypes(); it3.hasNext();) {
|
||||||
|
TypeReference ex = (TypeReference) it3.next();
|
||||||
|
IClass exClass = cha.lookupClass(ex);
|
||||||
|
if (exClass == null) {
|
||||||
|
throw new WalaException("failed to find " + ex);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < exceptions.length; i++) {
|
||||||
|
if (exceptions[i] != null) {
|
||||||
|
IClass exi = cha.lookupClass(exceptions[i]);
|
||||||
|
if (exi == null) {
|
||||||
|
throw new WalaException("failed to find " + exceptions[i]);
|
||||||
|
}
|
||||||
|
if (cha.isSubclassOf(exi, exClass)) {
|
||||||
|
exceptions[i] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check the remaining uncaught exceptions
|
||||||
|
TypeReference[] declared = ir.getMethod().getDeclaredExceptions();
|
||||||
|
if (declared != null && exceptions != null) {
|
||||||
|
for (int i = 0; i < exceptions.length; i++) {
|
||||||
|
boolean isDeclared = false;
|
||||||
|
if (exceptions[i] != null) {
|
||||||
|
IClass exi = cha.lookupClass(exceptions[i]);
|
||||||
|
if (exi == null) {
|
||||||
|
throw new WalaException("failed to find " + exceptions[i]);
|
||||||
|
}
|
||||||
|
for (int j = 0; j < declared.length; j++) {
|
||||||
|
IClass dc = cha.lookupClass(declared[j]);
|
||||||
|
if (dc == null) {
|
||||||
|
throw new WalaException("failed to find " + declared[j]);
|
||||||
|
}
|
||||||
|
if (cha.isSubclassOf(exi, dc)) {
|
||||||
|
isDeclared = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isDeclared) {
|
||||||
|
// found a declared exceptional edge
|
||||||
|
G.addEdge(b, exit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return G;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TypeReference[] computeExceptions(ClassHierarchy cha, SSAInstruction s) {
|
||||||
|
Collection c = null;
|
||||||
|
if (s instanceof SSAInvokeInstruction) {
|
||||||
|
SSAInvokeInstruction call = (SSAInvokeInstruction) s;
|
||||||
|
c = Exceptions.inferInvokeExceptions(call.getDeclaredTarget(), cha, new WarningSet());
|
||||||
|
} else {
|
||||||
|
c = s.getExceptionTypes();
|
||||||
|
}
|
||||||
|
if (c == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
TypeReference[] exceptions = new TypeReference[c.size()];
|
||||||
|
Iterator it = c.iterator();
|
||||||
|
for (int i = 0; i < exceptions.length; i++) {
|
||||||
|
exceptions[i] = (TypeReference) it.next();
|
||||||
|
}
|
||||||
|
return exceptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // CFGSanitizerImpl
|
|
@ -0,0 +1,102 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.cfg;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.shrikeBT.IInstruction;
|
||||||
|
import com.ibm.wala.util.graph.NumberedGraph;
|
||||||
|
import com.ibm.wala.util.intset.BitVector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface that is common to the Shrike and SSA CFG implementations.
|
||||||
|
*
|
||||||
|
* @author cahoon
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public interface ControlFlowGraph extends NumberedGraph<IBasicBlock> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the entry basic block in the CFG
|
||||||
|
*/
|
||||||
|
public IBasicBlock entry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the synthetic exit block for the cfg
|
||||||
|
*/
|
||||||
|
public IBasicBlock exit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the indices of the catch blocks, as a bit vector
|
||||||
|
*/
|
||||||
|
public BitVector getCatchBlocks();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param index
|
||||||
|
* an instruction index
|
||||||
|
* @return the basic block which contains this instruction.
|
||||||
|
*/
|
||||||
|
public IBasicBlock getBlockForInstruction(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the instructions of this CFG, as an array.
|
||||||
|
*/
|
||||||
|
IInstruction[] getInstructions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param index
|
||||||
|
* an instruction index
|
||||||
|
* @return the program counter (bytecode index) corresponding to that
|
||||||
|
* instruction
|
||||||
|
*/
|
||||||
|
public int getProgramCounter(int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the Method this CFG represents
|
||||||
|
*/
|
||||||
|
public IMethod getMethod();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The order of blocks returned should be arbitrary but deterministic.
|
||||||
|
*
|
||||||
|
* @param b
|
||||||
|
* @return the basic blocks which may be reached from b via exceptional
|
||||||
|
* control flow
|
||||||
|
*/
|
||||||
|
public Collection<IBasicBlock> getExceptionalSuccessors(IBasicBlock b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The order of blocks returned should be arbitrary but deterministic.
|
||||||
|
* @param b
|
||||||
|
* @return the basic blocks which may be reached from b via normal control
|
||||||
|
* flow
|
||||||
|
*/
|
||||||
|
public Collection<IBasicBlock> getNormalSuccessors(IBasicBlock b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The order of blocks returned should be arbitrary but deterministic.
|
||||||
|
*
|
||||||
|
* @param b
|
||||||
|
* @return the basic blocks from which b may be reached via exceptional
|
||||||
|
* control flow
|
||||||
|
*/
|
||||||
|
public Collection<IBasicBlock> getExceptionalPredecessors(IBasicBlock b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The order of blocks returned should be arbitrary but deterministic.
|
||||||
|
*
|
||||||
|
* @param b
|
||||||
|
* @return the basic blocks from which b may be reached via normal
|
||||||
|
* control flow
|
||||||
|
*/
|
||||||
|
public Collection<IBasicBlock> getNormalPredecessors(IBasicBlock b);
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.cfg;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.shrikeBT.IInstruction;
|
||||||
|
import com.ibm.wala.util.graph.INodeWithNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for a basic block in a control flow graph.
|
||||||
|
* @author cahoon
|
||||||
|
* @author Stephen Fink
|
||||||
|
*/
|
||||||
|
public interface IBasicBlock extends INodeWithNumber {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the index of the first instruction in the basic block. The value
|
||||||
|
* is an index into the instruction array that contains all the instructions
|
||||||
|
* for the method.
|
||||||
|
*
|
||||||
|
* If the result is < 0, the block has no instructions
|
||||||
|
*
|
||||||
|
* @return the instruction index for the first instruction in the basic block.
|
||||||
|
*/
|
||||||
|
public int getFirstInstructionIndex();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the index of the last instruction in the basic block. The value
|
||||||
|
* is an index into the instruction array that contains all the instructions
|
||||||
|
* for the method.
|
||||||
|
*
|
||||||
|
* If the result is < 0, the block has no instructions
|
||||||
|
*
|
||||||
|
* @return the instruction index for the last instruction in the basic block
|
||||||
|
*/
|
||||||
|
public int getLastInstructionIndex();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an Iterator of all instructions in this basic block
|
||||||
|
*/
|
||||||
|
public Iterator<? extends IInstruction> iterateAllInstructions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the basic block represents a catch block.
|
||||||
|
* @return true if the basic block represents a catch block.
|
||||||
|
*/
|
||||||
|
public boolean isCatchBlock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the basic block represents the unique exit block.
|
||||||
|
* @return true if the basic block represents the unique exit block.
|
||||||
|
*/
|
||||||
|
public boolean isExitBlock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the basic block represents the unique entry block.
|
||||||
|
* @return true if the basic block represents the unique entry block.
|
||||||
|
*/
|
||||||
|
public boolean isEntryBlock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return governing method for this block
|
||||||
|
*/
|
||||||
|
public IMethod getMethod();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Each basic block should have a unique number in its cfg
|
||||||
|
* @return the basic block's number
|
||||||
|
*/
|
||||||
|
public int getNumber();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,524 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.cfg;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.ipa.callgraph.Context;
|
||||||
|
import com.ibm.wala.shrikeBT.IInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAArrayLengthInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAArrayLoadInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAArrayStoreInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSACheckCastInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAConditionalBranchInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAGetInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAGotoInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInvokeInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAMonitorInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSANewInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAPutInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAReturnInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSASwitchInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAThrowInstruction;
|
||||||
|
import com.ibm.wala.util.collections.ArrayIterator;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.debug.Trace;
|
||||||
|
import com.ibm.wala.util.graph.GraphIntegrity;
|
||||||
|
import com.ibm.wala.util.graph.GraphIntegrity.UnsoundGraphException;
|
||||||
|
import com.ibm.wala.util.graph.impl.NodeWithNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ControlFlowGraph computed from a set of SSA instructions
|
||||||
|
*
|
||||||
|
* This is a funny CFG ... we assume that there are always fallthru edges, even
|
||||||
|
* from throws and returns.
|
||||||
|
*/
|
||||||
|
public class InducedCFG extends AbstractCFG {
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
/**
|
||||||
|
* A partial map from Instruction -> BasicBlock
|
||||||
|
*/
|
||||||
|
private final BasicBlock[] i2block;
|
||||||
|
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
private final IInstruction[] instructions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: we do not yet support induced CFGS with exception handlers.
|
||||||
|
*
|
||||||
|
* @param instructions
|
||||||
|
*/
|
||||||
|
public InducedCFG(SSAInstruction[] instructions, IMethod method, Context context) {
|
||||||
|
super(method);
|
||||||
|
this.context = context;
|
||||||
|
this.instructions = instructions;
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("compute InducedCFG: " + method);
|
||||||
|
}
|
||||||
|
i2block = new BasicBlock[instructions.length];
|
||||||
|
if (instructions.length == 0) {
|
||||||
|
makeEmptyBlocks();
|
||||||
|
} else {
|
||||||
|
makeBasicBlocks();
|
||||||
|
}
|
||||||
|
init();
|
||||||
|
computeEdges();
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
try {
|
||||||
|
GraphIntegrity.check(this);
|
||||||
|
} catch (UnsoundGraphException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return context.hashCode() ^ getMethod().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return (o instanceof InducedCFG) &&
|
||||||
|
getMethod().equals(((InducedCFG)o).getMethod()) &&
|
||||||
|
context.equals(((InducedCFG)o).context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IInstruction[] getInstructions() {
|
||||||
|
return instructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute outgoing edges in the control flow graph.
|
||||||
|
*/
|
||||||
|
private void computeEdges() {
|
||||||
|
for (Iterator it = iterateNodes(); it.hasNext();) {
|
||||||
|
BasicBlock b = (BasicBlock) it.next();
|
||||||
|
if (b.equals(exit()))
|
||||||
|
continue;
|
||||||
|
b.computeOutgoingEdges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create basic blocks for an empty method
|
||||||
|
*/
|
||||||
|
private void makeEmptyBlocks() {
|
||||||
|
BasicBlock b = new BasicBlock(-1);
|
||||||
|
addNode(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected BranchVisitor makeBranchVisitor(boolean[] r) {
|
||||||
|
return new BranchVisitor(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PEIVisitor makePEIVisitor(boolean[] r) {
|
||||||
|
return new PEIVisitor(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walk through the instructions and compute basic block boundaries.
|
||||||
|
*/
|
||||||
|
private void makeBasicBlocks() {
|
||||||
|
SSAInstruction[] instructions = (SSAInstruction[]) getInstructions();
|
||||||
|
final boolean[] r = new boolean[instructions.length];
|
||||||
|
|
||||||
|
// Compute r so r[i] == true iff instruction i begins a basic block.
|
||||||
|
// While doing so count the number of blocks.
|
||||||
|
r[0] = true;
|
||||||
|
BranchVisitor branchVisitor = makeBranchVisitor(r);
|
||||||
|
PEIVisitor peiVisitor = makePEIVisitor(r);
|
||||||
|
for (int i = 0; i < instructions.length; i++) {
|
||||||
|
if (instructions[i] != null) {
|
||||||
|
branchVisitor.setIndex(i);
|
||||||
|
instructions[i].visit(branchVisitor);
|
||||||
|
// TODO: deal with exception handlers
|
||||||
|
peiVisitor.setIndex(i);
|
||||||
|
instructions[i].visit(peiVisitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicBlock b = null;
|
||||||
|
for (int i = 0; i < r.length; i++) {
|
||||||
|
if (r[i]) {
|
||||||
|
b = new BasicBlock(i);
|
||||||
|
addNode(b);
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Add basic block " + b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i2block[i] = b;
|
||||||
|
}
|
||||||
|
// allocate the exit block
|
||||||
|
BasicBlock exit = new BasicBlock(-1);
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Add exit block " + exit);
|
||||||
|
}
|
||||||
|
addNode(exit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
* This visitor identifies basic block boundaries induced by branch
|
||||||
|
* instructions.
|
||||||
|
*/
|
||||||
|
public class BranchVisitor extends SSAInstruction.Visitor {
|
||||||
|
private boolean[] r;
|
||||||
|
|
||||||
|
protected BranchVisitor(boolean[] r) {
|
||||||
|
this.r = r;
|
||||||
|
}
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
void setIndex(int i) {
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitGoto(SSAGotoInstruction instruction) {
|
||||||
|
Assertions.UNREACHABLE("haven't implemented logic for goto yet.");
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitConditionalBranch(SSAConditionalBranchInstruction instruction) {
|
||||||
|
Assertions.UNREACHABLE("haven't implemented logic for cbranch yet.");
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitSwitch(SSASwitchInstruction instruction) {
|
||||||
|
Assertions.UNREACHABLE("haven't implemented logic for switch yet.");
|
||||||
|
breakBasicBlock();
|
||||||
|
int[] targets = instruction.getTargets();
|
||||||
|
for (int i = 0; i < targets.length; i++) {
|
||||||
|
r[targets[i]] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitReturn(SSAReturnInstruction instruction) {
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitThrow(SSAThrowInstruction instruction) {
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void breakBasicBlock() {
|
||||||
|
if (index + 1 < getInstructions().length && !r[index + 1]) {
|
||||||
|
r[index + 1] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: extend the following to deal with catch blocks. Right now
|
||||||
|
// it simply breaks basic blocks at PEIs.
|
||||||
|
public class PEIVisitor extends SSAInstruction.Visitor {
|
||||||
|
private boolean[] r;
|
||||||
|
|
||||||
|
protected PEIVisitor(boolean[] r) {
|
||||||
|
this.r = r;
|
||||||
|
}
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
void setIndex(int i) {
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void breakBasicBlock() {
|
||||||
|
if (index + 1 < getInstructions().length && !r[index + 1]) {
|
||||||
|
r[index + 1] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitArrayLength(SSAArrayLengthInstruction instruction) {
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitArrayLoad(SSAArrayLoadInstruction instruction) {
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitArrayStore(SSAArrayStoreInstruction instruction) {
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitCheckCast(SSACheckCastInstruction instruction) {
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitGet(SSAGetInstruction instruction) {
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitInvoke(SSAInvokeInstruction instruction) {
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitMonitor(SSAMonitorInstruction instruction) {
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitNew(SSANewInstruction instruction) {
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitPut(SSAPutInstruction instruction) {
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitThrow(com.ibm.wala.ssa.SSAThrowInstruction instruction) {
|
||||||
|
breakBasicBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getBlockForInstruction(int)
|
||||||
|
*/
|
||||||
|
public IBasicBlock getBlockForInstruction(int index) {
|
||||||
|
if (i2block[index] == null) {
|
||||||
|
Assertions.productionAssertion(false, "unexpected null for " + index);
|
||||||
|
}
|
||||||
|
return i2block[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getExceptionHandlers()
|
||||||
|
*/
|
||||||
|
public Set getExceptionHandlers() {
|
||||||
|
// TODO: support exception handlers
|
||||||
|
return Collections.EMPTY_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: share some common parts of this implementation with the ShrikeCFG
|
||||||
|
// implementation! right now it's clone-and-owned :(
|
||||||
|
private class BasicBlock extends NodeWithNumber implements IBasicBlock {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object arg0) {
|
||||||
|
if (getClass().equals(arg0.getClass())) {
|
||||||
|
BasicBlock other = (BasicBlock) arg0;
|
||||||
|
return start == other.start && getMethod().equals(other.getMethod());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private final int start;
|
||||||
|
|
||||||
|
BasicBlock(int start) {
|
||||||
|
this.start = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add any exceptional edges generated by the last instruction in a basic
|
||||||
|
* block.
|
||||||
|
*
|
||||||
|
* @param last
|
||||||
|
* the last instruction in a basic block.
|
||||||
|
*/
|
||||||
|
private void addExceptionalEdges(SSAInstruction last) {
|
||||||
|
if (last.isPEI()) {
|
||||||
|
// we don't currently model catch blocks here ... instead just link
|
||||||
|
// to the exit block
|
||||||
|
addExceptionalEdgeTo((BasicBlock) exit());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param b
|
||||||
|
*/
|
||||||
|
private void addNormalEdgeTo(BasicBlock b) {
|
||||||
|
addNormalEdge(this, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param b
|
||||||
|
*/
|
||||||
|
private void addExceptionalEdgeTo(BasicBlock b) {
|
||||||
|
addExceptionalEdge(this, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method computeOutgoingEdges.
|
||||||
|
*/
|
||||||
|
private void computeOutgoingEdges() {
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Block " + this + ": computeOutgoingEdges()");
|
||||||
|
}
|
||||||
|
// TODO: we don't currently model branches
|
||||||
|
|
||||||
|
SSAInstruction last = (SSAInstruction) getInstructions()[getLastInstructionIndex()];
|
||||||
|
addExceptionalEdges(last);
|
||||||
|
// this CFG is odd in that we assume fallthru might always
|
||||||
|
// happen .. this is because I'm too lazy to code control
|
||||||
|
// flow in all method summaries yet.
|
||||||
|
if (true) {
|
||||||
|
// if (last.isFallThrough()) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Add fallthru to " + getNode(getGraphNodeId() + 1));
|
||||||
|
}
|
||||||
|
addNormalEdgeTo((BasicBlock) getNode(getGraphNodeId() + 1));
|
||||||
|
}
|
||||||
|
if (last instanceof SSAReturnInstruction) {
|
||||||
|
// link each return instrution to the exit block.
|
||||||
|
BasicBlock exit = (BasicBlock) exit();
|
||||||
|
addNormalEdgeTo(exit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#getFirstInstructionIndex()
|
||||||
|
*/
|
||||||
|
public int getFirstInstructionIndex() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getLastInstructionIndex.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public int getLastInstructionIndex() {
|
||||||
|
int exitNumber = InducedCFG.this.getNumber(exit());
|
||||||
|
if (getGraphNodeId() == exitNumber) {
|
||||||
|
// this is the exit block
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
if (getGraphNodeId() == (exitNumber - 1)) {
|
||||||
|
// this is the last non-exit block
|
||||||
|
return getInstructions().length - 1;
|
||||||
|
} else {
|
||||||
|
BasicBlock next = (BasicBlock) getNode(getGraphNodeId() + 1);
|
||||||
|
return next.getFirstInstructionIndex() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#isCatchBlock()
|
||||||
|
*/
|
||||||
|
public boolean isCatchBlock() {
|
||||||
|
// TODO: support induced CFG with catch blocks.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return 1153 * getGraphNodeId() + getMethod().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "BB[Induced]" + getNumber() + " - " + getMethod().getSignature();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#isExitBlock()
|
||||||
|
*/
|
||||||
|
public boolean isExitBlock() {
|
||||||
|
return getLastInstructionIndex() == -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#isEntryBlock()
|
||||||
|
*/
|
||||||
|
public boolean isEntryBlock() {
|
||||||
|
return getNumber() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#getMethod()
|
||||||
|
*/
|
||||||
|
public IMethod getMethod() {
|
||||||
|
return InducedCFG.this.getMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean endsInPEI() {
|
||||||
|
return getInstructions()[getLastInstructionIndex()].isPEI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean endsInReturn() {
|
||||||
|
return getInstructions()[getLastInstructionIndex()] instanceof SSAReturnInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#getNumber()
|
||||||
|
*/
|
||||||
|
public int getNumber() {
|
||||||
|
return InducedCFG.this.getNumber(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<IInstruction> iterateAllInstructions() {
|
||||||
|
return new ArrayIterator<IInstruction>(getInstructions(),getFirstInstructionIndex(),getLastInstructionIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer s = new StringBuffer("");
|
||||||
|
for (Iterator it = iterateNodes(); it.hasNext();) {
|
||||||
|
BasicBlock bb = (BasicBlock) it.next();
|
||||||
|
s.append("BB").append(getNumber(bb)).append("\n");
|
||||||
|
for (int j = bb.getFirstInstructionIndex(); j <= bb.getLastInstructionIndex(); j++) {
|
||||||
|
s.append(" ").append(j).append(" ").append(getInstructions()[j]).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<IBasicBlock> succNodes = getSuccNodes(bb);
|
||||||
|
while (succNodes.hasNext()) {
|
||||||
|
s.append(" -> BB").append(getNumber(succNodes.next())).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since this CFG is synthetic, for now we assume the instruction index is the
|
||||||
|
* same as the program counter
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getProgramCounter(int)
|
||||||
|
*/
|
||||||
|
public int getProgramCounter(int index) {
|
||||||
|
if (getInstructions()[index] instanceof SSAInvokeInstruction) {
|
||||||
|
return ((SSAInvokeInstruction) getInstructions()[index]).getCallSite().getProgramCounter();
|
||||||
|
} else {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,581 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.cfg;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IClass;
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.classLoader.ShrikeCTMethodWrapper;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.shrikeBT.ExceptionHandler;
|
||||||
|
import com.ibm.wala.shrikeBT.IInstruction;
|
||||||
|
import com.ibm.wala.shrikeBT.Instruction;
|
||||||
|
import com.ibm.wala.shrikeBT.ReturnInstruction;
|
||||||
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.Exceptions;
|
||||||
|
import com.ibm.wala.util.ShrikeUtil;
|
||||||
|
import com.ibm.wala.util.collections.ArrayIterator;
|
||||||
|
import com.ibm.wala.util.collections.HashSetFactory;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.debug.Trace;
|
||||||
|
import com.ibm.wala.util.graph.impl.NodeWithNumber;
|
||||||
|
import com.ibm.wala.util.warnings.Warning;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A graph of basic blocks.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
* @author roca
|
||||||
|
*/
|
||||||
|
public class ShrikeCFG extends AbstractCFG {
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
|
private int[] instruction2Block;
|
||||||
|
|
||||||
|
private final WarningSet warnings;
|
||||||
|
|
||||||
|
private final ClassHierarchy cha;
|
||||||
|
|
||||||
|
private final ShrikeCTMethodWrapper method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache this here for efficiency
|
||||||
|
*/
|
||||||
|
private final int hashBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of Shrike ExceptionHandler objects that cover this method.
|
||||||
|
*/
|
||||||
|
private Set<ExceptionHandler> exceptionHandlers = HashSetFactory.make(10);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for ControlFlowGraph.
|
||||||
|
*/
|
||||||
|
public ShrikeCFG(ShrikeCTMethodWrapper method, WarningSet warnings, ClassHierarchy cha) {
|
||||||
|
super(method);
|
||||||
|
this.method = method;
|
||||||
|
this.hashBase = method.hashCode() * 9967;
|
||||||
|
this.warnings = warnings;
|
||||||
|
this.cha = cha;
|
||||||
|
makeBasicBlocks();
|
||||||
|
init();
|
||||||
|
computeI2BMapping();
|
||||||
|
computeEdges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return 9511 * getMethod().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return (o instanceof ShrikeCFG) && getMethod().equals(((ShrikeCFG) o).getMethod());
|
||||||
|
}
|
||||||
|
|
||||||
|
public IInstruction[] getInstructions() {
|
||||||
|
try {
|
||||||
|
return method.getInstructions();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute a mapping from instruction to basic block. Also, compute the blocks
|
||||||
|
* that end with a 'normal' return.
|
||||||
|
*/
|
||||||
|
private void computeI2BMapping() {
|
||||||
|
instruction2Block = new int[getInstructions().length];
|
||||||
|
for (Iterator it = iterateNodes(); it.hasNext();) {
|
||||||
|
final BasicBlock b = (BasicBlock) it.next();
|
||||||
|
for (int j = b.getFirstInstructionIndex(); j <= b.getLastInstructionIndex(); j++) {
|
||||||
|
instruction2Block[j] = getNumber(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute outgoing edges in the control flow graph.
|
||||||
|
*/
|
||||||
|
private void computeEdges() {
|
||||||
|
for (Iterator it = iterateNodes(); it.hasNext();) {
|
||||||
|
BasicBlock b = (BasicBlock) it.next();
|
||||||
|
if (b.equals(exit())) {
|
||||||
|
continue;
|
||||||
|
} else if (b.equals(entry())) {
|
||||||
|
addNormalEdge(b, getBlockForInstruction(0));
|
||||||
|
} else {
|
||||||
|
b.computeOutgoingEdges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getBasicBlockStarts, stolen from ShrikeBT verifier
|
||||||
|
*/
|
||||||
|
private void makeBasicBlocks() {
|
||||||
|
ExceptionHandler[][] handlers;
|
||||||
|
try {
|
||||||
|
handlers = method.getHandlers();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
handlers = null;
|
||||||
|
}
|
||||||
|
boolean[] r = new boolean[getInstructions().length];
|
||||||
|
boolean[] catchers = new boolean[getInstructions().length];
|
||||||
|
// we initially start with both the entry and exit block.
|
||||||
|
int blockCount = 2;
|
||||||
|
|
||||||
|
// Compute r so r[i] == true iff instruction i begins a basic block.
|
||||||
|
// While doing so count the number of blocks.
|
||||||
|
r[0] = true;
|
||||||
|
Instruction[] instructions = (Instruction[]) getInstructions();
|
||||||
|
for (int i = 0; i < instructions.length; i++) {
|
||||||
|
int[] targets = instructions[i].getBranchTargets();
|
||||||
|
|
||||||
|
// if there are any targets, then break the basic block here.
|
||||||
|
// also break the basic block after a return
|
||||||
|
if (targets.length > 0 || !instructions[i].isFallThrough()) {
|
||||||
|
if (i + 1 < instructions.length && !r[i + 1]) {
|
||||||
|
r[i + 1] = true;
|
||||||
|
blockCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < targets.length; j++) {
|
||||||
|
if (!r[targets[j]]) {
|
||||||
|
r[targets[j]] = true;
|
||||||
|
blockCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Exceptions.isPEI(instructions[i])) {
|
||||||
|
ExceptionHandler[] hs = handlers[i];
|
||||||
|
// break the basic block here.
|
||||||
|
if (i + 1 < instructions.length && !r[i + 1]) {
|
||||||
|
r[i + 1] = true;
|
||||||
|
blockCount++;
|
||||||
|
}
|
||||||
|
if (hs != null && hs.length > 0) {
|
||||||
|
for (int j = 0; j < hs.length; j++) {
|
||||||
|
exceptionHandlers.add(hs[j]);
|
||||||
|
if (!r[hs[j].getHandler()]) {
|
||||||
|
// we have not discovered the catch block yet.
|
||||||
|
// form a new basic block
|
||||||
|
r[hs[j].getHandler()] = true;
|
||||||
|
blockCount++;
|
||||||
|
}
|
||||||
|
catchers[hs[j].getHandler()] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicBlock entry = new BasicBlock(-1);
|
||||||
|
addNode(entry);
|
||||||
|
|
||||||
|
int j = 1;
|
||||||
|
for (int i = 0; i < r.length; i++) {
|
||||||
|
if (r[i]) {
|
||||||
|
BasicBlock b = new BasicBlock(i);
|
||||||
|
addNode(b);
|
||||||
|
if (catchers[i]) {
|
||||||
|
setCatchBlock(j);
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicBlock exit = new BasicBlock(-1);
|
||||||
|
addNode(exit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an instruction's basic block in the CFG given the index of the
|
||||||
|
* instruction in the CFG's instruction array.
|
||||||
|
*/
|
||||||
|
public IBasicBlock getBlockForInstruction(int index) {
|
||||||
|
return (IBasicBlock) getNode(instruction2Block[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class BasicBlock extends NodeWithNumber implements IBasicBlock {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of the ShrikeBT instruction that begins this block.
|
||||||
|
*/
|
||||||
|
private int startIndex;
|
||||||
|
|
||||||
|
public BasicBlock(int startIndex) {
|
||||||
|
this.startIndex = startIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCatchBlock() {
|
||||||
|
return ShrikeCFG.this.isCatchBlock(getNumber());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method computeOutgoingEdges.
|
||||||
|
*/
|
||||||
|
private void computeOutgoingEdges() {
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Block " + this + ": computeOutgoingEdges()");
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction last = (Instruction) getInstructions()[getLastInstructionIndex()];
|
||||||
|
int[] targets = last.getBranchTargets();
|
||||||
|
for (int i = 0; i < targets.length; i++) {
|
||||||
|
BasicBlock b = (BasicBlock) getBlockForInstruction(targets[i]);
|
||||||
|
addNormalEdgeTo(b);
|
||||||
|
}
|
||||||
|
addExceptionalEdges(last);
|
||||||
|
if (last.isFallThrough()) {
|
||||||
|
BasicBlock next = (BasicBlock) getNode(getNumber() + 1);
|
||||||
|
addNormalEdgeTo(next);
|
||||||
|
}
|
||||||
|
if (last instanceof ReturnInstruction) {
|
||||||
|
// link each return instrution to the exit block.
|
||||||
|
BasicBlock exit = (BasicBlock) exit();
|
||||||
|
addNormalEdgeTo(exit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add any exceptional edges generated by the last instruction in a basic
|
||||||
|
* block.
|
||||||
|
*
|
||||||
|
* @param last
|
||||||
|
* the last instruction in a basic block.
|
||||||
|
*/
|
||||||
|
private void addExceptionalEdges(Instruction last) {
|
||||||
|
if (Exceptions.isPEI(last)) {
|
||||||
|
Collection<TypeReference> exceptionTypes = null;
|
||||||
|
boolean goToAllHandlers = false;
|
||||||
|
|
||||||
|
ExceptionHandler[] hs = getExceptionHandlers();
|
||||||
|
if (last.getOpcode() == OP_athrow) {
|
||||||
|
// this class does not have the type information needed
|
||||||
|
// to determine what the athrow throws. So, add an
|
||||||
|
// edge to all reachable handlers. Better information can
|
||||||
|
// be obtained later with SSA type propagation.
|
||||||
|
// TODO: consider pruning to only the exception types that
|
||||||
|
// this method either catches or allocates, since these are
|
||||||
|
// the only types that can flow to an athrow.
|
||||||
|
goToAllHandlers = true;
|
||||||
|
} else {
|
||||||
|
if (hs != null && hs.length > 0) {
|
||||||
|
exceptionTypes = Exceptions.getExceptionTypes(getMethod().getDeclaringClass().getReference().getClassLoader(), last,
|
||||||
|
cha, warnings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hs != null && hs.length > 0) {
|
||||||
|
// found a handler for this PEI
|
||||||
|
|
||||||
|
// create a mutable copy
|
||||||
|
if (!goToAllHandlers) {
|
||||||
|
exceptionTypes = new HashSet<TypeReference>(exceptionTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < hs.length; j++) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println(" handler " + hs[j]);
|
||||||
|
}
|
||||||
|
BasicBlock b = (BasicBlock) getBlockForInstruction(hs[j].getHandler());
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println(" target " + b);
|
||||||
|
}
|
||||||
|
if (goToAllHandlers) {
|
||||||
|
// add an edge to the catch block.
|
||||||
|
addExceptionalEdgeTo(b);
|
||||||
|
} else {
|
||||||
|
TypeReference caughtException = null;
|
||||||
|
|
||||||
|
if (hs[j].getCatchClass() != null) {
|
||||||
|
ClassLoaderReference loader = ShrikeCFG.this.getMethod().getDeclaringClass().getReference().getClassLoader();
|
||||||
|
caughtException = ShrikeUtil.makeTypeReference(loader, hs[j].getCatchClass());
|
||||||
|
IClass caughtClass = cha.lookupClass(caughtException);
|
||||||
|
if (caughtClass == null) {
|
||||||
|
// conservatively add the edge, and raise a warning
|
||||||
|
addExceptionalEdgeTo(b);
|
||||||
|
warnings.add(FailedExceptionResolutionWarning.create(caughtException));
|
||||||
|
// null out caughtException, to avoid attempting to process it
|
||||||
|
caughtException = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (caughtException == null) {
|
||||||
|
// this means that the handler catches all exceptions.
|
||||||
|
// add the edge and null out all types
|
||||||
|
addExceptionalEdgeTo(b);
|
||||||
|
exceptionTypes.clear();
|
||||||
|
} else {
|
||||||
|
// the set "caught" should be the set of exceptions that MUST have been caught
|
||||||
|
// by the handlers in scope
|
||||||
|
HashSet<TypeReference> caught = HashSetFactory.make(exceptionTypes.size());
|
||||||
|
// check if we should add an edge to the catch block.
|
||||||
|
for (Iterator it = exceptionTypes.iterator(); it.hasNext();) {
|
||||||
|
TypeReference t = (TypeReference) it.next();
|
||||||
|
if (t != null) {
|
||||||
|
IClass klass = cha.lookupClass(t);
|
||||||
|
if (klass == null) {
|
||||||
|
warnings.add(FailedExceptionResolutionWarning.create(caughtException));
|
||||||
|
// conservatively add an edge
|
||||||
|
addExceptionalEdgeTo(b);
|
||||||
|
} else {
|
||||||
|
IClass caughtClass = cha.lookupClass(caughtException);
|
||||||
|
if (cha.isSubclassOf(klass, caughtClass) || cha.isSubclassOf(caughtClass, klass)) {
|
||||||
|
// add the edge and null out the type from the array
|
||||||
|
addExceptionalEdgeTo(b);
|
||||||
|
if (cha.isSubclassOf( klass, caughtClass )) {
|
||||||
|
caught.add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exceptionTypes.removeAll(caught);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if needed, add an edge to the exit block.
|
||||||
|
if (exceptionTypes == null || !exceptionTypes.isEmpty()) {
|
||||||
|
BasicBlock exit = (BasicBlock) exit();
|
||||||
|
addExceptionalEdgeTo(exit);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// found no handler for this PEI ... link to the exit block.
|
||||||
|
BasicBlock exit = (BasicBlock) exit();
|
||||||
|
addExceptionalEdgeTo(exit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExceptionHandler[] getExceptionHandlers() {
|
||||||
|
ExceptionHandler[][] handlers;
|
||||||
|
try {
|
||||||
|
handlers = method.getHandlers();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
handlers = null;
|
||||||
|
}
|
||||||
|
ExceptionHandler[] hs = handlers[getLastInstructionIndex()];
|
||||||
|
return hs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return true iff exception extends RuntimeException or Error
|
||||||
|
// */
|
||||||
|
// private boolean isUndeclaredType(IClass exception) {
|
||||||
|
// IClass re = cha.lookupClass(TypeReference.JavaLangRuntimeException);
|
||||||
|
// IClass error = cha.lookupClass(TypeReference.JavaLangError);
|
||||||
|
// boolean result = cha.isSubclassOf(exception, re) ||
|
||||||
|
// cha.isSubclassOf(exception, error);
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param b
|
||||||
|
*/
|
||||||
|
private void addNormalEdgeTo(BasicBlock b) {
|
||||||
|
addNormalEdge(this, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param b
|
||||||
|
*/
|
||||||
|
private void addExceptionalEdgeTo(BasicBlock b) {
|
||||||
|
addExceptionalEdge(this, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getLastInstructionIndex.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public int getLastInstructionIndex() {
|
||||||
|
|
||||||
|
if (this == entry() || this == exit()) {
|
||||||
|
// these are the special end blocks
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
if (getNumber() == (getMaxNumber() - 1)) {
|
||||||
|
// this is the last non-exit block
|
||||||
|
return getInstructions().length - 1;
|
||||||
|
} else {
|
||||||
|
BasicBlock next = (BasicBlock) getNode(getNumber() + 1);
|
||||||
|
return next.getFirstInstructionIndex() - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getFirstInstructionIndex.
|
||||||
|
*/
|
||||||
|
public int getFirstInstructionIndex() {
|
||||||
|
return startIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "BB[Shrike]" + getNumber() + " - " + method.getDeclaringClass().getReference().getName() + "." + method.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#isExitBlock()
|
||||||
|
*/
|
||||||
|
public boolean isExitBlock() {
|
||||||
|
return this == ShrikeCFG.this.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#isEntryBlock()
|
||||||
|
*/
|
||||||
|
public boolean isEntryBlock() {
|
||||||
|
return this == ShrikeCFG.this.entry();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#getMethod()
|
||||||
|
*/
|
||||||
|
public IMethod getMethod() {
|
||||||
|
return ShrikeCFG.this.getMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return hashBase + getNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return (o instanceof BasicBlock) && ((BasicBlock) o).getMethod().equals(getMethod())
|
||||||
|
&& ((BasicBlock) o).getNumber() == getNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#getNumber()
|
||||||
|
*/
|
||||||
|
public int getNumber() {
|
||||||
|
return getGraphNodeId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<IInstruction> iterateAllInstructions() {
|
||||||
|
return new ArrayIterator<IInstruction>(getInstructions(),getFirstInstructionIndex(),getLastInstructionIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer s = new StringBuffer("");
|
||||||
|
for (Iterator it = iterateNodes(); it.hasNext();) {
|
||||||
|
BasicBlock bb = (BasicBlock) it.next();
|
||||||
|
s.append("BB").append(getNumber(bb)).append("\n");
|
||||||
|
for (int j = bb.getFirstInstructionIndex(); j <= bb.getLastInstructionIndex(); j++) {
|
||||||
|
s.append(" ").append(j).append(" ").append(getInstructions()[j]).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<IBasicBlock> succNodes = getSuccNodes(bb);
|
||||||
|
while (succNodes.hasNext()) {
|
||||||
|
s.append(" -> BB").append(getNumber(succNodes.next())).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getMaxStackHeight.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public int getMaxStackHeight() {
|
||||||
|
return method.getMaxStackHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getMaxLocals
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public int getMaxLocals() {
|
||||||
|
return method.getMaxLocals();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the exceptionHandlers.
|
||||||
|
*
|
||||||
|
* @return Set
|
||||||
|
*/
|
||||||
|
public Set<ExceptionHandler> getExceptionHandlers() {
|
||||||
|
return exceptionHandlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getProgramCounter(int)
|
||||||
|
*/
|
||||||
|
public int getProgramCounter(int index) {
|
||||||
|
try {
|
||||||
|
return method.getBytecodeIndex(index);
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
* A waring when we fail to resolve the type of an exception
|
||||||
|
*/
|
||||||
|
private static class FailedExceptionResolutionWarning extends Warning {
|
||||||
|
|
||||||
|
final TypeReference T;
|
||||||
|
|
||||||
|
FailedExceptionResolutionWarning(TypeReference T) {
|
||||||
|
super(Warning.MODERATE);
|
||||||
|
this.T = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsg() {
|
||||||
|
return getClass().toString() + " : " + T;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FailedExceptionResolutionWarning create(TypeReference T) {
|
||||||
|
return new FailedExceptionResolutionWarning(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,696 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.cfg;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.classLoader.IMethod;
|
||||||
|
import com.ibm.wala.shrikeBT.IInstruction;
|
||||||
|
import com.ibm.wala.ssa.ISSABasicBlock;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAThrowInstruction;
|
||||||
|
import com.ibm.wala.util.IteratorPlusOne;
|
||||||
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||||||
|
import com.ibm.wala.util.collections.HashSetFactory;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.debug.Trace;
|
||||||
|
import com.ibm.wala.util.graph.impl.NumberedNodeIterator;
|
||||||
|
import com.ibm.wala.util.intset.BitVector;
|
||||||
|
import com.ibm.wala.util.intset.FixedSizeBitVector;
|
||||||
|
import com.ibm.wala.util.intset.IntSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This provides a view of a control flow graph with two exits, one for normal
|
||||||
|
* returns and one for exceptional exits.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class TwoExitCFG implements ControlFlowGraph {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEBUG_LEVEL: 0 No output 1 Print some simple stats and warning information
|
||||||
|
* 2 Detailed debugging
|
||||||
|
*/
|
||||||
|
static final int DEBUG_LEVEL = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A "normal" cfg with one exit node
|
||||||
|
*/
|
||||||
|
private final ControlFlowGraph delegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A distinguished basic block representing the exceptional exit.
|
||||||
|
*/
|
||||||
|
private final IBasicBlock exceptionalExit = new ExceptionalExitBlock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numbers of the "normal" predecessors of the delegate's exit() node
|
||||||
|
*/
|
||||||
|
private FixedSizeBitVector normalPred;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Numbers of the "exceptional" predecessors of the delegate's exit() node
|
||||||
|
*/
|
||||||
|
private FixedSizeBitVector exceptionalPred;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached here for efficiency: the "number" of the delegate's exit() node
|
||||||
|
*/
|
||||||
|
private final int delegateExitNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compute edges lazily
|
||||||
|
*/
|
||||||
|
private boolean edgesAreComputed = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param delegate
|
||||||
|
* A "normal" cfg with one exit node
|
||||||
|
*/
|
||||||
|
public TwoExitCFG(ControlFlowGraph delegate) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(!(delegate instanceof TwoExitCFG), "bad recursion");
|
||||||
|
}
|
||||||
|
this.delegate = delegate;
|
||||||
|
this.delegateExitNumber = delegate.getNumber(delegate.exit());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureEdgesReady() {
|
||||||
|
if (!edgesAreComputed) {
|
||||||
|
computeEdges(delegate);
|
||||||
|
edgesAreComputed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param delegate
|
||||||
|
*/
|
||||||
|
private void computeEdges(ControlFlowGraph delegate) {
|
||||||
|
normalPred = (delegate instanceof AbstractCFG) ? ((AbstractCFG) delegate).getNormalToExit() : new FixedSizeBitVector(delegate
|
||||||
|
.getMaxNumber() + 1);
|
||||||
|
exceptionalPred = (delegate instanceof AbstractCFG) ? ((AbstractCFG) delegate).getExceptionalToExit() : new FixedSizeBitVector(
|
||||||
|
delegate.getMaxNumber() + 1);
|
||||||
|
if (!(delegate instanceof AbstractCFG)) {
|
||||||
|
IInstruction[] instructions = delegate.getInstructions();
|
||||||
|
for (Iterator it = delegate.getPredNodes(delegate.exit()); it.hasNext();) {
|
||||||
|
IBasicBlock b = (IBasicBlock) it.next();
|
||||||
|
if (b.getLastInstructionIndex() >= 0) {
|
||||||
|
IInstruction last = instructions[b.getLastInstructionIndex()];
|
||||||
|
if (last != null && last.isPEI()) {
|
||||||
|
exceptionalPred.set(b.getNumber());
|
||||||
|
// occasionally for weird CFGs we may actually fall
|
||||||
|
// thru to the exit. TODO: perhaps enforce an invariant
|
||||||
|
// that all "normal" predecessors of exit end in return.
|
||||||
|
if (!(last instanceof SSAThrowInstruction)) {
|
||||||
|
if (b.getLastInstructionIndex() == instructions.length - 1) {
|
||||||
|
normalPred.set(b.getNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
normalPred.set(b.getNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#entry()
|
||||||
|
*/
|
||||||
|
public IBasicBlock entry() {
|
||||||
|
return delegate.entry();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#exit()
|
||||||
|
*/
|
||||||
|
public IBasicBlock exit() {
|
||||||
|
Assertions.UNREACHABLE("Don't call me");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getCatchBlocks()
|
||||||
|
*/
|
||||||
|
public BitVector getCatchBlocks() {
|
||||||
|
return delegate.getCatchBlocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getBlockForInstruction(int)
|
||||||
|
*/
|
||||||
|
public IBasicBlock getBlockForInstruction(int index) {
|
||||||
|
return delegate.getBlockForInstruction(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getInstructions()
|
||||||
|
*/
|
||||||
|
public IInstruction[] getInstructions() {
|
||||||
|
return delegate.getInstructions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getProgramCounter(int)
|
||||||
|
*/
|
||||||
|
public int getProgramCounter(int index) {
|
||||||
|
return delegate.getProgramCounter(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.Graph#removeNodeAndEdges(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public void removeNodeAndEdges(IBasicBlock N) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NumberedNodeManager#getNumber(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public int getNumber(IBasicBlock N) {
|
||||||
|
if (N.equals(exceptionalExit)) {
|
||||||
|
return getMaxNumber();
|
||||||
|
} else {
|
||||||
|
return delegate.getNumber(N);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NumberedNodeManager#getNode(int)
|
||||||
|
*/
|
||||||
|
public IBasicBlock getNode(int number) {
|
||||||
|
return (number == getMaxNumber()) ? exceptionalExit : delegate.getNode(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NumberedNodeManager#getMaxNumber()
|
||||||
|
*/
|
||||||
|
public int getMaxNumber() {
|
||||||
|
return delegate.getMaxNumber() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NodeManager#iterateNodes()
|
||||||
|
*/
|
||||||
|
public Iterator<IBasicBlock> iterateNodes() {
|
||||||
|
return new IteratorPlusOne<IBasicBlock>(delegate.iterateNodes(), exceptionalExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NodeManager#getNumberOfNodes()
|
||||||
|
*/
|
||||||
|
public int getNumberOfNodes() {
|
||||||
|
return delegate.getNumberOfNodes() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NodeManager#addNode(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public void addNode(IBasicBlock n) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NodeManager#removeNode(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public void removeNode(IBasicBlock n) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NodeManager#containsNode(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean containsNode(IBasicBlock N) {
|
||||||
|
return delegate.containsNode(N) || N.equals(exceptionalExit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodes(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public Iterator<? extends IBasicBlock> getPredNodes(IBasicBlock N) {
|
||||||
|
if (N.equals(exceptionalExit)) {
|
||||||
|
return delegate.getExceptionalPredecessors(delegate.exit()).iterator();
|
||||||
|
} else if (N.equals(delegate.exit())) {
|
||||||
|
return delegate.getNormalPredecessors(delegate.exit()).iterator();
|
||||||
|
} else {
|
||||||
|
return delegate.getPredNodes(N);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.EdgeManager#getPredNodeCount(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public int getPredNodeCount(IBasicBlock N) {
|
||||||
|
ensureEdgesReady();
|
||||||
|
if (N.equals(delegate.exit())) {
|
||||||
|
return normalPred.populationCount();
|
||||||
|
} else if (N.equals(exceptionalExit)) {
|
||||||
|
return exceptionalPred.populationCount();
|
||||||
|
} else {
|
||||||
|
return delegate.getPredNodeCount(N);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodes(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public Iterator<? extends IBasicBlock> getSuccNodes(IBasicBlock N) {
|
||||||
|
if (DEBUG_LEVEL > 1) {
|
||||||
|
Trace.println("TwoExitCFG: getSuccNodes " + N);
|
||||||
|
}
|
||||||
|
ensureEdgesReady();
|
||||||
|
IBasicBlock bb = (IBasicBlock) N;
|
||||||
|
if (N.equals(exceptionalExit)) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
} else if (exceptionalPred.get(bb.getNumber())) {
|
||||||
|
if (normalPred.get(bb.getNumber())) {
|
||||||
|
return new IteratorPlusOne<IBasicBlock>(delegate.getSuccNodes(N), exceptionalExit);
|
||||||
|
} else {
|
||||||
|
return new SubstitutionIterator(delegate.getSuccNodes(N));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return delegate.getSuccNodes(N);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.EdgeManager#getSuccNodeCount(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public int getSuccNodeCount(IBasicBlock N) {
|
||||||
|
if (N.equals(exceptionalExit)) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
ensureEdgesReady();
|
||||||
|
int result = delegate.getSuccNodeCount(N);
|
||||||
|
IBasicBlock bb = (IBasicBlock) N;
|
||||||
|
if (exceptionalPred.get(bb.getNumber()) && normalPred.get(bb.getNumber())) {
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.EdgeManager#addEdge(java.lang.Object,
|
||||||
|
* java.lang.Object)
|
||||||
|
*/
|
||||||
|
public void addEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean hasEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.EdgeManager#removeEdges(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public void removeAllIncidentEdges(IBasicBlock node) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
* An additional basic block to model exceptional exits
|
||||||
|
*/
|
||||||
|
public final class ExceptionalExitBlock implements ISSABasicBlock {
|
||||||
|
|
||||||
|
public ControlFlowGraph getDelegate() {
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#getFirstInstructionIndex()
|
||||||
|
*/
|
||||||
|
public int getFirstInstructionIndex() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#getLastInstructionIndex()
|
||||||
|
*/
|
||||||
|
public int getLastInstructionIndex() {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#isCatchBlock()
|
||||||
|
*/
|
||||||
|
public boolean isCatchBlock() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#isExitBlock()
|
||||||
|
*/
|
||||||
|
public boolean isExitBlock() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#isEntryBlock()
|
||||||
|
*/
|
||||||
|
public boolean isEntryBlock() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#getMethod()
|
||||||
|
*/
|
||||||
|
public IMethod getMethod() {
|
||||||
|
return delegate.getMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.INodeWithNumber#getGraphNodeId()
|
||||||
|
*/
|
||||||
|
public int getGraphNodeId() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.INodeWithNumber#setGraphNodeId(int)
|
||||||
|
*/
|
||||||
|
public void setGraphNodeId(int number) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object arg0) {
|
||||||
|
if (arg0 instanceof ExceptionalExitBlock) {
|
||||||
|
ExceptionalExitBlock other = (ExceptionalExitBlock) arg0;
|
||||||
|
return delegate.exit().equals(other.getDelegate().exit());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return delegate.exit().hashCode() * 8467;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "Exceptional Exit[ " + getMethod() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.IBasicBlock#getNumber()
|
||||||
|
*/
|
||||||
|
public int getNumber() {
|
||||||
|
return getMaxNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator iteratePhis() {
|
||||||
|
return Collections.EMPTY_LIST.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator iteratePis() {
|
||||||
|
return Collections.EMPTY_LIST.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<IInstruction> iterateAllInstructions() {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SSAInstruction getLastInstruction() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getMethod()
|
||||||
|
*/
|
||||||
|
public IMethod getMethod() {
|
||||||
|
return delegate.getMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An iterator that substitutes exceptionalExit for exit()
|
||||||
|
*/
|
||||||
|
private class SubstitutionIterator implements Iterator<IBasicBlock> {
|
||||||
|
private final Iterator it;
|
||||||
|
|
||||||
|
SubstitutionIterator(Iterator it) {
|
||||||
|
this.it = it;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.util.Iterator#remove()
|
||||||
|
*/
|
||||||
|
public void remove() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.util.Iterator#hasNext()
|
||||||
|
*/
|
||||||
|
public boolean hasNext() {
|
||||||
|
return it.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.util.Iterator#next()
|
||||||
|
*/
|
||||||
|
public IBasicBlock next() {
|
||||||
|
IBasicBlock n = (IBasicBlock) it.next();
|
||||||
|
if (n.getNumber() == delegateExitNumber) {
|
||||||
|
return exceptionalExit;
|
||||||
|
} else {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getExceptionalSuccessors(com.ibm.wala.cfg.IBasicBlock)
|
||||||
|
*/
|
||||||
|
public Collection<IBasicBlock> getExceptionalSuccessors(IBasicBlock b) {
|
||||||
|
if (b.equals(exceptionalExit)) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
} else {
|
||||||
|
HashSet<IBasicBlock> c = HashSetFactory.make(getSuccNodeCount(b));
|
||||||
|
for (Iterator<IBasicBlock> it = delegate.getExceptionalSuccessors(b).iterator(); it.hasNext(); ) {
|
||||||
|
IBasicBlock o = it.next();
|
||||||
|
if (o.equals(delegate.exit())) {
|
||||||
|
c.add(exceptionalExit);
|
||||||
|
} else {
|
||||||
|
c.add(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DEBUG_LEVEL > 1) {
|
||||||
|
Trace.println("Used delegate " + delegate.getClass());
|
||||||
|
Trace.println("Exceptional succ of " + b + " " + c);
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#getNormalSuccessors(com.ibm.wala.cfg.IBasicBlock)
|
||||||
|
*/
|
||||||
|
public Collection<IBasicBlock> getNormalSuccessors(IBasicBlock b) {
|
||||||
|
if (b.equals(exceptionalExit)) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
} else {
|
||||||
|
return delegate.getNormalSuccessors(b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A distinguished basic block representing the normal exit
|
||||||
|
*/
|
||||||
|
public IBasicBlock getNormalExit() {
|
||||||
|
return delegate.exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A distinguished basic block representing the exceptional exit
|
||||||
|
*/
|
||||||
|
public IBasicBlock getExceptionalExit() {
|
||||||
|
return exceptionalExit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer result = new StringBuffer("Two-Exit CFG");
|
||||||
|
result.append("\ndelegate\n" + delegate);
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.util.graph.NumberedNodeManager#iterateNodes(com.ibm.wala.util.intset.IntSet)
|
||||||
|
*/
|
||||||
|
public Iterator<IBasicBlock> iterateNodes(IntSet s) {
|
||||||
|
return new NumberedNodeIterator<IBasicBlock>(s, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void removeIncomingEdges(IBasicBlock node) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void removeOutgoingEdges(IBasicBlock node) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<IBasicBlock> getExceptionalPredecessors(IBasicBlock b) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<IBasicBlock> getNormalPredecessors(IBasicBlock b) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntSet getSuccNodeNumbers(IBasicBlock node) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntSet getPredNodeNumbers(IBasicBlock node) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the delegate.
|
||||||
|
*/
|
||||||
|
public ControlFlowGraph getDelegate() {
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.cfg;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.shrikeBT.ConditionalBranchInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAConditionalBranchInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSASwitchInstruction;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
public class Util {
|
||||||
|
|
||||||
|
public static SSAInstruction getLastInstruction(ControlFlowGraph G, IBasicBlock b) {
|
||||||
|
return (SSAInstruction) G.getInstructions()[b.getLastInstructionIndex()];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean endsWithConditionalBranch(ControlFlowGraph G, IBasicBlock b) {
|
||||||
|
return getLastInstruction(G, b) instanceof SSAConditionalBranchInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SSAConditionalBranchInstruction getConditionalBranch(ControlFlowGraph G, IBasicBlock b) {
|
||||||
|
return (SSAConditionalBranchInstruction) getLastInstruction(G, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean endsWithSwitch(ControlFlowGraph G, IBasicBlock b) {
|
||||||
|
return getLastInstruction(G, b) instanceof SSASwitchInstruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SSASwitchInstruction getSwitch(ControlFlowGraph G, IBasicBlock b) {
|
||||||
|
return (SSASwitchInstruction) getLastInstruction(G, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IBasicBlock getFallThruBlock(ControlFlowGraph G, IBasicBlock b) {
|
||||||
|
return G.getBlockForInstruction(b.getLastInstructionIndex() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IBasicBlock getFalseSuccessor(ControlFlowGraph G, IBasicBlock b) {
|
||||||
|
return getFallThruBlock(G, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IBasicBlock getTrueSuccessor(ControlFlowGraph G, IBasicBlock b) {
|
||||||
|
IBasicBlock fs = getFalseSuccessor(G, b);
|
||||||
|
for (Iterator ss = G.getSuccNodes(b); ss.hasNext();) {
|
||||||
|
IBasicBlock s = (IBasicBlock) ss.next();
|
||||||
|
if (s != fs)
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IBasicBlock resolveSwitch(ControlFlowGraph G, IBasicBlock b, int c) {
|
||||||
|
SSASwitchInstruction s = getSwitch(G, b);
|
||||||
|
int[] casesAndLabels = s.getCasesAndLabels();
|
||||||
|
for (int i = 0; i < casesAndLabels.length; i += 2)
|
||||||
|
if (casesAndLabels[i] == c)
|
||||||
|
return G.getBlockForInstruction(casesAndLabels[i + 1]);
|
||||||
|
|
||||||
|
return G.getBlockForInstruction(s.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IBasicBlock resolveBranch(ControlFlowGraph G, IBasicBlock bb, int c1, int c2) {
|
||||||
|
SSAConditionalBranchInstruction c = getConditionalBranch(G, bb);
|
||||||
|
switch ((ConditionalBranchInstruction.Operator)c.getOperator()) {
|
||||||
|
case EQ:
|
||||||
|
if (c1 == c2)
|
||||||
|
return getTrueSuccessor(G, bb);
|
||||||
|
else
|
||||||
|
return getFalseSuccessor(G, bb);
|
||||||
|
case NE:
|
||||||
|
if (c1 != c2)
|
||||||
|
return getTrueSuccessor(G, bb);
|
||||||
|
else
|
||||||
|
return getFalseSuccessor(G, bb);
|
||||||
|
case LT:
|
||||||
|
if (c1 < c2)
|
||||||
|
return getTrueSuccessor(G, bb);
|
||||||
|
else
|
||||||
|
return getFalseSuccessor(G, bb);
|
||||||
|
case GE:
|
||||||
|
if (c1 >= c2)
|
||||||
|
return getTrueSuccessor(G, bb);
|
||||||
|
else
|
||||||
|
return getFalseSuccessor(G, bb);
|
||||||
|
case GT:
|
||||||
|
if (c1 > c2)
|
||||||
|
return getTrueSuccessor(G, bb);
|
||||||
|
else
|
||||||
|
return getFalseSuccessor(G, bb);
|
||||||
|
case LE:
|
||||||
|
if (c1 <= c2)
|
||||||
|
return getTrueSuccessor(G, bb);
|
||||||
|
else
|
||||||
|
return getFalseSuccessor(G, bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.cfg.ControlFlowGraph#whichPred(com.ibm.wala.cfg.IBasicBlock,
|
||||||
|
* com.ibm.wala.cfg.IBasicBlock)
|
||||||
|
*/
|
||||||
|
public static int whichPred(ControlFlowGraph cfg, IBasicBlock a, IBasicBlock b) {
|
||||||
|
int i = 0;
|
||||||
|
for (Iterator it = cfg.getPredNodes(b); it.hasNext();) {
|
||||||
|
if (it.next().equals(a)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
Assertions.UNREACHABLE("Invalid: a must be a predecessor of b! " + a + " " + b);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,532 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.cfg.cdg;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
import com.ibm.wala.cfg.ControlFlowGraph;
|
||||||
|
import com.ibm.wala.cfg.IBasicBlock;
|
||||||
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.graph.AbstractNumberedGraph;
|
||||||
|
import com.ibm.wala.util.graph.EdgeManager;
|
||||||
|
import com.ibm.wala.util.graph.NodeManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control Dependence Graph
|
||||||
|
*
|
||||||
|
* TODO: document me!
|
||||||
|
*
|
||||||
|
* @author Mangala Gowri Nanda
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BVControlDependenceGraph extends AbstractNumberedGraph<IBasicBlock> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Governing control flow-graph. The control dependence graph is computed from
|
||||||
|
* this cfg.
|
||||||
|
*/
|
||||||
|
private final ControlFlowGraph cfg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the EdgeManager for the CDG. It implements the edge part of the standard
|
||||||
|
* Graph abstraction, using the control-dependence egdes of the cdg.
|
||||||
|
*/
|
||||||
|
private final EdgeManager<IBasicBlock> edgeManager;
|
||||||
|
|
||||||
|
private boolean ignoreUnreachableCode = false;
|
||||||
|
|
||||||
|
private final HashMap<IBasicBlock, BasicBlock> bbMap = new HashMap<IBasicBlock, BasicBlock>();
|
||||||
|
|
||||||
|
private Vector<BasicBlock> seen = new Vector<BasicBlock>();
|
||||||
|
|
||||||
|
private BasicBlock entry;
|
||||||
|
|
||||||
|
private Vector<BasicBlock> entryBlocks = new Vector<BasicBlock>();
|
||||||
|
|
||||||
|
private BasicBlock exitnode;
|
||||||
|
|
||||||
|
private int count = 0;
|
||||||
|
|
||||||
|
private int cfgCount = 0;
|
||||||
|
|
||||||
|
private final int isz = 32;
|
||||||
|
|
||||||
|
private final int BitMasks[] = { 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080,
|
||||||
|
0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000,
|
||||||
|
0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000,
|
||||||
|
0x10000000, 0x20000000, 0x40000000, 0x80000000 };
|
||||||
|
|
||||||
|
private int BitvectorSize = 0;
|
||||||
|
|
||||||
|
private int bitvectors[][];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cfg
|
||||||
|
* governing control flow graph wantEdgeLabels is always true
|
||||||
|
*/
|
||||||
|
public BVControlDependenceGraph(ControlFlowGraph cfg) {
|
||||||
|
this(cfg, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cfg
|
||||||
|
* governing control flow graph wantEdgeLabels is always true
|
||||||
|
*/
|
||||||
|
public BVControlDependenceGraph(ControlFlowGraph cfg, boolean ignoreUnreachableCode) {
|
||||||
|
this.cfg = cfg;
|
||||||
|
this.ignoreUnreachableCode = ignoreUnreachableCode;
|
||||||
|
buildParallelGraph();
|
||||||
|
buildCDG();
|
||||||
|
this.edgeManager = constructGraphEdges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ControlFlowGraph getUnderlyingCFG() {
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the set of edge labels for the control flow edges that cause the
|
||||||
|
* given edge in the CDG.
|
||||||
|
*/
|
||||||
|
public Set<? extends Object> getEdgeLabels(Object src, Object dst) {
|
||||||
|
BasicBlock csrc = (BasicBlock) bbMap.get(src);
|
||||||
|
if (csrc == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
BasicBlock cdst = (BasicBlock) bbMap.get(dst);
|
||||||
|
if (cdst == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
return csrc.getLabels(cdst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*/
|
||||||
|
public NodeManager<IBasicBlock> getNodeManager() {
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*/
|
||||||
|
public EdgeManager<IBasicBlock> getEdgeManager() {
|
||||||
|
return edgeManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildParallelGraph() {
|
||||||
|
for (Iterator<? extends IBasicBlock> it = cfg.iterateNodes(); it.hasNext();) {
|
||||||
|
IBasicBlock bb = it.next();
|
||||||
|
BasicBlock cdgbb = new BasicBlock(bb);
|
||||||
|
bbMap.put(bb, cdgbb);
|
||||||
|
cfgCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object entryBB = cfg.entry(); // original entry node
|
||||||
|
entry = new BasicBlock(null); // parallel entry BasicBlock
|
||||||
|
exitnode = (BasicBlock) bbMap.get(cfg.exit());
|
||||||
|
entryBlocks.add(entry);
|
||||||
|
|
||||||
|
for (Iterator<? extends IBasicBlock> it = cfg.iterateNodes(); it.hasNext();) {
|
||||||
|
IBasicBlock bb = it.next();
|
||||||
|
BasicBlock cdgbb = (BasicBlock) bbMap.get(bb);
|
||||||
|
|
||||||
|
// kludge for handling multi-entry CFGs
|
||||||
|
if (!ignoreUnreachableCode && bb != entryBB) {
|
||||||
|
if (cfg.getPredNodeCount(bb) == 0) {
|
||||||
|
entryBlocks.add(cdgbb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// build cfg edges for the parallel graph
|
||||||
|
for (Iterator succ = cfg.getSuccNodes(bb); succ.hasNext();) {
|
||||||
|
Object sbb = succ.next();
|
||||||
|
BasicBlock cdgsbb = (BasicBlock) bbMap.get(sbb);
|
||||||
|
cfgEdge(cdgbb, cdgsbb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// link parallel entry to original entry
|
||||||
|
cfgEdge(entry, (BasicBlock) bbMap.get(cfg.entry()));
|
||||||
|
// link parallel entry to exit
|
||||||
|
cfgEdge(entry, exitnode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the heart of the CDG computation. A simple bitvector
|
||||||
|
* implementation.
|
||||||
|
*/
|
||||||
|
private void buildCDG() {
|
||||||
|
// count and index the nodes
|
||||||
|
count(exitnode);
|
||||||
|
for (int i = 0; i < entryBlocks.size(); i++) {
|
||||||
|
BasicBlock en = (BasicBlock) entryBlocks.get(i);
|
||||||
|
count(en);
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize bitvectors
|
||||||
|
count = seen.size();
|
||||||
|
if (!ignoreUnreachableCode && count != cfgCount + 1) {
|
||||||
|
System.out.println("Strange! count=" + count + ", cfgCount=" + cfgCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
BitvectorSize = count / isz + ((count % isz != 0) ? 1 : 0);
|
||||||
|
bitvectors = new int[count][BitvectorSize];
|
||||||
|
|
||||||
|
// initialize the exitnode first
|
||||||
|
exitnode.index = 0;
|
||||||
|
ClearVector(0);
|
||||||
|
SetBitInVector(0, 0);
|
||||||
|
|
||||||
|
// initialize the rest of the blocks
|
||||||
|
for (int i = 1; i < count; i++) {
|
||||||
|
BasicBlock bb = (BasicBlock) seen.get(i);
|
||||||
|
bb.index = i;
|
||||||
|
SetVector(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterate till all post dominators are done
|
||||||
|
boolean change = true;
|
||||||
|
while (change) {
|
||||||
|
change = false;
|
||||||
|
for (int i = 1; i < count; i++) {
|
||||||
|
BasicBlock sb = (BasicBlock) seen.get(i);
|
||||||
|
Vector succ = sb.getSuccessors();
|
||||||
|
for (int j = 0; j < succ.size(); j++) {
|
||||||
|
if (intersect(sb.index, ((BasicBlock) succ.get(j)).index)) {
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// to find the control dependence
|
||||||
|
for (int n = count - 1; n >= 0; n--) {
|
||||||
|
int i, j, k, tx;
|
||||||
|
BasicBlock bb = (BasicBlock) seen.get(n);
|
||||||
|
Vector succ = bb.getSuccessors();
|
||||||
|
if (succ.size() > 1) {
|
||||||
|
for (int m = 0; m < succ.size(); m++) {
|
||||||
|
BasicBlock sb = (BasicBlock) succ.get(m);
|
||||||
|
for (i = 0, k = 0; i < BitvectorSize; i++) {
|
||||||
|
// postdominates sb but does not postdominate bb
|
||||||
|
tx = bitvectors[sb.index][i] & ~bitvectors[bb.index][i];
|
||||||
|
for (j = 0; j < isz; j++, k++) {
|
||||||
|
if (k >= count)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (GetBit(tx, BitMasks[j]) != 0) {
|
||||||
|
cdEdge(bb, (BasicBlock) seen.get(i * isz + j), sb.item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If bb postdominates one of its successors sb, it is control dependent
|
||||||
|
// on itself with label sb
|
||||||
|
for (int m = 0; m < succ.size(); m++) {
|
||||||
|
BasicBlock sb = (BasicBlock) succ.get(m);
|
||||||
|
if (postdominates(sb.index, bb.index)) {
|
||||||
|
cdEdge(bb, bb, sb.item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EdgeManager
|
||||||
|
*/
|
||||||
|
private EdgeManager<IBasicBlock> constructGraphEdges() {
|
||||||
|
return new EdgeManager<IBasicBlock>() {
|
||||||
|
public Iterator<IBasicBlock> getPredNodes(IBasicBlock N) {
|
||||||
|
BasicBlock cbb = (BasicBlock) bbMap.get(N);
|
||||||
|
if (cbb == null) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
return cbb.getPredNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPredNodeCount(IBasicBlock N) {
|
||||||
|
BasicBlock cbb = (BasicBlock) bbMap.get(N);
|
||||||
|
if (cbb == null)
|
||||||
|
return 0;
|
||||||
|
return cbb.getPredNodeCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<IBasicBlock> getSuccNodes(IBasicBlock N) {
|
||||||
|
BasicBlock cbb = (BasicBlock) bbMap.get(N);
|
||||||
|
if (cbb == null) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
return cbb.getSuccNodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSuccNodeCount(IBasicBlock N) {
|
||||||
|
BasicBlock cbb = (BasicBlock) bbMap.get(N);
|
||||||
|
if (cbb == null)
|
||||||
|
return 0;
|
||||||
|
return cbb.getSuccNodeCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
BasicBlock csrc = (BasicBlock) bbMap.get(src);
|
||||||
|
if (csrc == null)
|
||||||
|
return false;
|
||||||
|
BasicBlock cdst = (BasicBlock) bbMap.get(dst);
|
||||||
|
if (cdst == null)
|
||||||
|
return false;
|
||||||
|
return csrc.hasCDSuccessor(cdst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllIncidentEdges(IBasicBlock node) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeIncomingEdges(IBasicBlock node) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeOutgoingEdges(IBasicBlock node) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
for (Iterator<? extends IBasicBlock> ns = iterateNodes(); ns.hasNext();) {
|
||||||
|
IBasicBlock n = ns.next();
|
||||||
|
sb.append(n.toString()).append("\n");
|
||||||
|
for (Iterator<? extends IBasicBlock> ss = getSuccNodes(n); ss.hasNext();) {
|
||||||
|
Object s = ss.next();
|
||||||
|
sb.append(" --> ").append(s);
|
||||||
|
for (Iterator labels = getEdgeLabels(n, s).iterator(); labels.hasNext();)
|
||||||
|
sb.append("\n label: ").append(labels.next());
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void count(BasicBlock bb) {
|
||||||
|
// postorder
|
||||||
|
if (bb.mark)
|
||||||
|
return;
|
||||||
|
bb.mark = true;
|
||||||
|
|
||||||
|
Vector succ = bb.getSuccessors();
|
||||||
|
for (int i = 0; i < succ.size(); i++) {
|
||||||
|
BasicBlock bs = (BasicBlock) succ.get(i);
|
||||||
|
count(bs);
|
||||||
|
}
|
||||||
|
seen.add(bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cfgEdge(BasicBlock b1, BasicBlock b2) {
|
||||||
|
b2.linkPredecessor(b1);
|
||||||
|
b1.linkSuccessor(b2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cdEdge(BasicBlock b1, BasicBlock b2, IBasicBlock label) {
|
||||||
|
if (b1 == entry)
|
||||||
|
return;
|
||||||
|
b2.linkCDpredecessor(b1);
|
||||||
|
b1.linkCDsuccessor(b2, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearVector(int bb) {
|
||||||
|
for (int i = 0; i < BitvectorSize; i++) {
|
||||||
|
bitvectors[bb][i] = ClearAllBits();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetVector(int bb) {
|
||||||
|
for (int i = 0; i < BitvectorSize; i++) {
|
||||||
|
bitvectors[bb][i] = SetAllBits();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetBitInVector(int bb, int index) {
|
||||||
|
int div = index / isz;
|
||||||
|
int mod = index % isz;
|
||||||
|
bitvectors[bb][div] = SetBit(bitvectors[bb][div], BitMasks[mod]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean intersect(int b1, int b2) {
|
||||||
|
int div = b1 / isz;
|
||||||
|
int mod = b1 % isz;
|
||||||
|
boolean change = false;
|
||||||
|
for (int i = 0; i < BitvectorSize; i++) {
|
||||||
|
int save = bitvectors[b1][i];
|
||||||
|
bitvectors[b1][i] &= bitvectors[b2][i];
|
||||||
|
if (i == div)
|
||||||
|
bitvectors[b1][i] = SetBit(bitvectors[b1][i], BitMasks[mod]);
|
||||||
|
if (save != bitvectors[b1][i])
|
||||||
|
change = true;
|
||||||
|
}
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean postdominates(int b1, int b2) {
|
||||||
|
int div = b2 / isz;
|
||||||
|
int mod = b2 % isz;
|
||||||
|
return (GetBit(bitvectors[b1][div], BitMasks[mod]) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int SetBit(int flg, int msk) {
|
||||||
|
return flg |= msk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* private int ClearBit(int flg, int msk){ return flg &= ~msk; }
|
||||||
|
*/
|
||||||
|
|
||||||
|
private int GetBit(int flg, int msk) {
|
||||||
|
return flg & msk;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ClearAllBits() {
|
||||||
|
return 0x00000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int SetAllBits() {
|
||||||
|
return 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BasicBlock {
|
||||||
|
|
||||||
|
protected final IBasicBlock item;
|
||||||
|
|
||||||
|
protected boolean mark = false;
|
||||||
|
|
||||||
|
protected int index;
|
||||||
|
|
||||||
|
private Vector<BasicBlock> predecessors = new Vector<BasicBlock>(2);
|
||||||
|
|
||||||
|
private Vector<BasicBlock> successors = new Vector<BasicBlock>(2);
|
||||||
|
|
||||||
|
private Vector<IBasicBlock> cdPred = new Vector<IBasicBlock>(2);
|
||||||
|
|
||||||
|
private Vector<IBasicBlock> cdSucc = new Vector<IBasicBlock>(2);
|
||||||
|
|
||||||
|
private HashMap<IBasicBlock, Set<IBasicBlock>> labelMap = new HashMap<IBasicBlock, Set<IBasicBlock>>();
|
||||||
|
|
||||||
|
private BasicBlock(IBasicBlock item) {
|
||||||
|
this.item = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return item.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void linkPredecessor(BasicBlock bb) {
|
||||||
|
Assertions._assert(bb != null);
|
||||||
|
|
||||||
|
if (!predecessors.contains(bb))
|
||||||
|
predecessors.add(bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* private int countPredecessors () { return predecessors.size(); }
|
||||||
|
*
|
||||||
|
* private BasicBlock getPredecessor ( int idx ) { return (BasicBlock)
|
||||||
|
* predecessors.get(idx); }
|
||||||
|
*
|
||||||
|
* private Vector getPredecessors () { return predecessors; }
|
||||||
|
*/
|
||||||
|
|
||||||
|
private void linkSuccessor(BasicBlock bb) {
|
||||||
|
Assertions._assert(bb != null);
|
||||||
|
|
||||||
|
if (!successors.contains(bb))
|
||||||
|
successors.add(bb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* private int countSuccessors () { return successors.size(); }
|
||||||
|
*
|
||||||
|
* private BasicBlock getSuccessor ( int idx ) { return (BasicBlock)
|
||||||
|
* successors.get(idx); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
private Vector getSuccessors() {
|
||||||
|
return successors;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void linkCDpredecessor(BasicBlock bb) {
|
||||||
|
Assertions._assert(bb != null);
|
||||||
|
|
||||||
|
if (!cdPred.contains(bb.item))
|
||||||
|
cdPred.add(bb.item);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getPredNodeCount() {
|
||||||
|
return cdPred.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterator<IBasicBlock> getPredNodes() {
|
||||||
|
return cdPred.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void linkCDsuccessor(BasicBlock bb, IBasicBlock label) {
|
||||||
|
Assertions._assert(bb != null);
|
||||||
|
|
||||||
|
if (!cdSucc.contains(bb.item)) {
|
||||||
|
cdSucc.add(bb.item);
|
||||||
|
}
|
||||||
|
Set<IBasicBlock> labelSet = labelMap.get(bb.item);
|
||||||
|
if (labelSet == null) {
|
||||||
|
labelSet = new HashSet<IBasicBlock>(2);
|
||||||
|
labelMap.put(bb.item, labelSet);
|
||||||
|
}
|
||||||
|
if (label != null && !labelSet.contains(label))
|
||||||
|
labelSet.add(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSuccNodeCount() {
|
||||||
|
return cdSucc.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Iterator<IBasicBlock> getSuccNodes() {
|
||||||
|
return cdSucc.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<IBasicBlock> getLabels(BasicBlock succ) {
|
||||||
|
Set<IBasicBlock> ret = labelMap.get(succ.item);
|
||||||
|
if (ret == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasCDSuccessor(BasicBlock succ) {
|
||||||
|
if (cdSucc.contains(succ.item))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of BasicBlock
|
||||||
|
}
|
|
@ -0,0 +1,254 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.cfg.cdg;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.ibm.wala.cfg.ControlFlowGraph;
|
||||||
|
import com.ibm.wala.cfg.IBasicBlock;
|
||||||
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.collections.HashSetFactory;
|
||||||
|
import com.ibm.wala.util.collections.Pair;
|
||||||
|
import com.ibm.wala.util.graph.AbstractNumberedGraph;
|
||||||
|
import com.ibm.wala.util.graph.DominanceFrontiers;
|
||||||
|
import com.ibm.wala.util.graph.EdgeManager;
|
||||||
|
import com.ibm.wala.util.graph.NodeManager;
|
||||||
|
import com.ibm.wala.util.graph.impl.GraphInverter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control Dependence Graph
|
||||||
|
*
|
||||||
|
* @author Julian Dolby
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ControlDependenceGraph extends AbstractNumberedGraph<IBasicBlock> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Governing control flow-graph. The control dependence graph is computed from
|
||||||
|
* this cfg.
|
||||||
|
*/
|
||||||
|
private final ControlFlowGraph cfg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the EdgeManager for the CDG. It implements the edge part of the standard
|
||||||
|
* Graph abstraction, using the control-dependence egdes of the cdg.
|
||||||
|
*/
|
||||||
|
private final EdgeManager<IBasicBlock> edgeManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If requested, this is a map from parentXchild Pairs representing edges in
|
||||||
|
* the CDG to the labels of the control flow edges that edge corresponds to.
|
||||||
|
* The labels are Boolean.True or Boolean.False for conditionals and an
|
||||||
|
* Integer for a switch label.
|
||||||
|
*/
|
||||||
|
private Map<Pair, Set<Object>> edgeLabels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the heart of the CDG computation. Based on Cytron et al., this is
|
||||||
|
* the reverse dominance frontier based algorithm for computing control
|
||||||
|
* dependence edges.
|
||||||
|
*
|
||||||
|
* @return Map: node n -> {x : n is control-dependent on x}
|
||||||
|
*/
|
||||||
|
private Map<IBasicBlock, Set<IBasicBlock>> buildControlDependence(boolean wantEdgeLabels) {
|
||||||
|
Map<IBasicBlock, Set<IBasicBlock>> controlDependence = new HashMap<IBasicBlock, Set<IBasicBlock>>(cfg.getNumberOfNodes());
|
||||||
|
|
||||||
|
DominanceFrontiers<IBasicBlock> RDF = new DominanceFrontiers<IBasicBlock>(GraphInverter.invert(cfg), cfg.exit());
|
||||||
|
|
||||||
|
if (wantEdgeLabels) {
|
||||||
|
edgeLabels = HashMapFactory.make();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Iterator<? extends IBasicBlock> ns = cfg.iterateNodes(); ns.hasNext();) {
|
||||||
|
controlDependence.put(ns.next(), new HashSet<IBasicBlock>(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Iterator<? extends IBasicBlock> ns = cfg.iterateNodes(); ns.hasNext();) {
|
||||||
|
IBasicBlock y = ns.next();
|
||||||
|
for (Iterator<IBasicBlock> ns2 = RDF.getDominanceFrontier(y); ns2.hasNext();) {
|
||||||
|
IBasicBlock x = ns2.next();
|
||||||
|
controlDependence.get(x).add(y);
|
||||||
|
if (wantEdgeLabels) {
|
||||||
|
Set<Object> labels = new HashSet<Object>();
|
||||||
|
edgeLabels.put(new Pair<Object, Object>(x, y), labels);
|
||||||
|
for (Iterator<? extends IBasicBlock> ss = cfg.getSuccNodes(x); ss.hasNext();) {
|
||||||
|
IBasicBlock s = ss.next();
|
||||||
|
if (RDF.isDominatedBy(s, y)) {
|
||||||
|
labels.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return controlDependence;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given the control-dependence edges in a forward direction (i.e. edges from
|
||||||
|
* control parents to control children), this method creates an EdgeManager
|
||||||
|
* that provides the edge half of the Graph abstraction.
|
||||||
|
*/
|
||||||
|
private EdgeManager<IBasicBlock> constructGraphEdges(final Map<IBasicBlock, Set<IBasicBlock>> forwardEdges) {
|
||||||
|
return new EdgeManager<IBasicBlock>() {
|
||||||
|
Map<IBasicBlock, Set<IBasicBlock>> backwardEdges = new HashMap<IBasicBlock, Set<IBasicBlock>>(forwardEdges.size());
|
||||||
|
{
|
||||||
|
for (Iterator<? extends IBasicBlock> x = cfg.iterateNodes(); x.hasNext();) {
|
||||||
|
Set<IBasicBlock> s = HashSetFactory.make();
|
||||||
|
backwardEdges.put(x.next(), s);
|
||||||
|
}
|
||||||
|
for (Iterator<IBasicBlock> ps = forwardEdges.keySet().iterator(); ps.hasNext();) {
|
||||||
|
IBasicBlock p = ps.next();
|
||||||
|
for (Iterator ns = ((Set) forwardEdges.get(p)).iterator(); ns.hasNext();) {
|
||||||
|
Object n = ns.next();
|
||||||
|
backwardEdges.get(n).add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<IBasicBlock> getPredNodes(IBasicBlock N) {
|
||||||
|
if (backwardEdges.containsKey(N))
|
||||||
|
return backwardEdges.get(N).iterator();
|
||||||
|
else
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPredNodeCount(IBasicBlock N) {
|
||||||
|
if (backwardEdges.containsKey(N))
|
||||||
|
return ((Set) backwardEdges.get(N)).size();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<IBasicBlock> getSuccNodes(IBasicBlock N) {
|
||||||
|
if (forwardEdges.containsKey(N))
|
||||||
|
return forwardEdges.get(N).iterator();
|
||||||
|
else
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSuccNodeCount(IBasicBlock N) {
|
||||||
|
if (forwardEdges.containsKey(N))
|
||||||
|
return ((Set) forwardEdges.get(N)).size();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
return forwardEdges.containsKey(src) && ((Set) forwardEdges.get(src)).contains(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeEdge(IBasicBlock src, IBasicBlock dst) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllIncidentEdges(IBasicBlock node) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeIncomingEdges(IBasicBlock node) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeOutgoingEdges(IBasicBlock node) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
for (Iterator<? extends IBasicBlock> ns = iterateNodes(); ns.hasNext();) {
|
||||||
|
IBasicBlock n = ns.next();
|
||||||
|
sb.append(n.toString()).append("\n");
|
||||||
|
for (Iterator ss = getSuccNodes(n); ss.hasNext();) {
|
||||||
|
Object s = ss.next();
|
||||||
|
sb.append(" --> ").append(s);
|
||||||
|
if (edgeLabels != null)
|
||||||
|
for (Iterator labels = ((Set) edgeLabels.get(new Pair<IBasicBlock, Object>(n, s))).iterator(); labels.hasNext();)
|
||||||
|
sb.append("\n label: ").append(labels.next());
|
||||||
|
sb.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cfg
|
||||||
|
* governing control flow graph
|
||||||
|
* @param wantEdgeLabels
|
||||||
|
* whether to compute edge labels for CDG edges
|
||||||
|
*/
|
||||||
|
public ControlDependenceGraph(ControlFlowGraph cfg, boolean wantEdgeLabels) {
|
||||||
|
this.cfg = cfg;
|
||||||
|
this.edgeManager = constructGraphEdges(buildControlDependence(wantEdgeLabels));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cfg
|
||||||
|
* governing control flow graph
|
||||||
|
*/
|
||||||
|
public ControlDependenceGraph(ControlFlowGraph cfg) {
|
||||||
|
this(cfg, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ControlFlowGraph getUnderlyingCFG() {
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the set of edge labels for the control flow edges that cause the
|
||||||
|
* given edge in the CDG. Requires that the CDG be constructed with
|
||||||
|
* wantEdgeLabels being true.
|
||||||
|
*/
|
||||||
|
public Set<Object> getEdgeLabels(Object from, Object to) {
|
||||||
|
return edgeLabels.get(new Pair<Object, Object>(from, to));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*/
|
||||||
|
public NodeManager<IBasicBlock> getNodeManager() {
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*/
|
||||||
|
public EdgeManager<IBasicBlock> getEdgeManager() {
|
||||||
|
return edgeManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean controlEquivalent(IBasicBlock bb1, IBasicBlock bb2) {
|
||||||
|
if (getPredNodeCount(bb1) != getPredNodeCount(bb2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Iterator pbs1 = getPredNodes(bb1); pbs1.hasNext();) {
|
||||||
|
if (!hasEdge((IBasicBlock) pbs1.next(), bb2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<HTML>
|
||||||
|
<BODY>
|
||||||
|
This package supports a control-dependence graph.
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<HTML>
|
||||||
|
<BODY>
|
||||||
|
This package provides control-flow graph utilities.
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
|
@ -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.classLoader;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.JarURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||||
|
import com.ibm.wala.util.config.FileProvider;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
public abstract class AbstractURLModule implements Module, ModuleEntry {
|
||||||
|
|
||||||
|
private final URL url;
|
||||||
|
|
||||||
|
public AbstractURLModule(URL url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getURL() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
try {
|
||||||
|
URLConnection con = url.openConnection();
|
||||||
|
if (con instanceof JarURLConnection)
|
||||||
|
return ((JarURLConnection) con).getEntryName();
|
||||||
|
else
|
||||||
|
return FileProvider.filePathFromURL(url);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
try {
|
||||||
|
return url.openConnection().getInputStream();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isModuleFile() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Module asModule() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClassName() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<ModuleEntry> getEntries() {
|
||||||
|
return new NonNullSingletonIterator<ModuleEntry>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,354 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||||
|
import com.ibm.wala.shrikeBT.Constants;
|
||||||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
|
import com.ibm.wala.types.Selector;
|
||||||
|
import com.ibm.wala.types.TypeName;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.Atom;
|
||||||
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||||||
|
import com.ibm.wala.util.collections.HashSetFactory;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of IClass for array classes.
|
||||||
|
*
|
||||||
|
* @author Alan Donovan
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class ArrayClass implements IClass, Constants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Package-visible constructor; only for use by ArrayClassLoader class.
|
||||||
|
* 'loader' must be the Primordial IClassLoader.
|
||||||
|
*
|
||||||
|
* [WHY? -- array classes are loaded by the element classloader??]
|
||||||
|
*/
|
||||||
|
ArrayClass(TypeReference type, IClassLoader loader) {
|
||||||
|
this.type = type;
|
||||||
|
this.loader = loader;
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
TypeReference elementType = type.getInnermostElementType();
|
||||||
|
if (!elementType.isPrimitiveType()) {
|
||||||
|
IClass klass = loader.lookupClass(elementType.getName());
|
||||||
|
if (klass == null) {
|
||||||
|
Assertions.UNREACHABLE("caller should not attempt to create an array with type " + type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Assertions._assert(loader.getReference().equals(ClassLoaderReference.Primordial));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final TypeReference type;
|
||||||
|
|
||||||
|
private final IClassLoader loader;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getClassLoader()
|
||||||
|
*/
|
||||||
|
public IClassLoader getClassLoader() {
|
||||||
|
return loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getName()
|
||||||
|
*/
|
||||||
|
public TypeName getName() {
|
||||||
|
return getReference().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#isInterface()
|
||||||
|
*/
|
||||||
|
public boolean isInterface() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#isAbstract()
|
||||||
|
*/
|
||||||
|
public boolean isAbstract() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getModifiers()
|
||||||
|
*/
|
||||||
|
public int getModifiers() {
|
||||||
|
return ACC_PUBLIC | ACC_FINAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQualifiedNameForReflection() {
|
||||||
|
return type.getName().toString(); // XXX is this the right string?
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getSuperclass()
|
||||||
|
*/
|
||||||
|
public IClass getSuperclass() {
|
||||||
|
try {
|
||||||
|
IClass elt = getElementClass();
|
||||||
|
|
||||||
|
Assertions._assert(getReference().getArrayElementType().isPrimitiveType() || elt != null);
|
||||||
|
|
||||||
|
// super is Ljava/lang/Object in two cases:
|
||||||
|
// 1) [Ljava/lang/Object
|
||||||
|
// 2) [? for primitive arrays (null from getElementClass)
|
||||||
|
if (elt == null || elt.getReference() == TypeReference.JavaLangObject) {
|
||||||
|
return loader.lookupClass(TypeReference.JavaLangObject.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// else it is array of super of element type (yuck)
|
||||||
|
else {
|
||||||
|
TypeReference eltSuperRef = elt.getSuperclass().getReference();
|
||||||
|
TypeReference superRef = TypeReference.findOrCreateArrayOf(eltSuperRef);
|
||||||
|
return elt.getSuperclass().getClassLoader().lookupClass(superRef.getName());
|
||||||
|
}
|
||||||
|
} catch (ClassHierarchyException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getMethod(com.ibm.wala.classLoader.Selector)
|
||||||
|
*/
|
||||||
|
public IMethod getMethod(Selector sig) {
|
||||||
|
return loader.lookupClass(TypeReference.JavaLangObject.getName()).getMethod(sig);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IField getField(Atom name) {
|
||||||
|
return getSuperclass().getField(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getDeclaredMethods()
|
||||||
|
*/
|
||||||
|
public Iterator<IMethod> getDeclaredMethods() {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumberOfDeclaredMethods() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getReference()
|
||||||
|
*/
|
||||||
|
public TypeReference getReference() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getSourceFileName()
|
||||||
|
*/
|
||||||
|
public String getSourceFileName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getClassInitializer()
|
||||||
|
*/
|
||||||
|
public IMethod getClassInitializer() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#isArrayClass()
|
||||||
|
*/
|
||||||
|
public boolean isArrayClass() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return getReference().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the IClass that represents the array element type, or null if the
|
||||||
|
* element type is a primitive
|
||||||
|
*/
|
||||||
|
public IClass getElementClass() {
|
||||||
|
TypeReference elementType = getReference().getArrayElementType();
|
||||||
|
if (elementType.isPrimitiveType()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return loader.lookupClass(elementType.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return type.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getDeclaredFields()
|
||||||
|
*/
|
||||||
|
public Collection<IField> getDeclaredInstanceFields() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getDeclaredStaticFields()
|
||||||
|
*/
|
||||||
|
public Collection<IField> getDeclaredStaticFields() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getAllImplementedInterfaces()
|
||||||
|
*/
|
||||||
|
public Collection<IClass> getAllImplementedInterfaces() {
|
||||||
|
HashSet<IClass> result = HashSetFactory.make(2);
|
||||||
|
result.add(loader.lookupClass(TypeReference.array_interfaces[0]));
|
||||||
|
result.add(loader.lookupClass(TypeReference.array_interfaces[1]));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getAllAncestorInterfaces()
|
||||||
|
*/
|
||||||
|
public Collection<IClass> getAllAncestorInterfaces() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#isReferenceType()
|
||||||
|
*/
|
||||||
|
public boolean isReferenceType() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDimensionality() {
|
||||||
|
return getReference().getDimensionality();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the IClass that represents the innermost array element type, or
|
||||||
|
* null if the element type is a primitive
|
||||||
|
*/
|
||||||
|
public IClass getInnermostElementClass() {
|
||||||
|
TypeReference elementType = getReference().getInnermostElementType();
|
||||||
|
if (elementType.isPrimitiveType()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return loader.lookupClass(elementType.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getDirectInterfaces()
|
||||||
|
*/
|
||||||
|
public Collection<IClass> getDirectInterfaces() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj instanceof ArrayClass) {
|
||||||
|
ArrayClass other = (ArrayClass) obj;
|
||||||
|
return loader.equals(other.loader) && type.equals(other.type);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getAllInstanceFields()
|
||||||
|
*/
|
||||||
|
public Collection<IField> getAllInstanceFields() throws ClassHierarchyException {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getAllStaticFields()
|
||||||
|
*/
|
||||||
|
public Collection<IField> getAllStaticFields() throws ClassHierarchyException {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getAllMethods()
|
||||||
|
*/
|
||||||
|
public Collection getAllMethods() throws ClassHierarchyException {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getAllFields()
|
||||||
|
*/
|
||||||
|
public Collection<IField> getAllFields() throws ClassHierarchyException {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.classLoader;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import com.ibm.wala.types.TypeName;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pseudo-classloader for all array classes; all other IClassLoader
|
||||||
|
* implementations should delegate to this one for array classes only.
|
||||||
|
*
|
||||||
|
* @author Stephen Fink
|
||||||
|
*/
|
||||||
|
public class ArrayClassLoader {
|
||||||
|
|
||||||
|
private final static boolean DEBUG = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* map: TypeReference -> ArrayClass
|
||||||
|
*/
|
||||||
|
private HashMap<TypeReference, ArrayClass> arrayClasses = HashMapFactory.make();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param className
|
||||||
|
* name of the array class
|
||||||
|
* @param delegator
|
||||||
|
* class loader to look up element type with
|
||||||
|
*/
|
||||||
|
public IClass lookupClass(TypeName className, IClassLoader delegator) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Assertions._assert(className.toString().startsWith("["));
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeReference type = TypeReference.findOrCreate(delegator.getReference(), className);
|
||||||
|
ArrayClass arrayClass = arrayClasses.get(type);
|
||||||
|
if (arrayClass == null) {
|
||||||
|
TypeReference elementType = type.getArrayElementType();
|
||||||
|
if (elementType.isPrimitiveType()) {
|
||||||
|
TypeReference aRef = TypeReference.findOrCreateArrayOf(elementType);
|
||||||
|
arrayClass = arrayClasses.get(aRef);
|
||||||
|
IClassLoader primordial = getRootClassLoader(delegator);
|
||||||
|
if (arrayClass == null) {
|
||||||
|
arrayClasses.put(aRef, arrayClass = new ArrayClass(aRef, primordial));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// check that the element class is loadable. If not, return null.
|
||||||
|
if (delegator.lookupClass(elementType.getName()) == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
arrayClass = new ArrayClass(type, delegator);
|
||||||
|
}
|
||||||
|
arrayClasses.put(type, arrayClass);
|
||||||
|
}
|
||||||
|
return arrayClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IClassLoader getRootClassLoader(IClassLoader l) {
|
||||||
|
while (l.getParent() != null) {
|
||||||
|
l = l.getParent();
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class BinaryDirectoryTreeModule extends DirectoryTreeModule {
|
||||||
|
|
||||||
|
public BinaryDirectoryTreeModule(File root) {
|
||||||
|
super(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean includeFile(File file) {
|
||||||
|
return file.getName().endsWith("class");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FileModule makeFile(File file) {
|
||||||
|
return new ClassFileModule(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,186 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.callgraph.ContextItem;
|
||||||
|
import com.ibm.wala.shrikeBT.BytecodeConstants;
|
||||||
|
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
||||||
|
import com.ibm.wala.types.MethodReference;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Simple object that represents a static call site (ie., an invoke instruction
|
||||||
|
* in the bytecode)
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public abstract class CallSiteReference extends ProgramCounter implements BytecodeConstants, ContextItem {
|
||||||
|
|
||||||
|
final private MethodReference declaredTarget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param programCounter
|
||||||
|
* @param declaredTarget
|
||||||
|
*/
|
||||||
|
protected CallSiteReference(int programCounter, MethodReference declaredTarget) {
|
||||||
|
super(programCounter);
|
||||||
|
this.declaredTarget = declaredTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the following atrocities are needed to save a word of space by
|
||||||
|
// declaring these classes static, so they don't keep a pointer
|
||||||
|
// to the enclosing environment
|
||||||
|
// Java makes you type!
|
||||||
|
static class StaticCall extends CallSiteReference {
|
||||||
|
StaticCall(int programCounter, MethodReference declaredTarget) {
|
||||||
|
super(programCounter, declaredTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IInvokeInstruction.IDispatch getInvocationCode() {
|
||||||
|
return IInvokeInstruction.Dispatch.STATIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SpecialCall extends CallSiteReference {
|
||||||
|
SpecialCall(int programCounter, MethodReference declaredTarget) {
|
||||||
|
super(programCounter, declaredTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IInvokeInstruction.IDispatch getInvocationCode() {
|
||||||
|
return IInvokeInstruction.Dispatch.SPECIAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class VirtualCall extends CallSiteReference {
|
||||||
|
VirtualCall(int programCounter, MethodReference declaredTarget) {
|
||||||
|
super(programCounter, declaredTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IInvokeInstruction.IDispatch getInvocationCode() {
|
||||||
|
return IInvokeInstruction.Dispatch.VIRTUAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class InterfaceCall extends CallSiteReference {
|
||||||
|
InterfaceCall(int programCounter, MethodReference declaredTarget) {
|
||||||
|
super(programCounter, declaredTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IInvokeInstruction.IDispatch getInvocationCode() {
|
||||||
|
return IInvokeInstruction.Dispatch.INTERFACE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This factory method plays a little game to avoid storing the invocation
|
||||||
|
* code in the object; this saves a byte (probably actually a whole word) in
|
||||||
|
* each created object.
|
||||||
|
*
|
||||||
|
* TODO: Consider canonicalization?
|
||||||
|
*/
|
||||||
|
public static CallSiteReference make(int programCounter, MethodReference declaredTarget,
|
||||||
|
IInvokeInstruction.IDispatch invocationCode) {
|
||||||
|
|
||||||
|
if (invocationCode == IInvokeInstruction.Dispatch.SPECIAL)
|
||||||
|
return new SpecialCall(programCounter, declaredTarget);
|
||||||
|
if (invocationCode == IInvokeInstruction.Dispatch.VIRTUAL)
|
||||||
|
return new VirtualCall(programCounter, declaredTarget);
|
||||||
|
if (invocationCode == IInvokeInstruction.Dispatch.INTERFACE)
|
||||||
|
return new InterfaceCall(programCounter, declaredTarget);
|
||||||
|
if (invocationCode == IInvokeInstruction.Dispatch.STATIC)
|
||||||
|
return new StaticCall(programCounter, declaredTarget);
|
||||||
|
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Method that this call site calls. This represents the method
|
||||||
|
* declared in the invoke instruction only.
|
||||||
|
*/
|
||||||
|
public MethodReference getDeclaredTarget() {
|
||||||
|
return declaredTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return one of INVOKESPECIAL, INVOKESTATIC, INVOKEVIRTUAL, or
|
||||||
|
* INVOKEINTERFACE
|
||||||
|
*/
|
||||||
|
abstract public IInvokeInstruction.IDispatch getInvocationCode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "invoke" + getInvocationString(getInvocationCode()) + " " + declaredTarget + "@" + getProgramCounter();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getInvocationString.
|
||||||
|
*
|
||||||
|
* @param invocationCode
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
protected String getInvocationString(IInvokeInstruction.IDispatch invocationCode) {
|
||||||
|
if (invocationCode == IInvokeInstruction.Dispatch.STATIC)
|
||||||
|
return "static";
|
||||||
|
if (invocationCode == IInvokeInstruction.Dispatch.SPECIAL)
|
||||||
|
return "special";
|
||||||
|
if (invocationCode == IInvokeInstruction.Dispatch.VIRTUAL)
|
||||||
|
return "virtual";
|
||||||
|
if (invocationCode == IInvokeInstruction.Dispatch.INTERFACE)
|
||||||
|
return "interface";
|
||||||
|
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInvocationString() {
|
||||||
|
return getInvocationString(getInvocationCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this an invokeinterface call site?
|
||||||
|
*/
|
||||||
|
public final boolean isInterface() {
|
||||||
|
return (getInvocationCode() == IInvokeInstruction.Dispatch.INTERFACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this an invokevirtual call site?
|
||||||
|
*/
|
||||||
|
public final boolean isVirtual() {
|
||||||
|
return (getInvocationCode() == IInvokeInstruction.Dispatch.VIRTUAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this an invokespecial call site?
|
||||||
|
*/
|
||||||
|
public final boolean isSpecial() {
|
||||||
|
return (getInvocationCode() == IInvokeInstruction.Dispatch.SPECIAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this an invokestatic call site?
|
||||||
|
*/
|
||||||
|
public boolean isStatic() {
|
||||||
|
return (getInvocationCode() == IInvokeInstruction.Dispatch.STATIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFixed() {
|
||||||
|
return isStatic() || isSpecial();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDispatch() {
|
||||||
|
return isVirtual() || isInterface();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||||
|
import com.ibm.wala.util.ImmutableByteArray;
|
||||||
|
import com.ibm.wala.util.ShrikeClassReaderHandle;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A module which is a wrapper around a .class file
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class ClassFileModule extends FileModule implements Module, ModuleEntry {
|
||||||
|
|
||||||
|
private final String className;
|
||||||
|
|
||||||
|
public ClassFileModule(File f) {
|
||||||
|
super(f);
|
||||||
|
// this is delicate: TODO, clean it up a bit.
|
||||||
|
ShrikeClassReaderHandle reader = new ShrikeClassReaderHandle(this);
|
||||||
|
ImmutableByteArray name = null;
|
||||||
|
try {
|
||||||
|
name = ImmutableByteArray.make(reader.get().getName());
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
className = name.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "ClassFileModule:" + getFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#isClassFile()
|
||||||
|
*/
|
||||||
|
public boolean isClassFile() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#getClassName()
|
||||||
|
*/
|
||||||
|
public String getClassName() {
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile()
|
||||||
|
*/
|
||||||
|
public boolean isSourceFile() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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.classLoader;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ClassLoaderFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a class loader corresponding to a given
|
||||||
|
* class loader identifier. Create one if necessary.
|
||||||
|
* @param classLoaderReference identifier for the desired class loader
|
||||||
|
* @return IClassLoader
|
||||||
|
*/
|
||||||
|
IClassLoader getLoader(ClassLoaderReference classLoaderReference, ClassHierarchy cha, AnalysisScope scope)
|
||||||
|
throws IOException;
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.callgraph.AnalysisScope;
|
||||||
|
import com.ibm.wala.ipa.callgraph.impl.SetOfClasses;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.warnings.Warning;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of the class loader factory that produces ClassLoaderImpls
|
||||||
|
*/
|
||||||
|
public class ClassLoaderFactoryImpl implements ClassLoaderFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of classes that class loaders should ignore; classloaders should
|
||||||
|
* pretend these classes don't exit.
|
||||||
|
*/
|
||||||
|
private SetOfClasses exclusions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object to track warnings
|
||||||
|
*/
|
||||||
|
private final WarningSet warnings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Mapping from ClassLoaderReference to IClassLoader
|
||||||
|
*/
|
||||||
|
private HashMap<ClassLoaderReference, IClassLoader> map = HashMapFactory.make(3);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param exclusions
|
||||||
|
* A set of classes that class loaders should pretend don't exist.
|
||||||
|
*/
|
||||||
|
public ClassLoaderFactoryImpl(SetOfClasses exclusions, WarningSet warnings) {
|
||||||
|
this.exclusions = exclusions;
|
||||||
|
this.warnings = warnings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a class loader corresponding to a given class loader identifier.
|
||||||
|
* Create one if necessary.
|
||||||
|
*
|
||||||
|
* @param classLoaderReference
|
||||||
|
* identifier for the desired class loader
|
||||||
|
* @return IClassLoader
|
||||||
|
*/
|
||||||
|
public IClassLoader getLoader(ClassLoaderReference classLoaderReference, ClassHierarchy cha, AnalysisScope scope)
|
||||||
|
throws IOException {
|
||||||
|
IClassLoader result = map.get(classLoaderReference);
|
||||||
|
if (result == null) {
|
||||||
|
ClassLoaderReference parentRef = classLoaderReference.getParent();
|
||||||
|
IClassLoader parent = null;
|
||||||
|
if (parentRef != null) {
|
||||||
|
parent = getLoader(parentRef, cha, scope);
|
||||||
|
}
|
||||||
|
IClassLoader cl = makeNewClassLoader(classLoaderReference, cha, parent, scope);
|
||||||
|
map.put(classLoaderReference, cl);
|
||||||
|
result = cl;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new class loader for a given key
|
||||||
|
*
|
||||||
|
* @param classLoaderReference
|
||||||
|
* the key
|
||||||
|
* @param parent
|
||||||
|
* parent classloader to be used for delegation
|
||||||
|
* @return a new ClassLoaderImpl
|
||||||
|
* @throws IOException
|
||||||
|
* if the desired loader cannot be instantiated, usually because the
|
||||||
|
* specified module can't be found.
|
||||||
|
*/
|
||||||
|
protected IClassLoader makeNewClassLoader(ClassLoaderReference classLoaderReference, ClassHierarchy cha, IClassLoader parent,
|
||||||
|
AnalysisScope scope) throws IOException {
|
||||||
|
String implClass = scope.getLoaderImpl(classLoaderReference);
|
||||||
|
IClassLoader cl;
|
||||||
|
if (implClass == null) {
|
||||||
|
cl = new ClassLoaderImpl(classLoaderReference, scope.getArrayClassLoader(), parent, exclusions, scope.getModules(classLoaderReference), cha, warnings);
|
||||||
|
} else
|
||||||
|
try {
|
||||||
|
Class impl = Class.forName(implClass);
|
||||||
|
Constructor ctor = impl.getDeclaredConstructor(new Class[] { ClassLoaderReference.class, IClassLoader.class,
|
||||||
|
SetOfClasses.class, ClassHierarchy.class, WarningSet.class });
|
||||||
|
cl = (IClassLoader) ctor.newInstance(new Object[] { classLoaderReference, parent, exclusions, cha, warnings });
|
||||||
|
} catch (Exception e) {
|
||||||
|
warnings.add(InvalidClassLoaderImplementation.create(implClass));
|
||||||
|
cl = new ClassLoaderImpl(classLoaderReference, scope.getArrayClassLoader(), parent, exclusions, scope.getModules(classLoaderReference), cha, warnings);
|
||||||
|
}
|
||||||
|
cl.init(scope.getModules(classLoaderReference));
|
||||||
|
return cl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
* A waring when we fail to load an appropriate class loader implementation
|
||||||
|
*/
|
||||||
|
private static class InvalidClassLoaderImplementation extends Warning {
|
||||||
|
|
||||||
|
final String impl;
|
||||||
|
InvalidClassLoaderImplementation(String impl) {
|
||||||
|
super(Warning.SEVERE);
|
||||||
|
this.impl = impl;
|
||||||
|
}
|
||||||
|
public String getMsg() {
|
||||||
|
return getClass().toString() + " : " + impl;
|
||||||
|
}
|
||||||
|
public static InvalidClassLoaderImplementation create(String impl) {
|
||||||
|
return new InvalidClassLoaderImplementation(impl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the set of classes that will be ignored.
|
||||||
|
*/
|
||||||
|
public SetOfClasses getExclusions() {
|
||||||
|
return exclusions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarningSet getWarnings() {
|
||||||
|
return warnings;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,490 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.callgraph.impl.SetOfClasses;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
|
import com.ibm.wala.types.TypeName;
|
||||||
|
import com.ibm.wala.util.Atom;
|
||||||
|
import com.ibm.wala.util.ShrikeClassReaderHandle;
|
||||||
|
import com.ibm.wala.util.collections.HashCodeComparator;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.collections.HashSetFactory;
|
||||||
|
import com.ibm.wala.util.collections.Iterator2Collection;
|
||||||
|
import com.ibm.wala.util.collections.ToStringComparator;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.debug.Trace;
|
||||||
|
import com.ibm.wala.util.warnings.Warning;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A class loader that reads class definitions from a set of Modules.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class ClassLoaderImpl implements IClassLoader {
|
||||||
|
private static final int DEBUG_LEVEL = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* classes to ignore
|
||||||
|
*/
|
||||||
|
private SetOfClasses exclusions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identity for this class loader
|
||||||
|
*/
|
||||||
|
private ClassLoaderReference loader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapping from class name (TypeName) to IClass
|
||||||
|
*/
|
||||||
|
protected final Map<TypeName, IClass> loadedClasses = HashMapFactory.make();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapping from class name (TypeName) to String (source file name)
|
||||||
|
*/
|
||||||
|
private final Map<TypeName, String> sourceMap = HashMapFactory.make();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object to track warnings
|
||||||
|
*/
|
||||||
|
private final WarningSet warnings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parent classloader
|
||||||
|
*/
|
||||||
|
private IClassLoader parent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Governing class hierarchy
|
||||||
|
*/
|
||||||
|
protected final ClassHierarchy cha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an object to delegate to for loading of array classes
|
||||||
|
*/
|
||||||
|
private final ArrayClassLoader arrayClassLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for ModuleSetClassLoader.
|
||||||
|
*
|
||||||
|
* @param loader
|
||||||
|
* class loader reference identifying this loader
|
||||||
|
* @param parent
|
||||||
|
* parent loader for delegation
|
||||||
|
* @param exclusions
|
||||||
|
* set of classes to exclude from loading
|
||||||
|
*/
|
||||||
|
public ClassLoaderImpl(ClassLoaderReference loader, ArrayClassLoader arrayClassLoader, IClassLoader parent,
|
||||||
|
SetOfClasses exclusions, Set modules, ClassHierarchy cha, WarningSet warnings) {
|
||||||
|
|
||||||
|
this.arrayClassLoader = arrayClassLoader;
|
||||||
|
this.parent = parent;
|
||||||
|
this.loader = loader;
|
||||||
|
this.exclusions = exclusions;
|
||||||
|
this.cha = cha;
|
||||||
|
this.warnings = warnings;
|
||||||
|
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("Creating class loader for " + loader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Set of (ModuleEntry) source files found in a module.
|
||||||
|
*
|
||||||
|
* @param M
|
||||||
|
* the module
|
||||||
|
* @return the Set of source files in the module
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private Set<ModuleEntry> getSourceFiles(Module M) throws IOException {
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("Get source files for " + M);
|
||||||
|
}
|
||||||
|
TreeSet<ModuleEntry> sortedEntries = new TreeSet<ModuleEntry>(HashCodeComparator.instance());
|
||||||
|
sortedEntries.addAll(new Iterator2Collection<ModuleEntry>(M.getEntries()));
|
||||||
|
|
||||||
|
HashSet<ModuleEntry> result = HashSetFactory.make();
|
||||||
|
for (Iterator it = sortedEntries.iterator(); it.hasNext();) {
|
||||||
|
ModuleEntry entry = (ModuleEntry) it.next();
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("consider entry for source information: " + entry);
|
||||||
|
}
|
||||||
|
if (entry.isSourceFile()) {
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("found source file: " + entry);
|
||||||
|
}
|
||||||
|
result.add(entry);
|
||||||
|
} else if (entry.isModuleFile()) {
|
||||||
|
result.addAll(getSourceFiles(entry.asModule()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the Set of (ModuleEntry) class files found in a module.
|
||||||
|
*
|
||||||
|
* @param M
|
||||||
|
* the module
|
||||||
|
* @return the Set of class Files in the module
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private Set<ModuleEntry> getClassFiles(Module M) throws IOException {
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("Get class files for " + M);
|
||||||
|
}
|
||||||
|
TreeSet<ModuleEntry> sortedEntries = new TreeSet<ModuleEntry>(HashCodeComparator.instance());
|
||||||
|
sortedEntries.addAll(new Iterator2Collection<ModuleEntry>(M.getEntries()));
|
||||||
|
|
||||||
|
HashSet<ModuleEntry> result = HashSetFactory.make();
|
||||||
|
for (Iterator it = sortedEntries.iterator(); it.hasNext();) {
|
||||||
|
ModuleEntry entry = (ModuleEntry) it.next();
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("ClassLoaderImpl.getClassFiles:Got entry: " + entry);
|
||||||
|
}
|
||||||
|
if (entry.isClassFile()) {
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("result contains: " + entry);
|
||||||
|
}
|
||||||
|
result.add(entry);
|
||||||
|
} else if (entry.isModuleFile()) {
|
||||||
|
Set<ModuleEntry> s = getClassFiles(entry.asModule());
|
||||||
|
removeClassFiles(s, result);
|
||||||
|
result.addAll(s);
|
||||||
|
} else {
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("Ignoring entry: " + entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove from s any class file module entries which already are in t
|
||||||
|
*
|
||||||
|
* @param s
|
||||||
|
* @param t
|
||||||
|
*/
|
||||||
|
private void removeClassFiles(Set<ModuleEntry> s, Set<ModuleEntry> t) {
|
||||||
|
Set<String> old = new HashSet<String>();
|
||||||
|
for (Iterator<ModuleEntry> it = t.iterator(); it.hasNext();) {
|
||||||
|
ModuleEntry m = it.next();
|
||||||
|
old.add(m.getClassName());
|
||||||
|
}
|
||||||
|
HashSet<ModuleEntry> toRemove = new HashSet<ModuleEntry>();
|
||||||
|
for (Iterator<ModuleEntry> it = s.iterator(); it.hasNext();) {
|
||||||
|
ModuleEntry m = it.next();
|
||||||
|
if (old.contains(m.getClassName())) {
|
||||||
|
toRemove.add(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.removeAll(toRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a Set of IClasses, which represents all classes this class loader
|
||||||
|
* can load.
|
||||||
|
*/
|
||||||
|
private Collection<IClass> getAllClasses() {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(loadedClasses != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadedClasses.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the set of classes loaded by this object.
|
||||||
|
*/
|
||||||
|
private void loadAllClasses(Collection<ModuleEntry> moduleEntries) {
|
||||||
|
for (Iterator<ModuleEntry> it = moduleEntries.iterator(); it.hasNext();) {
|
||||||
|
ModuleEntry entry = it.next();
|
||||||
|
if (!entry.isClassFile()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String className = entry.getClassName().replace('.', '/');
|
||||||
|
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("Consider " + className);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exclusions != null && exclusions.contains(className)) {
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("Excluding " + className);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShrikeClassReaderHandle reader = new ShrikeClassReaderHandle(entry);
|
||||||
|
|
||||||
|
className = "L" + className;
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("Load class " + className);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
TypeName T = TypeName.string2TypeName(className);
|
||||||
|
if (loadedClasses.get(T) != null) {
|
||||||
|
warnings.add(MultipleImplementationsWarning.create(className));
|
||||||
|
} else {
|
||||||
|
ShrikeCTClassWrapper klass = new ShrikeCTClassWrapper(reader, this, cha, warnings);
|
||||||
|
if (klass.getReference().getName().equals(T)) {
|
||||||
|
loadedClasses.put(T, new ShrikeCTClassWrapper(reader, this, cha, warnings));
|
||||||
|
if (DEBUG_LEVEL > 1) {
|
||||||
|
Trace.println("put " + T + " ");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warnings.add(InvalidClassFile.create(className));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("Ignoring class " + className + " due to InvalidClassFileException");
|
||||||
|
}
|
||||||
|
warnings.add(InvalidClassFile.create(className));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
* A waring when we find more than one implementation of a given class name
|
||||||
|
*/
|
||||||
|
private static class MultipleImplementationsWarning extends Warning {
|
||||||
|
|
||||||
|
final String className;
|
||||||
|
|
||||||
|
MultipleImplementationsWarning(String className) {
|
||||||
|
super(Warning.SEVERE);
|
||||||
|
this.className = className;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsg() {
|
||||||
|
return getClass().toString() + " : " + className;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MultipleImplementationsWarning create(String className) {
|
||||||
|
return new MultipleImplementationsWarning(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
* A waring when we encounter InvalidClassFileException
|
||||||
|
*/
|
||||||
|
private static class InvalidClassFile extends Warning {
|
||||||
|
|
||||||
|
final String className;
|
||||||
|
|
||||||
|
InvalidClassFile(String className) {
|
||||||
|
super(Warning.SEVERE);
|
||||||
|
this.className = className;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsg() {
|
||||||
|
return getClass().toString() + " : " + className;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InvalidClassFile create(String className) {
|
||||||
|
return new InvalidClassFile(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up mapping from type name to Module Entry
|
||||||
|
*/
|
||||||
|
protected void loadAllSources(Set<ModuleEntry> sourceModules) {
|
||||||
|
|
||||||
|
for (Iterator<ModuleEntry> it = sourceModules.iterator(); it.hasNext();) {
|
||||||
|
ModuleEntry entry = it.next();
|
||||||
|
String className = entry.getClassName().replace('.', '/');
|
||||||
|
className = className.replace(File.separatorChar, '/');
|
||||||
|
className = "L" + ((className.startsWith("/")) ? className.substring(1) : className);
|
||||||
|
TypeName T = TypeName.string2TypeName(className);
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("adding to source map: " + T + " -> " + entry.getName());
|
||||||
|
}
|
||||||
|
sourceMap.put(T, entry.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize internal data structures
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void init(Set modules) throws IOException {
|
||||||
|
|
||||||
|
// use tree set to keep things sorted ... for deterministic class loading
|
||||||
|
TreeSet<Module> archives = new TreeSet<Module>(ToStringComparator.instance());
|
||||||
|
for (Iterator i = modules.iterator(); i.hasNext();) {
|
||||||
|
Module M = (Module) i.next();
|
||||||
|
if (DEBUG_LEVEL > 0) {
|
||||||
|
Trace.println("add archive: " + M);
|
||||||
|
}
|
||||||
|
archives.add(M);
|
||||||
|
}
|
||||||
|
Set<ModuleEntry> classModuleEntries = new HashSet<ModuleEntry>();
|
||||||
|
Set<ModuleEntry> sourceModuleEntries = new HashSet<ModuleEntry>();
|
||||||
|
for (Iterator<Module> it = archives.iterator(); it.hasNext();) {
|
||||||
|
Module archive = it.next();
|
||||||
|
Set<ModuleEntry> classFiles = getClassFiles(archive);
|
||||||
|
removeClassFiles(classFiles, classModuleEntries);
|
||||||
|
for (Iterator<ModuleEntry> it2 = classFiles.iterator(); it2.hasNext();) {
|
||||||
|
ModuleEntry file = it2.next();
|
||||||
|
classModuleEntries.add(file);
|
||||||
|
}
|
||||||
|
Set<ModuleEntry> sourceFiles = getSourceFiles(archive);
|
||||||
|
for (Iterator<ModuleEntry> it2 = sourceFiles.iterator(); it2.hasNext();) {
|
||||||
|
ModuleEntry file = it2.next();
|
||||||
|
sourceModuleEntries.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadAllClasses(classModuleEntries);
|
||||||
|
loadAllSources(sourceModuleEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassLoaderReference getReference() {
|
||||||
|
return loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<IClass> iterateAllClasses() {
|
||||||
|
return getAllClasses().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This version returns null instead of throwing ClassNotFoundException.
|
||||||
|
*/
|
||||||
|
private IClass lookupClassInternal(TypeName className) {
|
||||||
|
if (DEBUG_LEVEL > 1) {
|
||||||
|
Trace.println(this + ": lookupClassInternal " + className);
|
||||||
|
}
|
||||||
|
|
||||||
|
// try delegating first.
|
||||||
|
ClassLoaderImpl parent = (ClassLoaderImpl) getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
IClass result = parent.lookupClassInternal(className);
|
||||||
|
if (result != null)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// delegating failed. Try our own namespace.
|
||||||
|
return loadedClasses.get(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IClass lookupClass(TypeName className) {
|
||||||
|
if (DEBUG_LEVEL > 1) {
|
||||||
|
Trace.println(this + ": lookupClass " + className);
|
||||||
|
}
|
||||||
|
|
||||||
|
// treat arrays specially:
|
||||||
|
if (className.isArrayType()) {
|
||||||
|
return arrayClassLoader.lookupClass(className, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// try delegating first.
|
||||||
|
ClassLoaderImpl parent = (ClassLoaderImpl) getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
IClass result = parent.lookupClassInternal(className);
|
||||||
|
if (result != null) {
|
||||||
|
if (DEBUG_LEVEL > 1) {
|
||||||
|
Trace.println(this + ": returning class from parent: " + result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// delegating failed. Try our own namespace.
|
||||||
|
IClass result = loadedClasses.get(className);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getParent.
|
||||||
|
*/
|
||||||
|
public IClassLoader getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Atom getName() {
|
||||||
|
return loader.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return getName().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClassLoader#getNumberOfClasses()
|
||||||
|
*/
|
||||||
|
public int getNumberOfClasses() {
|
||||||
|
return getAllClasses().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClassLoader#getNumberOfMethods()
|
||||||
|
*/
|
||||||
|
public int getNumberOfMethods() {
|
||||||
|
int result = 0;
|
||||||
|
for (Iterator<IClass> it = iterateAllClasses(); it.hasNext();) {
|
||||||
|
IClass klass = it.next();
|
||||||
|
for (Iterator i2 = klass.getDeclaredMethods(); i2.hasNext();) {
|
||||||
|
i2.next();
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClassLoader#getSourceFileName(com.ibm.wala.classLoader.IClass)
|
||||||
|
*/
|
||||||
|
public String getSourceFileName(IClass klass) {
|
||||||
|
return sourceMap.get(klass.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClassLoader#removeAll(java.util.Collection)
|
||||||
|
*/
|
||||||
|
public void removeAll(Collection<IClass> toRemove) {
|
||||||
|
for (Iterator<IClass> it = toRemove.iterator(); it.hasNext();) {
|
||||||
|
IClass klass = it.next();
|
||||||
|
loadedClasses.remove(klass.getName());
|
||||||
|
sourceMap.remove(klass.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,365 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||||
|
import com.ibm.wala.ssa.SSAArrayLoadInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAArrayStoreInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSACheckCastInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAGetInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInvokeInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSANewInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAOptions;
|
||||||
|
import com.ibm.wala.ssa.SSAPutInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction.Visitor;
|
||||||
|
import com.ibm.wala.types.FieldReference;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.collections.HashSetFactory;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* This class can scan an IMethod and generate a list of call sites in the
|
||||||
|
* method.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class CodeScanner {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return iterator of call site references.
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public static Iterator<CallSiteReference> iterateCallSites(IMethod m, WarningSet warnings) throws InvalidClassFileException {
|
||||||
|
if (m.isSynthetic()) {
|
||||||
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
|
return getCallSites(sm.getStatements(SSAOptions.defaultOptions(), warnings)).iterator();
|
||||||
|
} else {
|
||||||
|
return getCallSitesFromShrikeBT((ShrikeCTMethodWrapper) m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return iterator of FieldReference
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public static Iterator iterateFieldsRead(IMethod m, WarningSet warnings) throws InvalidClassFileException {
|
||||||
|
if (m.isSynthetic()) {
|
||||||
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
|
return getFieldsRead(sm.getStatements(SSAOptions.defaultOptions(), warnings)).iterator();
|
||||||
|
} else {
|
||||||
|
return getFieldsReadFromShrikeBT((ShrikeCTMethodWrapper) m).iterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return iterator of FieldReference
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public static Iterator iterateFieldsWritten(IMethod m, WarningSet warnings) throws InvalidClassFileException {
|
||||||
|
if (m.isSynthetic()) {
|
||||||
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
|
return getFieldsWritten(sm.getStatements(SSAOptions.defaultOptions(), warnings)).iterator();
|
||||||
|
} else {
|
||||||
|
return getFieldsWrittenFromShrikeBT((ShrikeCTMethodWrapper) m).iterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return iterator of TypeReference.
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public static Iterator<NewSiteReference> iterateNewSites(IMethod m, WarningSet warnings) throws InvalidClassFileException {
|
||||||
|
if (m.isSynthetic()) {
|
||||||
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
|
return getNewSites(sm.getStatements(SSAOptions.defaultOptions(), warnings)).iterator();
|
||||||
|
} else {
|
||||||
|
return getNewSitesFromShrikeBT((ShrikeCTMethodWrapper) m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasObjectArrayLoad(IMethod m, WarningSet warnings) throws InvalidClassFileException {
|
||||||
|
if (m.isSynthetic()) {
|
||||||
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
|
return hasObjectArrayLoad(sm.getStatements(SSAOptions.defaultOptions(), warnings));
|
||||||
|
} else {
|
||||||
|
return hasShrikeBTObjectArrayLoad((ShrikeCTMethodWrapper) m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasObjectArrayStore(IMethod m, WarningSet warnings) throws InvalidClassFileException {
|
||||||
|
if (m.isSynthetic()) {
|
||||||
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
|
return hasObjectArrayStore(sm.getStatements(SSAOptions.defaultOptions(), warnings));
|
||||||
|
} else {
|
||||||
|
return hasShrikeBTObjectArrayStore((ShrikeCTMethodWrapper) m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set getCaughtExceptions(IMethod m, WarningSet warnings) throws InvalidClassFileException {
|
||||||
|
if (m.isSynthetic()) {
|
||||||
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
|
return getCaughtExceptions(sm.getStatements(SSAOptions.defaultOptions(), warnings));
|
||||||
|
} else {
|
||||||
|
return getShrikeBTCaughtExceptions((ShrikeCTMethodWrapper) m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the types this method may cast to
|
||||||
|
*
|
||||||
|
* @return iterator of TypeReference
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public static Iterator iterateCastTypes(IMethod m, WarningSet warnings) throws InvalidClassFileException {
|
||||||
|
if (m.isSynthetic()) {
|
||||||
|
SyntheticMethod sm = (SyntheticMethod) m;
|
||||||
|
return iterateCastTypes(sm.getStatements(SSAOptions.defaultOptions(), warnings));
|
||||||
|
} else {
|
||||||
|
return iterateShrikeBTCastTypes((ShrikeCTMethodWrapper) m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Iterator iterateShrikeBTCastTypes(ShrikeCTMethodWrapper wrapper) throws InvalidClassFileException {
|
||||||
|
return wrapper.getCastTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set getShrikeBTCaughtExceptions(ShrikeCTMethodWrapper method) throws InvalidClassFileException {
|
||||||
|
return method.getCaughtExceptionTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasShrikeBTObjectArrayStore(ShrikeCTMethodWrapper M) throws InvalidClassFileException {
|
||||||
|
for (Iterator it = M.getArraysWritten(); it.hasNext();) {
|
||||||
|
TypeReference t = (TypeReference) it.next();
|
||||||
|
if (t.isReferenceType()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Iterator<CallSiteReference> getCallSitesFromShrikeBT(ShrikeCTMethodWrapper M) throws InvalidClassFileException {
|
||||||
|
return M.getCallSites();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param M
|
||||||
|
* @return Iterator of TypeReference
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
private static Iterator<NewSiteReference> getNewSitesFromShrikeBT(ShrikeCTMethodWrapper M) throws InvalidClassFileException {
|
||||||
|
return M.getNewSites();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<FieldReference> getFieldsReadFromShrikeBT(ShrikeCTMethodWrapper M) throws InvalidClassFileException {
|
||||||
|
// TODO move the logic here from ShrikeCTMethodWrapper
|
||||||
|
LinkedList<FieldReference> result = new LinkedList<FieldReference>();
|
||||||
|
for (Iterator<FieldReference> it = M.getFieldsRead(); it.hasNext();) {
|
||||||
|
result.add(it.next());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<FieldReference> getFieldsWrittenFromShrikeBT(ShrikeCTMethodWrapper M) throws InvalidClassFileException {
|
||||||
|
// TODO move the logic here from ShrikeCTMethodWrapper
|
||||||
|
LinkedList<FieldReference> result = new LinkedList<FieldReference>();
|
||||||
|
for (Iterator<FieldReference> it = M.getFieldsWritten(); it.hasNext();) {
|
||||||
|
result.add(it.next());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean hasShrikeBTObjectArrayLoad(ShrikeCTMethodWrapper M) throws InvalidClassFileException {
|
||||||
|
for (Iterator it = M.getArraysRead(); it.hasNext();) {
|
||||||
|
TypeReference t = (TypeReference) it.next();
|
||||||
|
if (t.isReferenceType()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Set <TypeReference>
|
||||||
|
*/
|
||||||
|
public static Set<TypeReference> getCaughtExceptions(SSAInstruction[] statements) {
|
||||||
|
final HashSet<TypeReference> result = HashSetFactory.make(10);
|
||||||
|
Visitor v = new Visitor() {
|
||||||
|
public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) {
|
||||||
|
Collection<TypeReference> t = instruction.getExceptionTypes();
|
||||||
|
result.addAll(t);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (int i = 0; i < statements.length; i++) {
|
||||||
|
SSAInstruction s = statements[i];
|
||||||
|
if (s != null) {
|
||||||
|
s.visit(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public static Iterator<TypeReference> iterateCastTypes(SSAInstruction[] statements) {
|
||||||
|
final HashSet<TypeReference> result = HashSetFactory.make(10);
|
||||||
|
for (int i = 0; i < statements.length; i++) {
|
||||||
|
if (statements[i] != null) {
|
||||||
|
if (statements[i] instanceof SSACheckCastInstruction) {
|
||||||
|
SSACheckCastInstruction c = (SSACheckCastInstruction) statements[i];
|
||||||
|
result.add(c.getDeclaredResultType());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param statements
|
||||||
|
* list of ssa statements
|
||||||
|
* @return List of InvokeInstruction
|
||||||
|
*/
|
||||||
|
private static List<CallSiteReference> getCallSites(SSAInstruction[] statements) {
|
||||||
|
final List<CallSiteReference> result = new LinkedList<CallSiteReference>();
|
||||||
|
Visitor v = new Visitor() {
|
||||||
|
public void visitInvoke(SSAInvokeInstruction instruction) {
|
||||||
|
result.add(instruction.getCallSite());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (int i = 0; i < statements.length; i++) {
|
||||||
|
SSAInstruction s = statements[i];
|
||||||
|
if (s != null) {
|
||||||
|
s.visit(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param statements
|
||||||
|
* list of ssa statements
|
||||||
|
* @return List of InvokeInstruction
|
||||||
|
*/
|
||||||
|
private static List<NewSiteReference> getNewSites(SSAInstruction[] statements) {
|
||||||
|
final List<NewSiteReference> result = new LinkedList<NewSiteReference>();
|
||||||
|
Visitor v = new Visitor() {
|
||||||
|
public void visitNew(SSANewInstruction instruction) {
|
||||||
|
result.add(instruction.getNewSite());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (int i = 0; i < statements.length; i++) {
|
||||||
|
SSAInstruction s = statements[i];
|
||||||
|
if (s != null) {
|
||||||
|
s.visit(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param statements
|
||||||
|
* list of ssa statements
|
||||||
|
* @return List of FieldReference
|
||||||
|
*/
|
||||||
|
public static List<FieldReference> getFieldsRead(SSAInstruction[] statements) {
|
||||||
|
final List<FieldReference> result = new LinkedList<FieldReference>();
|
||||||
|
Visitor v = new Visitor() {
|
||||||
|
public void visitGet(SSAGetInstruction instruction) {
|
||||||
|
result.add(instruction.getDeclaredField());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (int i = 0; i < statements.length; i++) {
|
||||||
|
SSAInstruction s = statements[i];
|
||||||
|
if (s != null) {
|
||||||
|
s.visit(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param statements
|
||||||
|
* list of ssa statements
|
||||||
|
* @return List of FieldReference
|
||||||
|
*/
|
||||||
|
public static List<FieldReference> getFieldsWritten(SSAInstruction[] statements) {
|
||||||
|
final List<FieldReference> result = new LinkedList<FieldReference>();
|
||||||
|
Visitor v = new Visitor() {
|
||||||
|
public void visitPut(SSAPutInstruction instruction) {
|
||||||
|
result.add(instruction.getDeclaredField());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (int i = 0; i < statements.length; i++) {
|
||||||
|
SSAInstruction s = statements[i];
|
||||||
|
if (s != null) {
|
||||||
|
s.visit(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasObjectArrayLoad(SSAInstruction[] statements) {
|
||||||
|
|
||||||
|
class ScanVisitor extends Visitor {
|
||||||
|
boolean foundOne = false;
|
||||||
|
|
||||||
|
public void visitArrayLoad(SSAArrayLoadInstruction instruction) {
|
||||||
|
if (!instruction.typeIsPrimitive()) {
|
||||||
|
foundOne = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ScanVisitor v = new ScanVisitor();
|
||||||
|
for (int i = 0; i < statements.length; i++) {
|
||||||
|
SSAInstruction s = statements[i];
|
||||||
|
if (s != null) {
|
||||||
|
s.visit(v);
|
||||||
|
}
|
||||||
|
if (v.foundOne) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasObjectArrayStore(SSAInstruction[] statements) {
|
||||||
|
|
||||||
|
class ScanVisitor extends Visitor {
|
||||||
|
boolean foundOne = false;
|
||||||
|
|
||||||
|
public void visitArrayStore(SSAArrayStoreInstruction instruction) {
|
||||||
|
if (!instruction.typeIsPrimitive()) {
|
||||||
|
foundOne = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ScanVisitor v = new ScanVisitor();
|
||||||
|
for (int i = 0; i < statements.length; i++) {
|
||||||
|
SSAInstruction s = statements[i];
|
||||||
|
if (s != null) {
|
||||||
|
s.visit(v);
|
||||||
|
}
|
||||||
|
if (v.foundOne) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public abstract class DirectoryTreeModule implements Module {
|
||||||
|
|
||||||
|
protected final File root;
|
||||||
|
|
||||||
|
DirectoryTreeModule(File root) {
|
||||||
|
this.root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract FileModule makeFile(File file);
|
||||||
|
|
||||||
|
protected abstract boolean includeFile(File file);
|
||||||
|
|
||||||
|
private Set<ModuleEntry> getEntriesRecursive(File dir) {
|
||||||
|
Set<ModuleEntry> result = new HashSet<ModuleEntry>();
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
if (files[i].isDirectory())
|
||||||
|
result.addAll(getEntriesRecursive(files[i]));
|
||||||
|
else if (includeFile(files[i]))
|
||||||
|
result.add(makeFile(files[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<ModuleEntry> getEntries() {
|
||||||
|
return getEntriesRecursive(root).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return root.getAbsolutePath();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import com.ibm.wala.shrikeCT.ClassConstants;
|
||||||
|
import com.ibm.wala.types.FieldReference;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.Atom;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Implementation of a canonical field reference. TODO: canonicalize these?
|
||||||
|
* TODO: don't cache fieldType here .. move to class?
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public final class FieldImpl implements IField {
|
||||||
|
|
||||||
|
private final IClass declaringClass;
|
||||||
|
private final FieldReference fieldRef;
|
||||||
|
private final int accessFlags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor when the field type is not a primitive
|
||||||
|
*/
|
||||||
|
public FieldImpl(IClass declaringClass, FieldReference canonicalRef,int accessFlags) {
|
||||||
|
this.declaringClass = declaringClass;
|
||||||
|
this.fieldRef = canonicalRef;
|
||||||
|
this.accessFlags = accessFlags;
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(declaringClass != null);
|
||||||
|
Assertions._assert(fieldRef != null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMember#getDeclaringClass()
|
||||||
|
*/
|
||||||
|
public IClass getDeclaringClass() {
|
||||||
|
return declaringClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
// instanceof is OK because this class is final
|
||||||
|
if (obj instanceof FieldImpl) {
|
||||||
|
FieldImpl other = (FieldImpl) obj;
|
||||||
|
return fieldRef.equals(other.fieldRef) && declaringClass.equals(other.declaringClass);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return 87049 * declaringClass.hashCode() + fieldRef.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
FieldReference fr = getFieldReference();
|
||||||
|
return fr.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldReference getFieldReference() {
|
||||||
|
return FieldReference.findOrCreate(getDeclaringClass().getReference(), getName(), getFieldTypeReference());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMember#getName()
|
||||||
|
*/
|
||||||
|
public Atom getName() {
|
||||||
|
return fieldRef.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IField#getFieldTypeReference()
|
||||||
|
*/
|
||||||
|
public TypeReference getFieldTypeReference() {
|
||||||
|
return fieldRef.getFieldType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStatic() {
|
||||||
|
return ((accessFlags & ClassConstants.ACC_STATIC) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isFinal() {
|
||||||
|
return ((accessFlags & ClassConstants.ACC_FINAL) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrivate() {
|
||||||
|
return ((accessFlags & ClassConstants.ACC_PRIVATE) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isProtected() {
|
||||||
|
return ((accessFlags & ClassConstants.ACC_PROTECTED) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPublic() {
|
||||||
|
return ((accessFlags & ClassConstants.ACC_PUBLIC) != 0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.util.collections.NonNullSingletonIterator;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A module which is a wrapper around a file in the filesystem
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public abstract class FileModule implements Module, ModuleEntry {
|
||||||
|
|
||||||
|
private final File file;
|
||||||
|
|
||||||
|
public FileModule(File f) {
|
||||||
|
this.file = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAbsolutePath() {
|
||||||
|
return file.getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.Module#getEntries()
|
||||||
|
*/
|
||||||
|
public Iterator<ModuleEntry> getEntries() {
|
||||||
|
return new NonNullSingletonIterator<ModuleEntry>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return file.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.FileModule#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o.getClass().equals(getClass())) {
|
||||||
|
FileModule other = (FileModule)o;
|
||||||
|
return getName().equals(other.getName());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#getName()
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return file.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#getInputStream()
|
||||||
|
*/
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
try {
|
||||||
|
return new FileInputStream(file);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE("could not read " + file);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#isModuleFile()
|
||||||
|
*/
|
||||||
|
public boolean isModuleFile() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#asModule()
|
||||||
|
*/
|
||||||
|
public Module asModule() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return Returns the file.
|
||||||
|
*/
|
||||||
|
public File getFile() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||||
|
import com.ibm.wala.types.Selector;
|
||||||
|
import com.ibm.wala.types.TypeName;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.Atom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Basic interface for an object that represents a single Java class
|
||||||
|
* for analysis purposes, including array classes.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public interface IClass {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the object that represents the defining class loader
|
||||||
|
* for this class.
|
||||||
|
* @return the object that represents the defining class loader
|
||||||
|
* for this class.
|
||||||
|
*/
|
||||||
|
IClassLoader getClassLoader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this class a Java interface?
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean isInterface();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true iff this class is abstract
|
||||||
|
*/
|
||||||
|
boolean isAbstract();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the integer that encodes the class's modifiers,
|
||||||
|
* as defined by the JVM specification
|
||||||
|
* @return the integer that encodes the class's modifiers,
|
||||||
|
* as defined by the JVM specification
|
||||||
|
*/
|
||||||
|
int getModifiers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the superclass, or null if java.lang.Object
|
||||||
|
*/
|
||||||
|
IClass getSuperclass() throws ClassHierarchyException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection of (IClass) interfaces this class directly implements
|
||||||
|
*/
|
||||||
|
Collection<IClass> getDirectInterfaces() throws ClassHierarchyException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection of (IClass) interfaces this class implements, including
|
||||||
|
* all ancestors of interfaces immediately implemented
|
||||||
|
*/
|
||||||
|
Collection<IClass> getAllImplementedInterfaces() throws ClassHierarchyException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection of (IClass) interfaces this class extends, including
|
||||||
|
* transitive ancestors
|
||||||
|
*/
|
||||||
|
Collection<IClass> getAllAncestorInterfaces() throws ClassHierarchyException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds method matching signature. Delegates to superclass if not
|
||||||
|
* found.
|
||||||
|
*
|
||||||
|
* @param selector a method signature
|
||||||
|
* @return IMethod from this class matching the signature; null
|
||||||
|
* if not found in this class or any superclass.
|
||||||
|
*/
|
||||||
|
IMethod getMethod(Selector selector);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a field.
|
||||||
|
*/
|
||||||
|
IField getField(Atom name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return canonical TypeReference corresponding to this class
|
||||||
|
*/
|
||||||
|
TypeReference getReference();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return String holding the name of the source file that defined
|
||||||
|
* this class, or null if none found
|
||||||
|
*/
|
||||||
|
String getSourceFileName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the method that is this class's initializer, or null if none
|
||||||
|
*/
|
||||||
|
IMethod getClassInitializer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true iff the class is an array class.
|
||||||
|
*/
|
||||||
|
boolean isArrayClass();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an Iterator of the IMethods declared by this class.
|
||||||
|
*/
|
||||||
|
Iterator<IMethod> getDeclaredMethods();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the instance fields declared by this class or any of
|
||||||
|
* its superclasses.
|
||||||
|
*
|
||||||
|
* @return Collection of IFields
|
||||||
|
* @throws ClassHierarchyException
|
||||||
|
*/
|
||||||
|
Collection<IField> getAllInstanceFields() throws ClassHierarchyException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the static fields declared by this class or any of
|
||||||
|
* its superclasses.
|
||||||
|
*
|
||||||
|
* @return Collection of IFields
|
||||||
|
* @throws ClassHierarchyException
|
||||||
|
*/
|
||||||
|
Collection<IField> getAllStaticFields() throws ClassHierarchyException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the instance and static fields declared by this class or
|
||||||
|
* any of its superclasses.
|
||||||
|
*
|
||||||
|
* @return Collection of IFields
|
||||||
|
* @throws ClassHierarchyException
|
||||||
|
*/
|
||||||
|
Collection<IField> getAllFields() throws ClassHierarchyException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the methods declared by this class or
|
||||||
|
* any of its superclasses.
|
||||||
|
*
|
||||||
|
* @return Collection of IMethods
|
||||||
|
* @throws ClassHierarchyException
|
||||||
|
*/
|
||||||
|
Collection getAllMethods() throws ClassHierarchyException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the instance fields declared by this class.
|
||||||
|
*
|
||||||
|
* @return Collection of IFields
|
||||||
|
*/
|
||||||
|
Collection<IField> getDeclaredInstanceFields();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection of IField
|
||||||
|
*/
|
||||||
|
Collection<IField> getDeclaredStaticFields();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the TypeName for this class
|
||||||
|
*/
|
||||||
|
TypeName getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does 'this' refer to a reference type? If not, then it refers
|
||||||
|
* to a primitive type.
|
||||||
|
*/
|
||||||
|
boolean isReferenceType();
|
||||||
|
}
|
|
@ -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.classLoader;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
|
import com.ibm.wala.types.TypeName;
|
||||||
|
import com.ibm.wala.util.Atom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Base class for an object that represents a single
|
||||||
|
* Java classloader for analysis purposes.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public interface IClassLoader {
|
||||||
|
/**
|
||||||
|
* Find and return the IClass defined by this class loader that
|
||||||
|
* corresponds to the given class name.
|
||||||
|
*
|
||||||
|
* @param className name of the class
|
||||||
|
* @return the IClass defined by this class loader that
|
||||||
|
* corresponds to the given class name, or null if not found.
|
||||||
|
*/
|
||||||
|
public abstract IClass lookupClass(TypeName className);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the ClassLoaderReference for this class loader.
|
||||||
|
* @return ClassLoaderReference
|
||||||
|
*/
|
||||||
|
public abstract ClassLoaderReference getReference();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an Iterator of all classees loaded by this loader
|
||||||
|
*/
|
||||||
|
public abstract Iterator<IClass> iterateAllClasses();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of classes in scope to be loaded by this loader
|
||||||
|
*/
|
||||||
|
public abstract int getNumberOfClasses();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the unique name that identifies this class loader.
|
||||||
|
*/
|
||||||
|
Atom getName();
|
||||||
|
|
||||||
|
public abstract int getNumberOfMethods();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param klass
|
||||||
|
* @return name of source file corresponding to the class
|
||||||
|
*/
|
||||||
|
public abstract String getSourceFileName(IClass klass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the parent IClassLoader, if any, or null
|
||||||
|
*/
|
||||||
|
public abstract IClassLoader getParent();
|
||||||
|
|
||||||
|
public abstract void init(Set modules) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* blow away references to any classes in the set
|
||||||
|
* @param toRemove Collection<IClass>
|
||||||
|
*/
|
||||||
|
public abstract void removeAll(Collection<IClass> toRemove);
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import com.ibm.wala.types.FieldReference;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface IField extends IMember {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the type of the declared type of the field
|
||||||
|
*/
|
||||||
|
public TypeReference getFieldTypeReference();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FieldReference representing this field
|
||||||
|
*/
|
||||||
|
public FieldReference getFieldReference();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this field final?
|
||||||
|
*/
|
||||||
|
public boolean isFinal();
|
||||||
|
|
||||||
|
public boolean isPrivate();
|
||||||
|
public boolean isProtected();
|
||||||
|
public boolean isPublic();
|
||||||
|
public boolean isStatic();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import com.ibm.wala.util.Atom;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Basic interface for an object that represents a single
|
||||||
|
* Java member (method or field) for analysis purposes.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public interface IMember {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the object that represents the declaring class
|
||||||
|
* for this member.
|
||||||
|
* @return the object that represents the declaring class
|
||||||
|
* for this member.
|
||||||
|
*/
|
||||||
|
IClass getDeclaringClass();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return the name of this member
|
||||||
|
*/
|
||||||
|
Atom getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this method static?
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean isStatic();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,184 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.callgraph.ContextItem;
|
||||||
|
import com.ibm.wala.types.Descriptor;
|
||||||
|
import com.ibm.wala.types.MethodReference;
|
||||||
|
import com.ibm.wala.types.Selector;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Basic interface for an object that represents a single Java method for
|
||||||
|
* analysis purposes.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public interface IMethod extends IMember, ContextItem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this method synchronized?
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean isSynchronized();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this method a class initializer?
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean isClinit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this method an object initializer?
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean isInit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this method native?
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean isNative();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Did someone synthesize this method? (As opposed to reading it from a class
|
||||||
|
* file)
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean isSynthetic();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this method abstract?
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean isAbstract();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this method private?
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean isPrivate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this method protected?
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean isProtected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this method public?
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean isPublic();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this method final?
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
boolean isFinal();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return canonical MethodReference corresponding to this method
|
||||||
|
*/
|
||||||
|
MethodReference getReference();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return maximum number of JVM locals used by this method
|
||||||
|
*/
|
||||||
|
int getMaxLocals();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return maximum height of JVM stack used by this method
|
||||||
|
*/
|
||||||
|
int getMaxStackHeight();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true iff this method has at least one exception handler
|
||||||
|
*/
|
||||||
|
boolean hasExceptionHandler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getParameterType. By convention, for a non-static method,
|
||||||
|
* getParameterType(0) is the this pointer
|
||||||
|
*/
|
||||||
|
TypeReference getParameterType(int i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name of the return type for this method
|
||||||
|
*/
|
||||||
|
TypeReference getReturnType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getNumberOfParameters. This result includes the "this" pointer if
|
||||||
|
* applicable
|
||||||
|
*/
|
||||||
|
int getNumberOfParameters();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an array of the exception types declared by the throws clause for
|
||||||
|
* this method, or null if there are none
|
||||||
|
*/
|
||||||
|
TypeReference[] getDeclaredExceptions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the source line number corresponding to a particular bytecode
|
||||||
|
* index, or -1 if the information is not available.
|
||||||
|
*/
|
||||||
|
int getLineNumber(int bcIndex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the (source code) name of the local variable of a given number at
|
||||||
|
* the specified program counter, or null if the information is not
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
String getLocalVariableName(int bcIndex, int localNumber);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getSignature. something like:
|
||||||
|
* com.foo.bar.createLargeOrder(IILjava.lang.String;SLjava.sql.Date;)Ljava.lang.Integer;
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String getSignature();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getSignature. something like:
|
||||||
|
* createLargeOrder(IILjava.lang.String;SLjava.sql.Date;)Ljava.lang.Integer;
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public Selector getSelector();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getDescriptor. something like:
|
||||||
|
* (IILjava.lang.String;SLjava.sql.Date;)Ljava.lang.Integer;
|
||||||
|
*
|
||||||
|
* @return Descriptor
|
||||||
|
*/
|
||||||
|
Descriptor getDescriptor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true iff the local variable table information for this method is
|
||||||
|
* available
|
||||||
|
*/
|
||||||
|
boolean hasLocalVariableTable();
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* An interface for something that carries a location in bytecode
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public interface IProgramCounter {
|
||||||
|
/**
|
||||||
|
* A constant indicating no source line number information is available.
|
||||||
|
*/
|
||||||
|
public static final int NO_SOURCE_LINE_NUMBER = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the program counter (index into the method's bytecode)
|
||||||
|
* for this call site.
|
||||||
|
* @return the program counter (index into the method's bytecode)
|
||||||
|
* for this call site.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract int getProgramCounter();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.io.FileSuffixes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* An entry in a Jar file.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class JarFileEntry implements ModuleEntry {
|
||||||
|
|
||||||
|
private final String entryName;
|
||||||
|
private final JarFileModule jarFileModule;
|
||||||
|
private final JarFile jarFile;
|
||||||
|
JarFileEntry(String entryName, JarFileModule jarFile) {
|
||||||
|
this.entryName = entryName;
|
||||||
|
this.jarFileModule = jarFile;
|
||||||
|
this.jarFile = jarFile.getJarFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#getName()
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return entryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#isClassFile()
|
||||||
|
*/
|
||||||
|
public boolean isClassFile() {
|
||||||
|
return FileSuffixes.isClassFile(getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#getInputStream()
|
||||||
|
*/
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
try {
|
||||||
|
return jarFile.getInputStream(jarFile.getEntry(entryName));
|
||||||
|
} catch (Exception e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#getSize()
|
||||||
|
*/
|
||||||
|
public long getSize() {
|
||||||
|
// TODO: cache this?
|
||||||
|
return jarFile.getEntry(entryName).getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return jarFile.getName() + ":" + getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#isModuleFile()
|
||||||
|
*/
|
||||||
|
public boolean isModuleFile() {
|
||||||
|
return FileSuffixes.isJarFile(getName()) || FileSuffixes.isWarFile(getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#asModule()
|
||||||
|
*/
|
||||||
|
public Module asModule() {
|
||||||
|
return new NestedJarFileModule(jarFileModule,jarFile.getEntry(entryName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public JarFile getJarFile() {
|
||||||
|
return jarFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return entryName.hashCode() * 5059 + jarFile.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#getClassName()
|
||||||
|
*/
|
||||||
|
public String getClassName() {
|
||||||
|
return FileSuffixes.stripSuffix(getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile()
|
||||||
|
*/
|
||||||
|
public boolean isSourceFile() {
|
||||||
|
return FileSuffixes.isSourceFile(getName());
|
||||||
|
}
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return this == obj;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.classLoader;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
import com.ibm.wala.util.CacheReference;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.collections.HashSetFactory;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A module which is a wrapper around a Jar file
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class JarFileModule implements Module {
|
||||||
|
|
||||||
|
private final JarFile file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For efficiency, try to cache the byte[] holding each ZipEntries contents;
|
||||||
|
* this will help avoid multiple unzipping
|
||||||
|
*/
|
||||||
|
private final HashMap<ZipEntry, Object> cache = HashMapFactory.make();
|
||||||
|
|
||||||
|
public JarFileModule(JarFile f) {
|
||||||
|
this.file = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAbsolutePath() {
|
||||||
|
return file.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "JarFileModule:" + file.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.Module#getEntries()
|
||||||
|
*/
|
||||||
|
public Iterator<ModuleEntry> getEntries() {
|
||||||
|
HashSet<ModuleEntry> result = HashSetFactory.make();
|
||||||
|
for (Enumeration e = file.entries(); e.hasMoreElements();) {
|
||||||
|
ZipEntry Z = (ZipEntry) e.nextElement();
|
||||||
|
result.add(new JarFileEntry(Z.getName(), this));
|
||||||
|
}
|
||||||
|
return result.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return file.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object arg0) {
|
||||||
|
if (getClass().equals(arg0.getClass())) {
|
||||||
|
JarFileModule other = (JarFileModule) arg0;
|
||||||
|
return file.equals(other.file);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getContents(ZipEntry entry) {
|
||||||
|
byte[] b = (byte[]) CacheReference.get(cache.get(entry));
|
||||||
|
|
||||||
|
if (b != null) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
InputStream s = file.getInputStream(entry);
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
b = new byte[1024];
|
||||||
|
int n = s.read(b);
|
||||||
|
while (n != -1) {
|
||||||
|
out.write(b, 0, n);
|
||||||
|
n = s.read(b);
|
||||||
|
}
|
||||||
|
byte[] bb = out.toByteArray();
|
||||||
|
cache.put(entry, CacheReference.make(bb));
|
||||||
|
s.close();
|
||||||
|
return bb;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JarFile getJarFile() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A Module represents a set of files to analyze. eg., a Jar file.
|
||||||
|
* These are persistent (hung onto by ClassLoaderReference) .. so,
|
||||||
|
* a Module should not hold onto a lot of data.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public interface Module {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an Iterator of the ModuleEntries in this Module.
|
||||||
|
*/
|
||||||
|
Iterator<ModuleEntry> getEntries();
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A ModuleEntry represents a wrapper around a file representation
|
||||||
|
* in a Module.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public interface ModuleEntry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a String that represents the name of the file described
|
||||||
|
* by this object
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the file is a class file.
|
||||||
|
*/
|
||||||
|
boolean isClassFile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the file is a source file.
|
||||||
|
*/
|
||||||
|
boolean isSourceFile();
|
||||||
|
|
||||||
|
InputStream getInputStream();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true iff this module entry (file) represents a module in its own right.
|
||||||
|
* e.g., a jar file which is an entry in another jar file.
|
||||||
|
*/
|
||||||
|
boolean isModuleFile();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Precondition: isModuleFile().
|
||||||
|
* @return a Module view of this entry.
|
||||||
|
*/
|
||||||
|
Module asModule();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name of the class represented by this entry
|
||||||
|
* @throws UnsupportedOperationException if !isClassFile() nad !isSourceFile()
|
||||||
|
*/
|
||||||
|
String getClassName();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,242 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.jar.JarInputStream;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
|
import com.ibm.wala.shrikeCT.ClassReader;
|
||||||
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.debug.Trace;
|
||||||
|
import com.ibm.wala.util.io.FileSuffixes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A Jar file nested in a parent jar file
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class NestedJarFileModule implements Module {
|
||||||
|
|
||||||
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
|
private final JarFileModule parent;
|
||||||
|
private final ZipEntry entry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For efficiency, we cache the byte[] holding each ZipEntry's contents; this
|
||||||
|
* will help avoid multiple unzipping TODO: use a soft reference?
|
||||||
|
*/
|
||||||
|
private HashMap<String, byte[]> cache = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public NestedJarFileModule(JarFileModule parent, ZipEntry entry) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getInputStream(String name) {
|
||||||
|
populateCache();
|
||||||
|
byte[] b = cache.get(name);
|
||||||
|
return new ByteArrayInputStream(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateCache() {
|
||||||
|
if (cache != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
cache = HashMapFactory.make();
|
||||||
|
final byte[] b = parent.getContents(entry);
|
||||||
|
final JarInputStream stream = new JarInputStream(new ByteArrayInputStream(b));
|
||||||
|
for (ZipEntry z = stream.getNextEntry(); z != null; z = stream.getNextEntry()) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("got entry: " + z.getName());
|
||||||
|
}
|
||||||
|
if (FileSuffixes.isClassFile(z.getName()) || FileSuffixes.isSourceFile(z.getName())) {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
byte[] temp = new byte[1024];
|
||||||
|
int n = stream.read(temp);
|
||||||
|
while (n != -1) {
|
||||||
|
out.write(temp, 0, n);
|
||||||
|
n = stream.read(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] bb = out.toByteArray();
|
||||||
|
try {
|
||||||
|
if (FileSuffixes.isClassFile(z.getName())) {
|
||||||
|
// check that we can read without an InvalidClassFileException
|
||||||
|
new ClassReader(bb);
|
||||||
|
}
|
||||||
|
cache.put(z.getName(), bb);
|
||||||
|
} catch (InvalidClassFileException e1) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e1.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long getEntrySize(String name) {
|
||||||
|
populateCache();
|
||||||
|
byte[] b = cache.get(name);
|
||||||
|
return b.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.Module#getEntries()
|
||||||
|
*/
|
||||||
|
public Iterator<ModuleEntry> getEntries() {
|
||||||
|
populateCache();
|
||||||
|
final Iterator<String> it = cache.keySet().iterator();
|
||||||
|
return new Iterator<ModuleEntry>() {
|
||||||
|
String next = null;
|
||||||
|
{
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void advance() {
|
||||||
|
if (it.hasNext()) {
|
||||||
|
next = it.next();
|
||||||
|
} else {
|
||||||
|
next = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
return next != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModuleEntry next() {
|
||||||
|
ModuleEntry result = new Entry(next);
|
||||||
|
advance();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
* an entry in a nested jar file.
|
||||||
|
*/
|
||||||
|
private class Entry implements ModuleEntry {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
Entry(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#getName()
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#isClassFile()
|
||||||
|
*/
|
||||||
|
public boolean isClassFile() {
|
||||||
|
return FileSuffixes.isClassFile(getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#getInputStream()
|
||||||
|
*/
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
return NestedJarFileModule.this.getInputStream(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getSize() {
|
||||||
|
return NestedJarFileModule.this.getEntrySize(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#isModuleFile()
|
||||||
|
*/
|
||||||
|
public boolean isModuleFile() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#asModule()
|
||||||
|
*/
|
||||||
|
public Module asModule() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "nested entry: " + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#getClassName()
|
||||||
|
*/
|
||||||
|
public String getClassName() {
|
||||||
|
return FileSuffixes.stripSuffix(getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile()
|
||||||
|
*/
|
||||||
|
public boolean isSourceFile() {
|
||||||
|
return FileSuffixes.isSourceFile(getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "Nested Jar File:" + entry.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.classLoader;
|
||||||
|
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Represents a textual allocation site
|
||||||
|
*
|
||||||
|
* @author dolby
|
||||||
|
*/
|
||||||
|
public class NewSiteReference extends ProgramCounter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type allocated
|
||||||
|
*/
|
||||||
|
private final TypeReference declaredType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param programCounter bytecode index of the allocation site
|
||||||
|
* @param declaredType declared type that is allocated
|
||||||
|
*/
|
||||||
|
public NewSiteReference(int programCounter, TypeReference declaredType) {
|
||||||
|
super(programCounter);
|
||||||
|
this.declaredType = declaredType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeReference getDeclaredType() {
|
||||||
|
return declaredType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NewSiteReference make(int programCounter, TypeReference declaredType) {
|
||||||
|
return new NewSiteReference(programCounter, declaredType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "NEW " + declaredType + "@" + getProgramCounter();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Simple object that represents a program counter value
|
||||||
|
* (ie., an instruction in the bytecode)
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class ProgramCounter implements IProgramCounter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index into bytecode describing this instruction
|
||||||
|
*/
|
||||||
|
private final int programCounter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param programCounter Index into bytecode describing this instruction
|
||||||
|
*/
|
||||||
|
public ProgramCounter(final int programCounter) {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(programCounter >= 0);
|
||||||
|
}
|
||||||
|
this.programCounter = programCounter;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the program counter (index into the method's bytecode)
|
||||||
|
* for this call site.
|
||||||
|
* @return the program counter (index into the method's bytecode)
|
||||||
|
* for this call site.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public int getProgramCounter() {
|
||||||
|
return programCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Program Counter value is enough to uniquely identify a call site reference
|
||||||
|
* within a method.
|
||||||
|
*
|
||||||
|
* Note: must use these objects with extreme care; this only works if you never
|
||||||
|
* mix ProgramLocations from different methods in the same collection.
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#equals(Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return
|
||||||
|
(obj instanceof ProgramCounter)
|
||||||
|
&&
|
||||||
|
((ProgramCounter) obj).programCounter == programCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return programCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "PC@" + programCounter;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,925 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.ibm.wala.shrikeBT.ArrayLoadInstruction;
|
||||||
|
import com.ibm.wala.shrikeBT.ArrayStoreInstruction;
|
||||||
|
import com.ibm.wala.shrikeBT.BytecodeConstants;
|
||||||
|
import com.ibm.wala.shrikeBT.CheckCastInstruction;
|
||||||
|
import com.ibm.wala.shrikeBT.Constants;
|
||||||
|
import com.ibm.wala.shrikeBT.Decoder;
|
||||||
|
import com.ibm.wala.shrikeBT.ExceptionHandler;
|
||||||
|
import com.ibm.wala.shrikeBT.GetInstruction;
|
||||||
|
import com.ibm.wala.shrikeBT.IInvokeInstruction;
|
||||||
|
import com.ibm.wala.shrikeBT.Instruction;
|
||||||
|
import com.ibm.wala.shrikeBT.InvokeInstruction;
|
||||||
|
import com.ibm.wala.shrikeBT.MonitorInstruction;
|
||||||
|
import com.ibm.wala.shrikeBT.NewInstruction;
|
||||||
|
import com.ibm.wala.shrikeBT.PutInstruction;
|
||||||
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
|
import com.ibm.wala.types.Descriptor;
|
||||||
|
import com.ibm.wala.types.FieldReference;
|
||||||
|
import com.ibm.wala.types.MethodReference;
|
||||||
|
import com.ibm.wala.types.Selector;
|
||||||
|
import com.ibm.wala.types.TypeName;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.Atom;
|
||||||
|
import com.ibm.wala.util.Exceptions;
|
||||||
|
import com.ibm.wala.util.ImmutableByteArray;
|
||||||
|
import com.ibm.wala.util.ShrikeUtil;
|
||||||
|
import com.ibm.wala.util.bytecode.BytecodeStream;
|
||||||
|
import com.ibm.wala.util.collections.EmptyIterator;
|
||||||
|
import com.ibm.wala.util.collections.HashSetFactory;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A wrapper around a Shrike object that represents a method
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public abstract class ShrikeBTMethodWrapper implements IMethod, BytecodeConstants {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some verbose progress output?
|
||||||
|
*/
|
||||||
|
private final static boolean verbose = false;
|
||||||
|
|
||||||
|
private static int methodsParsed = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around the declaring class.
|
||||||
|
*/
|
||||||
|
protected final IClass declaringClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Canonical reference for this method
|
||||||
|
*/
|
||||||
|
private MethodReference methodReference;
|
||||||
|
|
||||||
|
// break these out to save some space; they're computed lazily.
|
||||||
|
protected static class BytecodeInfo {
|
||||||
|
Decoder decoder;
|
||||||
|
|
||||||
|
CallSiteReference[] callSites;
|
||||||
|
|
||||||
|
FieldReference[] fieldsWritten;
|
||||||
|
|
||||||
|
FieldReference[] fieldsRead;
|
||||||
|
|
||||||
|
NewSiteReference[] newSites;
|
||||||
|
|
||||||
|
TypeReference[] arraysRead;
|
||||||
|
|
||||||
|
TypeReference[] arraysWritten;
|
||||||
|
|
||||||
|
TypeReference[] implicitExceptions;
|
||||||
|
|
||||||
|
TypeReference[] castTypes;
|
||||||
|
|
||||||
|
boolean hasMonitorOp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping from instruction index to program counter.
|
||||||
|
*/
|
||||||
|
private int[] pcMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cached map representing line number information in ShrikeCT format TODO:
|
||||||
|
* do more careful caching than just soft references
|
||||||
|
*/
|
||||||
|
protected int[] lineNumberMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an array mapping bytecode offsets to arrays representing the local
|
||||||
|
* variable maps for each offset; a local variable map is represented as an
|
||||||
|
* array of localVars*2 elements, containing a pair (nameIndex, typeIndex)
|
||||||
|
* for each local variable; a pair (0,0) indicates there is no information
|
||||||
|
* for that local variable at that offset
|
||||||
|
*/
|
||||||
|
protected int[][] localVariableMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception types this method might throw. Computed on demand.
|
||||||
|
*/
|
||||||
|
private TypeReference[] exceptionTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache the information about the method statements.
|
||||||
|
*/
|
||||||
|
protected BytecodeInfo bcInfo;
|
||||||
|
|
||||||
|
public ShrikeBTMethodWrapper(IClass klass) {
|
||||||
|
this.declaringClass = klass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the program counter (bytecode index) for a particular Shrike
|
||||||
|
* instruction index.
|
||||||
|
*
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public int getBytecodeIndex(int instructionIndex) throws InvalidClassFileException {
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
return bcInfo.pcMap[instructionIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an Iterator of CallSiteReferences from this method.
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
Iterator<CallSiteReference> getCallSites() throws InvalidClassFileException {
|
||||||
|
if (isNative()) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
Iterator<CallSiteReference> empty = EmptyIterator.instance();
|
||||||
|
return (bcInfo.callSites == null) ? empty : Arrays.asList(bcInfo.callSites).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an Iterator of NewlSiteReferences from this method.
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
Iterator<NewSiteReference> getNewSites() throws InvalidClassFileException {
|
||||||
|
if (isNative()) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
Iterator<NewSiteReference> empty = EmptyIterator.instance();
|
||||||
|
return (bcInfo.newSites == null) ? empty : Arrays.asList(bcInfo.newSites).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Set <TypeReference>, the exceptions that statements in this method
|
||||||
|
* may throw,
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public Collection getImplicitExceptionTypes() throws InvalidClassFileException {
|
||||||
|
if (isNative()) {
|
||||||
|
return Collections.EMPTY_SET;
|
||||||
|
}
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
return (bcInfo.implicitExceptions == null) ? Arrays.asList(new TypeReference[0]) : Arrays.asList(bcInfo.implicitExceptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method processBytecodes. Do a cheap pass over the bytecodes to collect some
|
||||||
|
* mapping information. Some methods require this as a pre-req to accessing
|
||||||
|
* ShrikeCT information.
|
||||||
|
*
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public void processBytecodes() throws InvalidClassFileException {
|
||||||
|
if (bcInfo != null) {
|
||||||
|
// already done.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bcInfo = new BytecodeInfo();
|
||||||
|
bcInfo.exceptionTypes = computeDeclaredExceptions();
|
||||||
|
|
||||||
|
if (isNative()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (verbose) {
|
||||||
|
methodsParsed += 1;
|
||||||
|
if (methodsParsed % 100 == 0) {
|
||||||
|
System.out.println(methodsParsed + " methods processed...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processBytecodesWithShrikeBT();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true iff this method has a monitorenter or monitorexit
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public boolean hasMonitorOp() throws InvalidClassFileException {
|
||||||
|
if (isNative()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
return bcInfo.hasMonitorOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Set of FieldReference
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public Iterator<FieldReference> getFieldsWritten() throws InvalidClassFileException {
|
||||||
|
if (isNative()) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
if (bcInfo.fieldsWritten == null) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
} else {
|
||||||
|
List<FieldReference> l = Arrays.asList(bcInfo.fieldsWritten);
|
||||||
|
return l.iterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Iterator of FieldReference
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public Iterator<FieldReference> getFieldsRead() throws InvalidClassFileException {
|
||||||
|
if (isNative()) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
if (bcInfo.fieldsRead == null) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
} else {
|
||||||
|
List<FieldReference> l = Arrays.asList(bcInfo.fieldsRead);
|
||||||
|
return l.iterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Iterator of TypeReference
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public Iterator getArraysRead() throws InvalidClassFileException {
|
||||||
|
if (isNative()) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bcInfo.arraysRead == null) ? EmptyIterator.instance() : Arrays.asList(bcInfo.arraysRead).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Iterator of TypeReference
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public Iterator getArraysWritten() throws InvalidClassFileException {
|
||||||
|
if (isNative()) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bcInfo.arraysWritten == null) ? EmptyIterator.instance() : Arrays.asList(bcInfo.arraysWritten).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Iterator of TypeReference
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public Iterator getCastTypes() throws InvalidClassFileException {
|
||||||
|
if (isNative()) {
|
||||||
|
return EmptyIterator.instance();
|
||||||
|
}
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (bcInfo.castTypes == null) ? EmptyIterator.instance() : Arrays.asList(bcInfo.castTypes).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract byte[] getBytecodes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getBytecodeStream.
|
||||||
|
*
|
||||||
|
* @return the bytecode stream for this method, or null if no bytecodes.
|
||||||
|
*/
|
||||||
|
public BytecodeStream getBytecodeStream() {
|
||||||
|
byte[] bytecodes = getBytecodes();
|
||||||
|
if (bytecodes == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return new BytecodeStream(this, bytecodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getMethodName() throws InvalidClassFileException;
|
||||||
|
|
||||||
|
protected abstract String getMethodSignature() throws InvalidClassFileException;
|
||||||
|
|
||||||
|
private MethodReference computeMethodReference() {
|
||||||
|
try {
|
||||||
|
Atom name = Atom.findOrCreateUnicodeAtom(getMethodName());
|
||||||
|
ImmutableByteArray desc = ImmutableByteArray.make(getMethodSignature());
|
||||||
|
Descriptor D = Descriptor.findOrCreate(desc);
|
||||||
|
return
|
||||||
|
MethodReference.findOrCreate(declaringClass.getReference(), name, D);
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodReference getReference() {
|
||||||
|
if (methodReference == null) {
|
||||||
|
methodReference = computeMethodReference();
|
||||||
|
}
|
||||||
|
return methodReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClinit() {
|
||||||
|
return getReference().getSelector().equals(MethodReference.clinitSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInit() {
|
||||||
|
return getReference().getName().equals(MethodReference.initAtom);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract int getModifiers();
|
||||||
|
|
||||||
|
public boolean isNative() {
|
||||||
|
return ((getModifiers() & Constants.ACC_NATIVE) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAbstract() {
|
||||||
|
return ((getModifiers() & Constants.ACC_ABSTRACT) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrivate() {
|
||||||
|
return ((getModifiers() & Constants.ACC_PRIVATE) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isProtected() {
|
||||||
|
return ((getModifiers() & Constants.ACC_PROTECTED) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPublic() {
|
||||||
|
return ((getModifiers() & Constants.ACC_PUBLIC) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFinal() {
|
||||||
|
return ((getModifiers() & Constants.ACC_FINAL) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSynchronized() {
|
||||||
|
return ((getModifiers() & Constants.ACC_SYNCHRONIZED) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStatic() {
|
||||||
|
return ((getModifiers() & Constants.ACC_STATIC) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSynthetic() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IClass getDeclaringClass() {
|
||||||
|
return declaringClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the decoder object for this method, or create one if necessary.
|
||||||
|
*
|
||||||
|
* @return null if the method has no code.
|
||||||
|
*/
|
||||||
|
protected abstract Decoder makeDecoder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walk through the bytecodes and collect trivial information.
|
||||||
|
*
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
protected abstract void processDebugInfo(BytecodeInfo bcInfo) throws InvalidClassFileException;
|
||||||
|
|
||||||
|
|
||||||
|
private void processBytecodesWithShrikeBT() throws InvalidClassFileException {
|
||||||
|
bcInfo.decoder = makeDecoder();
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
if (!isAbstract() && bcInfo.decoder == null) {
|
||||||
|
Assertions.UNREACHABLE("bad method " + getReference());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bcInfo.decoder == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bcInfo.pcMap = bcInfo.decoder.getInstructionsToBytecodes();
|
||||||
|
|
||||||
|
processDebugInfo(bcInfo);
|
||||||
|
|
||||||
|
SimpleVisitor simpleVisitor = new SimpleVisitor();
|
||||||
|
|
||||||
|
Instruction[] instructions = bcInfo.decoder.getInstructions();
|
||||||
|
for (int i = 0; i < instructions.length; i++) {
|
||||||
|
simpleVisitor.setInstructionIndex(i);
|
||||||
|
instructions[i].visit(simpleVisitor);
|
||||||
|
if (Exceptions.isPEI(instructions[i])) {
|
||||||
|
Collection<TypeReference> t = Exceptions.getIndependentExceptionTypes(instructions[i]);
|
||||||
|
simpleVisitor.implicitExceptions.addAll(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the Set results into arrays; will use less
|
||||||
|
// storage
|
||||||
|
copyVisitorSetsToArrays(simpleVisitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyVisitorSetsToArrays(SimpleVisitor simpleVisitor) {
|
||||||
|
bcInfo.newSites = new NewSiteReference[simpleVisitor.newSites.size()];
|
||||||
|
int i = 0;
|
||||||
|
for (Iterator<NewSiteReference> it = simpleVisitor.newSites.iterator(); it.hasNext();) {
|
||||||
|
bcInfo.newSites[i++] = it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bcInfo.fieldsRead = new FieldReference[simpleVisitor.fieldsRead.size()];
|
||||||
|
i = 0;
|
||||||
|
for (Iterator<FieldReference> it = simpleVisitor.fieldsRead.iterator(); it.hasNext();) {
|
||||||
|
bcInfo.fieldsRead[i++] = it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bcInfo.fieldsRead = new FieldReference[simpleVisitor.fieldsRead.size()];
|
||||||
|
i = 0;
|
||||||
|
for (Iterator<FieldReference> it = simpleVisitor.fieldsRead.iterator(); it.hasNext();) {
|
||||||
|
bcInfo.fieldsRead[i++] = it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bcInfo.fieldsWritten = new FieldReference[simpleVisitor.fieldsWritten.size()];
|
||||||
|
i = 0;
|
||||||
|
for (Iterator<FieldReference> it = simpleVisitor.fieldsWritten.iterator(); it.hasNext();) {
|
||||||
|
bcInfo.fieldsWritten[i++] = it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bcInfo.callSites = new CallSiteReference[simpleVisitor.callSites.size()];
|
||||||
|
i = 0;
|
||||||
|
for (Iterator<CallSiteReference> it = simpleVisitor.callSites.iterator(); it.hasNext();) {
|
||||||
|
bcInfo.callSites[i++] = it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bcInfo.arraysRead = new TypeReference[simpleVisitor.arraysRead.size()];
|
||||||
|
i = 0;
|
||||||
|
for (Iterator<TypeReference> it = simpleVisitor.arraysRead.iterator(); it.hasNext();) {
|
||||||
|
bcInfo.arraysRead[i++] = it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bcInfo.arraysWritten = new TypeReference[simpleVisitor.arraysWritten.size()];
|
||||||
|
i = 0;
|
||||||
|
for (Iterator<TypeReference> it = simpleVisitor.arraysWritten.iterator(); it.hasNext();) {
|
||||||
|
bcInfo.arraysWritten[i++] = it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bcInfo.implicitExceptions = new TypeReference[simpleVisitor.implicitExceptions.size()];
|
||||||
|
i = 0;
|
||||||
|
for (Iterator it = simpleVisitor.implicitExceptions.iterator(); it.hasNext();) {
|
||||||
|
bcInfo.implicitExceptions[i++] = (TypeReference) it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bcInfo.castTypes = new TypeReference[simpleVisitor.castTypes.size()];
|
||||||
|
i = 0;
|
||||||
|
for (Iterator<TypeReference> it = simpleVisitor.castTypes.iterator(); it.hasNext();) {
|
||||||
|
bcInfo.castTypes[i++] = it.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
bcInfo.hasMonitorOp = simpleVisitor.hasMonitorOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return getReference().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#equals(Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
// instanceof is OK because this class is final.
|
||||||
|
// if (this.getClass().equals(obj.getClass())) {
|
||||||
|
if (obj instanceof ShrikeBTMethodWrapper) {
|
||||||
|
ShrikeBTMethodWrapper that = (ShrikeBTMethodWrapper) obj;
|
||||||
|
return (getDeclaringClass().equals(that.getDeclaringClass()) && getReference().equals(that.getReference()));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return 9661 * getReference().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getMaxLocals()
|
||||||
|
*/
|
||||||
|
public abstract int getMaxLocals();
|
||||||
|
|
||||||
|
// TODO: ShrikeBT should have a getMaxStack method on Decoder, I think.
|
||||||
|
public abstract int getMaxStackHeight();
|
||||||
|
|
||||||
|
public Atom getName() {
|
||||||
|
return getReference().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Descriptor getDescriptor() {
|
||||||
|
return getReference().getDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SimpleVisitor extends Instruction.Visitor {
|
||||||
|
|
||||||
|
// TODO: make a better Set implementation for these.
|
||||||
|
Set<CallSiteReference> callSites = HashSetFactory.make(5);
|
||||||
|
|
||||||
|
Set<FieldReference> fieldsWritten = HashSetFactory.make(5);
|
||||||
|
|
||||||
|
Set<FieldReference> fieldsRead = HashSetFactory.make(5);
|
||||||
|
|
||||||
|
Set<NewSiteReference> newSites = HashSetFactory.make(5);
|
||||||
|
|
||||||
|
Set<TypeReference> arraysRead = HashSetFactory.make(5);
|
||||||
|
|
||||||
|
Set<TypeReference> arraysWritten = HashSetFactory.make(5);
|
||||||
|
|
||||||
|
Set<TypeReference> implicitExceptions = HashSetFactory.make(5);
|
||||||
|
|
||||||
|
Set<TypeReference> castTypes = HashSetFactory.make(5);
|
||||||
|
|
||||||
|
boolean hasMonitorOp;
|
||||||
|
|
||||||
|
private int instructionIndex;
|
||||||
|
|
||||||
|
public void setInstructionIndex(int i) {
|
||||||
|
instructionIndex = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getProgramCounter() throws InvalidClassFileException {
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
return bcInfo.pcMap[instructionIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitMonitor(com.ibm.wala.shrikeBT.MonitorInstruction)
|
||||||
|
*/
|
||||||
|
public void visitMonitor(MonitorInstruction instruction) {
|
||||||
|
hasMonitorOp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitNew(NewInstruction instruction) {
|
||||||
|
ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader();
|
||||||
|
TypeReference t = ShrikeUtil.makeTypeReference(loader, instruction.getType());
|
||||||
|
try {
|
||||||
|
newSites.add(NewSiteReference.make(getProgramCounter(), t));
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitGet(GetInstruction instruction) {
|
||||||
|
ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader();
|
||||||
|
FieldReference f = ShrikeUtil.makeFieldReference(loader, instruction.getClassType(), instruction.getFieldName(), instruction
|
||||||
|
.getFieldType());
|
||||||
|
fieldsRead.add(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitPut(PutInstruction instruction) {
|
||||||
|
ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader();
|
||||||
|
FieldReference f = ShrikeUtil.makeFieldReference(loader, instruction.getClassType(), instruction.getFieldName(), instruction
|
||||||
|
.getFieldType());
|
||||||
|
fieldsWritten.add(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitInvoke(InvokeInstruction instruction) {
|
||||||
|
ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader();
|
||||||
|
MethodReference m = ShrikeUtil.makeMethodReference(loader, instruction.getClassType(), instruction.getMethodName(),
|
||||||
|
instruction.getMethodSignature());
|
||||||
|
int programCounter = 0;
|
||||||
|
try {
|
||||||
|
programCounter = getProgramCounter();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
CallSiteReference site = null;
|
||||||
|
int nParams = m.getNumberOfParameters();
|
||||||
|
switch (instruction.getInvocationMode()) {
|
||||||
|
case Constants.OP_invokestatic:
|
||||||
|
site = CallSiteReference.make(programCounter, m, IInvokeInstruction.Dispatch.STATIC);
|
||||||
|
break;
|
||||||
|
case Constants.OP_invokeinterface:
|
||||||
|
site = CallSiteReference.make(programCounter, m, IInvokeInstruction.Dispatch.INTERFACE);
|
||||||
|
nParams++;
|
||||||
|
break;
|
||||||
|
case Constants.OP_invokespecial:
|
||||||
|
site = CallSiteReference.make(programCounter, m, IInvokeInstruction.Dispatch.SPECIAL);
|
||||||
|
nParams++;
|
||||||
|
break;
|
||||||
|
case Constants.OP_invokevirtual:
|
||||||
|
site = CallSiteReference.make(programCounter, m, IInvokeInstruction.Dispatch.VIRTUAL);
|
||||||
|
nParams++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
callSites.add(site);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayLoad(com.ibm.wala.shrikeBT.ArrayLoadInstruction)
|
||||||
|
*/
|
||||||
|
public void visitArrayLoad(ArrayLoadInstruction instruction) {
|
||||||
|
arraysRead.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), instruction.getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.shrikeBT.Instruction.Visitor#visitArrayStore(com.ibm.wala.shrikeBT.ArrayStoreInstruction)
|
||||||
|
*/
|
||||||
|
public void visitArrayStore(ArrayStoreInstruction instruction) {
|
||||||
|
arraysWritten.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), instruction.getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitCheckCast(CheckCastInstruction instruction) {
|
||||||
|
castTypes.add(ShrikeUtil.makeTypeReference(getDeclaringClass().getClassLoader().getReference(), instruction.getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getInstructions.
|
||||||
|
*
|
||||||
|
* @return Instruction[]
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public Instruction[] getInstructions() throws InvalidClassFileException {
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
if (bcInfo.decoder == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return bcInfo.decoder.getInstructions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getHandlers.
|
||||||
|
*
|
||||||
|
* @return ExceptionHandler[][]
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public ExceptionHandler[][] getHandlers() throws InvalidClassFileException {
|
||||||
|
if (bcInfo == null) {
|
||||||
|
processBytecodes();
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
if (bcInfo.decoder == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return bcInfo.decoder.getHandlers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getParameterType. By convention, for a non-static method,
|
||||||
|
* getParameterType(0) is the this pointer
|
||||||
|
*
|
||||||
|
* @param i
|
||||||
|
* @return TypeReference
|
||||||
|
*/
|
||||||
|
public TypeReference getParameterType(int i) {
|
||||||
|
if (!isStatic()) {
|
||||||
|
if (i == 0)
|
||||||
|
return declaringClass.getReference();
|
||||||
|
else
|
||||||
|
return getReference().getParameterType(i - 1);
|
||||||
|
} else {
|
||||||
|
return getReference().getParameterType(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getNumberOfParameters. This result includes the "this" pointer if
|
||||||
|
* applicable
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public int getNumberOfParameters() {
|
||||||
|
if (isStatic() || isClinit()) {
|
||||||
|
return getReference().getNumberOfParameters();
|
||||||
|
} else {
|
||||||
|
return getReference().getNumberOfParameters() + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#hasExceptionHandler()
|
||||||
|
*/
|
||||||
|
public abstract boolean hasExceptionHandler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clients should not modify the returned array. TODO: clone to avoid the
|
||||||
|
* problem?
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getDeclaredExceptions()
|
||||||
|
*/
|
||||||
|
public TypeReference[] getDeclaredExceptions() {
|
||||||
|
|
||||||
|
if (bcInfo == null) {
|
||||||
|
try {
|
||||||
|
processBytecodes();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
return (bcInfo.exceptionTypes == null) ? new TypeReference[0] : bcInfo.exceptionTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String[] getDeclaredExceptionTypeNames() throws InvalidClassFileException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getDeclaredExceptions()
|
||||||
|
*/
|
||||||
|
private TypeReference[] computeDeclaredExceptions() {
|
||||||
|
try {
|
||||||
|
String[] strings = getDeclaredExceptionTypeNames();
|
||||||
|
if (strings == null) return null;
|
||||||
|
|
||||||
|
ClassLoaderReference loader = getDeclaringClass().getClassLoader().getReference();
|
||||||
|
|
||||||
|
TypeReference[] result = new TypeReference[strings.length];
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
result[i] = TypeReference.findOrCreate(loader, TypeName.findOrCreate(ImmutableByteArray.make("L" + strings[i])));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getLineNumber(int)
|
||||||
|
*/
|
||||||
|
public int getLineNumber(int bcIndex) {
|
||||||
|
if (bcInfo == null) {
|
||||||
|
try {
|
||||||
|
processBytecodes();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
return (bcInfo.lineNumberMap == null) ? -1 : bcInfo.lineNumberMap[bcIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Set <TypeReference>
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public Set<TypeReference> getCaughtExceptionTypes() throws InvalidClassFileException {
|
||||||
|
|
||||||
|
ExceptionHandler[][] handlers = getHandlers();
|
||||||
|
if (handlers == null) {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
HashSet<TypeReference> result = HashSetFactory.make(10);
|
||||||
|
ClassLoaderReference loader = getReference().getDeclaringClass().getClassLoader();
|
||||||
|
for (int i = 0; i < handlers.length; i++) {
|
||||||
|
for (int j = 0; j < handlers[i].length; j++) {
|
||||||
|
TypeReference t = ShrikeUtil.makeTypeReference(loader, handlers[i][j].getCatchClass());
|
||||||
|
if (t == null) {
|
||||||
|
t = TypeReference.JavaLangThrowable;
|
||||||
|
}
|
||||||
|
result.add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getSignature()
|
||||||
|
*/
|
||||||
|
public String getSignature() {
|
||||||
|
return getReference().getSignature();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getSelector()
|
||||||
|
*/
|
||||||
|
public Selector getSelector() {
|
||||||
|
return getReference().getSelector();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getLocalVariableName(int, int)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract String getLocalVariableName(int bcIndex, int localNumber);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: cache for efficiency? (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#hasLocalVariableTable()
|
||||||
|
*/
|
||||||
|
public abstract boolean hasLocalVariableTable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all optional cached data associated with this class
|
||||||
|
*/
|
||||||
|
public void clearCaches() {
|
||||||
|
bcInfo = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,836 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchyWarning;
|
||||||
|
import com.ibm.wala.shrikeBT.Constants;
|
||||||
|
import com.ibm.wala.shrikeCT.ClassConstants;
|
||||||
|
import com.ibm.wala.shrikeCT.ClassReader;
|
||||||
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||||
|
import com.ibm.wala.types.FieldReference;
|
||||||
|
import com.ibm.wala.types.MethodReference;
|
||||||
|
import com.ibm.wala.types.Selector;
|
||||||
|
import com.ibm.wala.types.TypeName;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.Atom;
|
||||||
|
import com.ibm.wala.util.ImmutableByteArray;
|
||||||
|
import com.ibm.wala.util.ShrikeClassReaderHandle;
|
||||||
|
import com.ibm.wala.util.collections.BimodalMap;
|
||||||
|
import com.ibm.wala.util.collections.HashMapFactory;
|
||||||
|
import com.ibm.wala.util.collections.HashSetFactory;
|
||||||
|
import com.ibm.wala.util.collections.SmallMap;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.debug.Trace;
|
||||||
|
import com.ibm.wala.util.warnings.Warning;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A wrapper around a java.lang.Class object
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public final class ShrikeCTClassWrapper implements IClass {
|
||||||
|
|
||||||
|
static final boolean DEBUG = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Shrike object that knows how to read the class file
|
||||||
|
*/
|
||||||
|
private final ShrikeClassReaderHandle reader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object that loaded this class.
|
||||||
|
*/
|
||||||
|
private final IClassLoader loader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Governing class hierarchy for this class
|
||||||
|
*/
|
||||||
|
private final ClassHierarchy cha;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapping from Selector to IMethod
|
||||||
|
*
|
||||||
|
* TODO: get rid of this for classes (though keep it for interfaces) instead
|
||||||
|
* ... use a VMT.
|
||||||
|
*/
|
||||||
|
private Map<Selector, IMethod> methodMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mapping from Selector to IMethod used to cache method lookups from
|
||||||
|
* superclasses
|
||||||
|
*/
|
||||||
|
private Map<Selector, IMethod> inheritCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Canonical type representation
|
||||||
|
*/
|
||||||
|
private TypeReference typeReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object to track warnings
|
||||||
|
*/
|
||||||
|
private final WarningSet warnings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* superclass
|
||||||
|
*/
|
||||||
|
private IClass superClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the superclass lazily.
|
||||||
|
*/
|
||||||
|
private boolean superclassComputed = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Atom which holds the name of the super class. We cache this for
|
||||||
|
* efficiency reasons.
|
||||||
|
*/
|
||||||
|
private ImmutableByteArray superName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The names of interfaces for this class. We cache this for efficiency
|
||||||
|
* reasons.
|
||||||
|
*/
|
||||||
|
private ImmutableByteArray[] interfaceNames;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The IClasses that represent all interfaces this class implements (if it's a
|
||||||
|
* class) or extends (it it's an interface)
|
||||||
|
*/
|
||||||
|
private Collection<IClass> allInterfaces = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The instance fields declared in this class.
|
||||||
|
*/
|
||||||
|
private IField[] instanceFields;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The static fields declared in this class.
|
||||||
|
*/
|
||||||
|
private IField[] staticFields;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JVM-level modifiers; cached here for efficiency
|
||||||
|
*/
|
||||||
|
private int modifiers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash code; cached here for efficiency
|
||||||
|
*/
|
||||||
|
private final int hashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param reader
|
||||||
|
* @param loader
|
||||||
|
* @param cha
|
||||||
|
* @param warnings
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
public ShrikeCTClassWrapper(ShrikeClassReaderHandle reader, IClassLoader loader, ClassHierarchy cha, WarningSet warnings)
|
||||||
|
throws InvalidClassFileException {
|
||||||
|
if (reader == null)
|
||||||
|
throw new NullPointerException();
|
||||||
|
this.reader = reader;
|
||||||
|
this.loader = loader;
|
||||||
|
this.cha = cha;
|
||||||
|
this.warnings = warnings;
|
||||||
|
computeTypeReference();
|
||||||
|
this.hashCode = 2161 * getReference().hashCode();
|
||||||
|
// as long as the reader is around, pull more data out
|
||||||
|
// of it before the soft reference to it disappears
|
||||||
|
computeSuperName();
|
||||||
|
computeModifiers();
|
||||||
|
computeInterfaceNames();
|
||||||
|
computeFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the fields declared by this class
|
||||||
|
*
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
* iff Shrike fails to read the class file correctly
|
||||||
|
*/
|
||||||
|
private void computeFields() throws InvalidClassFileException {
|
||||||
|
ClassReader cr = reader.get();
|
||||||
|
int fieldCount = cr.getFieldCount();
|
||||||
|
List<FieldImpl> instanceList = new ArrayList<FieldImpl>(fieldCount);
|
||||||
|
List<FieldImpl> staticList = new ArrayList<FieldImpl>(fieldCount);
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < fieldCount; i++) {
|
||||||
|
int accessFlags = cr.getFieldAccessFlags(i);
|
||||||
|
Atom name = Atom.findOrCreateUnicodeAtom(cr.getFieldName(i));
|
||||||
|
ImmutableByteArray b = ImmutableByteArray.make(cr.getFieldType(i));
|
||||||
|
|
||||||
|
if ((accessFlags & ClassConstants.ACC_STATIC) == 0) {
|
||||||
|
addFieldToList(instanceList, name, b, accessFlags);
|
||||||
|
} else {
|
||||||
|
addFieldToList(staticList, name, b, accessFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instanceFields = new IField[instanceList.size()];
|
||||||
|
populateFieldArrayFromList(instanceList, instanceFields);
|
||||||
|
staticFields = new IField[staticList.size()];
|
||||||
|
populateFieldArrayFromList(staticList, staticFields);
|
||||||
|
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateFieldArrayFromList(List<FieldImpl> L, IField[] A) {
|
||||||
|
Iterator<FieldImpl> it = L.iterator();
|
||||||
|
for (int i = 0; i < A.length; i++) {
|
||||||
|
A[i] = it.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFieldToList(List<FieldImpl> L, Atom name, ImmutableByteArray fieldType, int accessFlags) {
|
||||||
|
TypeName T = null;
|
||||||
|
if (fieldType.get(fieldType.length() - 1) == ';') {
|
||||||
|
T = TypeName.findOrCreate(fieldType, 0, fieldType.length() - 1);
|
||||||
|
} else {
|
||||||
|
T = TypeName.findOrCreate(fieldType);
|
||||||
|
}
|
||||||
|
TypeReference type = TypeReference.findOrCreate(getClassLoader().getReference(), T);
|
||||||
|
FieldReference fr = FieldReference.findOrCreate(getReference(), name, type);
|
||||||
|
FieldImpl f = new FieldImpl(this, fr, accessFlags);
|
||||||
|
L.add(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IClassLoader getClassLoader() {
|
||||||
|
return loader;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInterface() {
|
||||||
|
boolean result = ((modifiers & Constants.ACC_INTERFACE) != 0);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#isAbstract()
|
||||||
|
*/
|
||||||
|
public boolean isAbstract() {
|
||||||
|
boolean result = ((modifiers & Constants.ACC_ABSTRACT) != 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
private void computeModifiers() throws InvalidClassFileException {
|
||||||
|
modifiers = reader.get().getAccessFlags();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getModifiers() {
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that this is called from the constructor, at which point this class is
|
||||||
|
* not yet ready to actually load the superclass. Instead, we pull out the
|
||||||
|
* name of the superclass and cache it here, to avoid hitting the reader
|
||||||
|
* later.
|
||||||
|
*/
|
||||||
|
private void computeSuperName() {
|
||||||
|
try {
|
||||||
|
String s = reader.get().getSuperName();
|
||||||
|
if (s != null) {
|
||||||
|
superName = ImmutableByteArray.make("L" + s);
|
||||||
|
}
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void computeSuperclass() {
|
||||||
|
superclassComputed = true;
|
||||||
|
|
||||||
|
if (superName == null) {
|
||||||
|
if (!getReference().equals(TypeReference.JavaLangObject)) {
|
||||||
|
superClass = loader.lookupClass(TypeReference.JavaLangObject.getName());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
superClass = loader.lookupClass(TypeName.findOrCreate(superName));
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("got superclass " + superClass + " for " + this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IClass getSuperclass() throws ClassHierarchyException {
|
||||||
|
if (!superclassComputed) {
|
||||||
|
computeSuperclass();
|
||||||
|
}
|
||||||
|
if (superClass == null && !getReference().equals(TypeReference.JavaLangObject)) {
|
||||||
|
try {
|
||||||
|
throw new ClassHierarchyException("No superclass " + reader.get().getSuperName() + " found for " + this);
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return superClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that this is called from the constructor, at which point this class is
|
||||||
|
* not yet ready to actually load the interfaces. Instead, we pull out the
|
||||||
|
* name of the interfaces and cache it here, to avoid hitting the reader
|
||||||
|
* later.
|
||||||
|
*/
|
||||||
|
private void computeInterfaceNames() {
|
||||||
|
try {
|
||||||
|
String[] s = reader.get().getInterfaceNames();
|
||||||
|
interfaceNames = new ImmutableByteArray[s.length];
|
||||||
|
for (int i = 0; i < interfaceNames.length; i++) {
|
||||||
|
interfaceNames[i] = ImmutableByteArray.make("L" + s[i]);
|
||||||
|
}
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getAllInterfacesAsCollection.
|
||||||
|
*
|
||||||
|
* @return Collection of IClasses, representing the interfaces this class
|
||||||
|
* implements.
|
||||||
|
*/
|
||||||
|
private Collection<IClass> computeAllInterfacesAsCollection() throws ClassHierarchyException {
|
||||||
|
Collection<IClass> c = getDirectInterfaces();
|
||||||
|
Set<IClass> result = HashSetFactory.make();
|
||||||
|
for (Iterator<IClass> it = c.iterator(); it.hasNext();) {
|
||||||
|
IClass klass = it.next();
|
||||||
|
if (klass.isInterface()) {
|
||||||
|
result.add(klass);
|
||||||
|
} else {
|
||||||
|
warnings.add(ClassHierarchyWarning.create("expected an interface " + klass));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Iterator<IClass> it = c.iterator(); it.hasNext();) {
|
||||||
|
ShrikeCTClassWrapper I = (ShrikeCTClassWrapper) it.next();
|
||||||
|
if (I.isInterface()) {
|
||||||
|
result.addAll(I.computeAllInterfacesAsCollection());
|
||||||
|
} else {
|
||||||
|
warnings.add(ClassHierarchyWarning.create("expected an interface " + I));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now add any interfaces from the super class
|
||||||
|
ShrikeCTClassWrapper sup = null;
|
||||||
|
try {
|
||||||
|
sup = (ShrikeCTClassWrapper) getSuperclass();
|
||||||
|
} catch (ClassHierarchyException e1) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
if (sup != null) {
|
||||||
|
result.addAll(sup.computeAllInterfacesAsCollection());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getDirectInterfaces()
|
||||||
|
*/
|
||||||
|
public Collection<IClass> getDirectInterfaces() {
|
||||||
|
return array2IClassSet(interfaceNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method array2Set.
|
||||||
|
*
|
||||||
|
* @param interfaces
|
||||||
|
* a set of class names
|
||||||
|
* @return Set of all IClasses that can be loaded corresponding to the class
|
||||||
|
* names in the interfaces array; raise warnings if classes can not be
|
||||||
|
* loaded
|
||||||
|
*/
|
||||||
|
private Collection<IClass> array2IClassSet(ImmutableByteArray[] interfaces) {
|
||||||
|
ArrayList<IClass> result = new ArrayList<IClass>(interfaces.length);
|
||||||
|
for (int i = 0; i < interfaces.length; i++) {
|
||||||
|
ImmutableByteArray name = interfaces[i];
|
||||||
|
IClass klass = null;
|
||||||
|
klass = loader.lookupClass(TypeName.findOrCreate(name));
|
||||||
|
if (klass == null) {
|
||||||
|
warnings.add(ClassNotFoundWarning.create(name));
|
||||||
|
} else {
|
||||||
|
result.add(klass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
* A warning for when we get a class not found exception
|
||||||
|
*/
|
||||||
|
private static class ClassNotFoundWarning extends Warning {
|
||||||
|
|
||||||
|
final ImmutableByteArray className;
|
||||||
|
|
||||||
|
ClassNotFoundWarning(ImmutableByteArray className) {
|
||||||
|
super(Warning.SEVERE);
|
||||||
|
this.className = className;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMsg() {
|
||||||
|
return getClass().toString() + " : " + className;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ClassNotFoundWarning create(ImmutableByteArray className) {
|
||||||
|
return new ClassNotFoundWarning(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set up the methodMap mapping
|
||||||
|
*/
|
||||||
|
private void computeMethodMap() throws InvalidClassFileException {
|
||||||
|
|
||||||
|
if (methodMap == null) {
|
||||||
|
ShrikeCTMethodWrapper[] methods = computeDeclaredMethods();
|
||||||
|
if (methods.length > 5) {
|
||||||
|
methodMap = HashMapFactory.make(methods.length);
|
||||||
|
} else {
|
||||||
|
methodMap = new SmallMap<Selector, IMethod>();
|
||||||
|
}
|
||||||
|
for (int i = 0; i < methods.length; i++) {
|
||||||
|
ShrikeCTMethodWrapper m = methods[i];
|
||||||
|
methodMap.put(m.getReference().getSelector(), m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* initialize the declared methods array
|
||||||
|
*
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
*/
|
||||||
|
private ShrikeCTMethodWrapper[] computeDeclaredMethods() throws InvalidClassFileException {
|
||||||
|
int methodCount = reader.get().getMethodCount();
|
||||||
|
ShrikeCTMethodWrapper[] result = new ShrikeCTMethodWrapper[methodCount];
|
||||||
|
for (int i = 0; i < methodCount; i++) {
|
||||||
|
ShrikeCTMethodWrapper m = new ShrikeCTMethodWrapper(this, i);
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("Register method " + m + " for class " + this);
|
||||||
|
}
|
||||||
|
result[i] = m;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getMethod(com.ibm.wala.types.Selector)
|
||||||
|
*/
|
||||||
|
public IMethod getMethod(Selector selector) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Trace.println("getMethod " + selector + " in " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (methodMap == null) {
|
||||||
|
try {
|
||||||
|
computeMethodMap();
|
||||||
|
} catch (InvalidClassFileException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// my methods + cached parent stuff
|
||||||
|
IMethod result = (IMethod) methodMap.get(selector);
|
||||||
|
if (result != null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (inheritCache != null) {
|
||||||
|
result = inheritCache.get(selector);
|
||||||
|
if (result != null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check parent, caching if found
|
||||||
|
try {
|
||||||
|
if (!selector.equals(MethodReference.clinitSelector) && !selector.equals(MethodReference.initSelector)) {
|
||||||
|
ShrikeCTClassWrapper superclass = (ShrikeCTClassWrapper) getSuperclass();
|
||||||
|
if (superclass != null) {
|
||||||
|
IMethod inherit = superclass.getMethod(selector);
|
||||||
|
if (inherit != null) {
|
||||||
|
if (inheritCache == null) {
|
||||||
|
inheritCache = new BimodalMap<Selector, IMethod>(5);
|
||||||
|
}
|
||||||
|
inheritCache.put(selector, inherit);
|
||||||
|
return inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ClassHierarchyException e) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
// didn't find it yet. special logic for interfaces
|
||||||
|
try {
|
||||||
|
if (isInterface()) {
|
||||||
|
// try each superinterface
|
||||||
|
for (Iterator it = getAllAncestorInterfaces().iterator(); it.hasNext();) {
|
||||||
|
IClass k = (IClass) it.next();
|
||||||
|
result = k.getMethod(selector);
|
||||||
|
if (result != null) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} catch (ClassHierarchyException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE("Bad method lookup in " + this);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final HashMap<Atom, IField> fieldMap = new HashMap<Atom, IField>(5);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getField(com.ibm.wala.util.Atom)
|
||||||
|
*/
|
||||||
|
public IField getField(Atom name) {
|
||||||
|
if (fieldMap.containsKey(name)) {
|
||||||
|
return fieldMap.get(name);
|
||||||
|
} else {
|
||||||
|
IField f = findDeclaredField(name);
|
||||||
|
if (f != null) {
|
||||||
|
fieldMap.put(name, f);
|
||||||
|
return f;
|
||||||
|
} else if (superClass != null) {
|
||||||
|
f = superClass.getField(name);
|
||||||
|
if (f != null) {
|
||||||
|
fieldMap.put(name, f);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IField findDeclaredField(Atom name) {
|
||||||
|
for (int i = 0; i < instanceFields.length; i++) {
|
||||||
|
if (instanceFields[i].getName() == name) {
|
||||||
|
return instanceFields[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < staticFields.length; i++) {
|
||||||
|
if (staticFields[i].getName() == name) {
|
||||||
|
return staticFields[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* initialize the TypeReference field for this instance
|
||||||
|
*
|
||||||
|
* @throws InvalidClassFileException
|
||||||
|
* iff Shrike can't read this class
|
||||||
|
*/
|
||||||
|
private void computeTypeReference() throws InvalidClassFileException {
|
||||||
|
String className = "L" + reader.get().getName();
|
||||||
|
ImmutableByteArray name = ImmutableByteArray.make(className);
|
||||||
|
|
||||||
|
typeReference = TypeReference.findOrCreate(getClassLoader().getReference(), TypeName.findOrCreate(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getReference()
|
||||||
|
*/
|
||||||
|
public TypeReference getReference() {
|
||||||
|
return typeReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getSourceFileName()
|
||||||
|
*/
|
||||||
|
public String getSourceFileName() {
|
||||||
|
return loader.getSourceFileName(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<IClass> getAllImplementedInterfaces() throws ClassHierarchyException {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
if (isInterface()) {
|
||||||
|
Assertions.UNREACHABLE("shouldn't ask for implemented interfaces of " + this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allInterfaces != null) {
|
||||||
|
return allInterfaces;
|
||||||
|
} else {
|
||||||
|
Collection<IClass> C = computeAllInterfacesAsCollection();
|
||||||
|
allInterfaces = Collections.unmodifiableCollection(C);
|
||||||
|
return allInterfaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<IClass> getAllAncestorInterfaces() throws ClassHierarchyException {
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
if (!isInterface()) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allInterfaces != null) {
|
||||||
|
return allInterfaces;
|
||||||
|
} else {
|
||||||
|
Collection<IClass> C = computeAllInterfacesAsCollection();
|
||||||
|
allInterfaces = Collections.unmodifiableCollection(C);
|
||||||
|
return allInterfaces;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return getReference().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#equals(Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
// it's ok to use instanceof since this class is final
|
||||||
|
// if (this.getClass().equals(obj.getClass())) {
|
||||||
|
if (obj instanceof ShrikeCTClassWrapper) {
|
||||||
|
return getReference().equals(((ShrikeCTClassWrapper) obj).getReference());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method getReader.
|
||||||
|
*/
|
||||||
|
public ClassReader getReader() {
|
||||||
|
try {
|
||||||
|
return reader.get();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getClassInitializer()
|
||||||
|
*/
|
||||||
|
public IMethod getClassInitializer() {
|
||||||
|
if (methodMap == null) {
|
||||||
|
try {
|
||||||
|
computeMethodMap();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (IMethod) methodMap.get(MethodReference.clinitSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getDeclaredMethods()
|
||||||
|
*/
|
||||||
|
public Iterator<IMethod> getDeclaredMethods() {
|
||||||
|
if (methodMap == null) {
|
||||||
|
try {
|
||||||
|
computeMethodMap();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return methodMap.values().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#isArrayClass()
|
||||||
|
*/
|
||||||
|
public boolean isArrayClass() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassHierarchy getClassHierarchy() {
|
||||||
|
return cha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WarningSet getWarnings() {
|
||||||
|
return warnings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getDeclaredFields()
|
||||||
|
*/
|
||||||
|
public Collection<IField> getDeclaredInstanceFields() {
|
||||||
|
return Collections.unmodifiableList(Arrays.asList(instanceFields));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getDeclaredFields()
|
||||||
|
*/
|
||||||
|
public Collection<IField> getDeclaredStaticFields() {
|
||||||
|
return Collections.unmodifiableList(Arrays.asList(staticFields));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getName()
|
||||||
|
*/
|
||||||
|
public TypeName getName() {
|
||||||
|
return getReference().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#isReferenceType()
|
||||||
|
*/
|
||||||
|
public boolean isReferenceType() {
|
||||||
|
return getReference().isReferenceType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all optional cached data associated with this class
|
||||||
|
*/
|
||||||
|
public void clearSoftCaches() {
|
||||||
|
// toss optional information from each method.
|
||||||
|
if (methodMap != null) {
|
||||||
|
for (Iterator it = getDeclaredMethods(); it.hasNext();) {
|
||||||
|
ShrikeCTMethodWrapper m = (ShrikeCTMethodWrapper) it.next();
|
||||||
|
m.clearCaches();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// clear the methodMap cache
|
||||||
|
// SJF: don't do this!!! makes it hard to clear caches on methods.
|
||||||
|
// methodMap = null;
|
||||||
|
inheritCache = null;
|
||||||
|
// clear the cached interfaces
|
||||||
|
allInterfaces = null;
|
||||||
|
// toss away the Shrike reader
|
||||||
|
reader.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getAllInstanceFields()
|
||||||
|
*/
|
||||||
|
public Collection<IField> getAllInstanceFields() throws ClassHierarchyException {
|
||||||
|
Collection<IField> result = new LinkedList<IField>(getDeclaredInstanceFields());
|
||||||
|
IClass s = getSuperclass();
|
||||||
|
while (s != null) {
|
||||||
|
result.addAll(s.getDeclaredInstanceFields());
|
||||||
|
s = s.getSuperclass();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getAllStaticFields()
|
||||||
|
*/
|
||||||
|
public Collection<IField> getAllStaticFields() throws ClassHierarchyException {
|
||||||
|
Collection<IField> result = new LinkedList<IField>(getDeclaredStaticFields());
|
||||||
|
IClass s = getSuperclass();
|
||||||
|
while (s != null) {
|
||||||
|
result.addAll(s.getDeclaredStaticFields());
|
||||||
|
s = s.getSuperclass();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getAllMethods()
|
||||||
|
*/
|
||||||
|
public Collection<IMethod> getAllMethods() throws ClassHierarchyException {
|
||||||
|
Collection<IMethod> result = new LinkedList<IMethod>();
|
||||||
|
Iterator<IMethod> declaredMethods = getDeclaredMethods();
|
||||||
|
while (declaredMethods.hasNext()) {
|
||||||
|
result.add(declaredMethods.next());
|
||||||
|
}
|
||||||
|
IClass s = getSuperclass();
|
||||||
|
while (s != null) {
|
||||||
|
Iterator<IMethod> superDeclaredMethods = s.getDeclaredMethods();
|
||||||
|
while (superDeclaredMethods.hasNext()) {
|
||||||
|
result.add(superDeclaredMethods.next());
|
||||||
|
}
|
||||||
|
s = s.getSuperclass();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getAllFields()
|
||||||
|
*/
|
||||||
|
public Collection<IField> getAllFields() throws ClassHierarchyException {
|
||||||
|
Collection<IField> result = new LinkedList<IField>();
|
||||||
|
result.addAll(getAllInstanceFields());
|
||||||
|
result.addAll(getAllStaticFields());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,241 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import com.ibm.wala.shrikeBT.Decoder;
|
||||||
|
import com.ibm.wala.shrikeBT.shrikeCT.CTDecoder;
|
||||||
|
import com.ibm.wala.shrikeCT.ClassReader;
|
||||||
|
import com.ibm.wala.shrikeCT.CodeReader;
|
||||||
|
import com.ibm.wala.shrikeCT.ExceptionsReader;
|
||||||
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||||
|
import com.ibm.wala.shrikeCT.LineNumberTableReader;
|
||||||
|
import com.ibm.wala.shrikeCT.LocalVariableTableReader;
|
||||||
|
import com.ibm.wala.shrikeCT.ClassReader.AttrIterator;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A wrapper around a Shrike object that represents a method
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public final class ShrikeCTMethodWrapper extends ShrikeBTMethodWrapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index of this method in the declaring class's method list according to
|
||||||
|
* Shrike CT.
|
||||||
|
*/
|
||||||
|
private int shrikeMethodIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JVM-level modifiers for this method a value of -1 means "uninitialized"
|
||||||
|
*/
|
||||||
|
private int modifiers = -1;
|
||||||
|
|
||||||
|
public ShrikeCTMethodWrapper(IClass klass, int index) {
|
||||||
|
super(klass);
|
||||||
|
this.shrikeMethodIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBytecodes() {
|
||||||
|
CodeReader code = getCodeReader();
|
||||||
|
if (code == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return code.getBytecode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getMethodName() throws InvalidClassFileException {
|
||||||
|
ClassReader reader = getClassReader();
|
||||||
|
return reader.getMethodName(shrikeMethodIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getMethodSignature() throws InvalidClassFileException {
|
||||||
|
ClassReader reader = getClassReader();
|
||||||
|
return reader.getMethodType(shrikeMethodIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getModifiers() {
|
||||||
|
if (modifiers == -1) {
|
||||||
|
modifiers = getClassReader().getMethodAccessFlags(shrikeMethodIndex);
|
||||||
|
}
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Decoder makeDecoder() {
|
||||||
|
CodeReader reader = getCodeReader();
|
||||||
|
if (reader == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final Decoder d = new CTDecoder(reader);
|
||||||
|
try {
|
||||||
|
d.decode();
|
||||||
|
} catch (Decoder.InvalidBytecodeException ex) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxLocals() {
|
||||||
|
CodeReader reader = getCodeReader();
|
||||||
|
return reader.getMaxLocals();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxStackHeight() {
|
||||||
|
CodeReader reader = getCodeReader();
|
||||||
|
// note that Shrike returns the maximum index in the zero-indexed stack
|
||||||
|
// array.
|
||||||
|
// Instead, we want the max number of entries on the stack.
|
||||||
|
// So we add 1.
|
||||||
|
// Additionally, ShrikeBT may add additional stack entries with
|
||||||
|
// Constant instructions. We add an additional 1 to account for this,
|
||||||
|
// which seems to handle all ShrikeBT code generation patterns.
|
||||||
|
// TODO: ShrikeBT should have a getMaxStack method on Decoder, I think.
|
||||||
|
return reader.getMaxStack() + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasExceptionHandler() {
|
||||||
|
CodeReader reader = getCodeReader();
|
||||||
|
if (reader == null)
|
||||||
|
return false;
|
||||||
|
int[] handlers = reader.getRawHandlers();
|
||||||
|
return handlers != null && handlers.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String[] getDeclaredExceptionTypeNames() throws InvalidClassFileException {
|
||||||
|
ExceptionsReader reader = getExceptionReader();
|
||||||
|
if (reader == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return reader.getClasses();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void processDebugInfo(BytecodeInfo bcInfo) throws InvalidClassFileException {
|
||||||
|
CodeReader cr = getCodeReader();
|
||||||
|
bcInfo.lineNumberMap = LineNumberTableReader.makeBytecodeToSourceMap(cr);
|
||||||
|
bcInfo.localVariableMap = LocalVariableTableReader.makeVarMap(cr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getLocalVariableName(int bcIndex, int localNumber) {
|
||||||
|
if (bcInfo == null) {
|
||||||
|
try {
|
||||||
|
processBytecodes();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Assertions.verifyAssertions) {
|
||||||
|
Assertions._assert(bcInfo != null);
|
||||||
|
}
|
||||||
|
int[][] map = bcInfo.localVariableMap;
|
||||||
|
|
||||||
|
if (localNumber > getMaxLocals()) {
|
||||||
|
throw new IllegalArgumentException("illegal local number: " + localNumber + ", method " + getName() + " uses at most "
|
||||||
|
+ getMaxLocals());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
int[] localPairs = map[bcIndex];
|
||||||
|
int localIndex = localNumber * 2;
|
||||||
|
if (localPairs == null || localIndex >= localPairs.length) {
|
||||||
|
// no information about the specified local at this program point
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int nameIndex = localPairs[localIndex];
|
||||||
|
if (nameIndex == 0) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
return getClassReader().getCP().getCPUtf8(nameIndex);
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: cache for efficiency? (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#hasLocalVariableTable()
|
||||||
|
*/
|
||||||
|
public boolean hasLocalVariableTable() {
|
||||||
|
try {
|
||||||
|
ClassReader.AttrIterator iter = new ClassReader.AttrIterator();
|
||||||
|
getCodeReader().initAttributeIterator(iter);
|
||||||
|
for (; iter.isValid(); iter.advance()) {
|
||||||
|
if (iter.getName().equals("LocalVariableTable")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassReader getClassReader() {
|
||||||
|
return ((ShrikeCTClassWrapper)getDeclaringClass()).getReader();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeReader getCodeReader() {
|
||||||
|
ClassReader.AttrIterator iter = new AttrIterator();
|
||||||
|
getClassReader().initMethodAttributeIterator(shrikeMethodIndex, iter);
|
||||||
|
|
||||||
|
// search for the code attribute
|
||||||
|
CodeReader code = null;
|
||||||
|
try {
|
||||||
|
for (; iter.isValid(); iter.advance()) {
|
||||||
|
if (iter.getName().toString().equals("Code")) {
|
||||||
|
code = new CodeReader(iter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExceptionsReader getExceptionReader() {
|
||||||
|
ClassReader.AttrIterator iter = new AttrIterator();
|
||||||
|
getClassReader().initMethodAttributeIterator(shrikeMethodIndex, iter);
|
||||||
|
|
||||||
|
// search for the desired attribute
|
||||||
|
ExceptionsReader result = null;
|
||||||
|
try {
|
||||||
|
for (; iter.isValid(); iter.advance()) {
|
||||||
|
if (iter.getName().toString().equals("Exceptions")) {
|
||||||
|
result = new ExceptionsReader(iter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeReference getReturnType() {
|
||||||
|
return getReference().getReturnType();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import com.ibm.wala.cfg.ControlFlowGraph;
|
||||||
|
import com.ibm.wala.cfg.ShrikeCFG;
|
||||||
|
import com.ibm.wala.ipa.callgraph.Context;
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.shrikeCT.InvalidClassFileException;
|
||||||
|
import com.ibm.wala.ssa.IR;
|
||||||
|
import com.ibm.wala.ssa.IRFactory;
|
||||||
|
import com.ibm.wala.ssa.SSABuilder;
|
||||||
|
import com.ibm.wala.ssa.SSACFG;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAOptions;
|
||||||
|
import com.ibm.wala.ssa.SymbolTable;
|
||||||
|
import com.ibm.wala.ssa.analysis.DeadAssignmentElimination;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Julian Dolby
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ShrikeIRFactory implements IRFactory {
|
||||||
|
|
||||||
|
public final static boolean buildLocalMap = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ssa.IRFactory#makeCFG(com.ibm.wala.classLoader.IMethod,
|
||||||
|
* com.ibm.wala.ipa.cha.ClassHierarchy,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public ControlFlowGraph makeCFG(final IMethod method, Context C, final ClassHierarchy cha, final WarningSet warnings) {
|
||||||
|
return new ShrikeCFG((ShrikeCTMethodWrapper) method, warnings, cha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.ssa.IRFactory#makeIR(com.ibm.wala.classLoader.IMethod,
|
||||||
|
* com.ibm.wala.ipa.cha.ClassHierarchy, com.ibm.wala.ssa.SSAOptions,
|
||||||
|
* com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public IR makeIR(final IMethod method, Context C, final ClassHierarchy cha, final SSAOptions options, final WarningSet warnings) {
|
||||||
|
// This should be a method from Shrike
|
||||||
|
Assertions._assert(method instanceof ShrikeCTMethodWrapper);
|
||||||
|
|
||||||
|
// Set up some ShrikeCT mapping information before constructing SSA
|
||||||
|
try {
|
||||||
|
((ShrikeCTMethodWrapper) method).processBytecodes();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
com.ibm.wala.shrikeBT.Instruction[] shrikeInstructions;
|
||||||
|
try {
|
||||||
|
shrikeInstructions = ((ShrikeCTMethodWrapper) method).getInstructions();
|
||||||
|
} catch (InvalidClassFileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
shrikeInstructions = null;
|
||||||
|
}
|
||||||
|
final ShrikeCFG shrikeCFG = (ShrikeCFG) makeCFG(method, C, cha, warnings);
|
||||||
|
|
||||||
|
final SymbolTable symbolTable = new SymbolTable(method.getNumberOfParameters());
|
||||||
|
final SSAInstruction[] newInstrs = new SSAInstruction[shrikeInstructions.length];
|
||||||
|
|
||||||
|
final SSACFG newCfg = new SSACFG(method, shrikeCFG, newInstrs, warnings);
|
||||||
|
|
||||||
|
return new IR(method, newInstrs, symbolTable, newCfg, options) {
|
||||||
|
private final SSA2LocalMap localMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove any phis that are dead assignments.
|
||||||
|
*
|
||||||
|
* TODO: move this elsewhere?
|
||||||
|
*/
|
||||||
|
private void eliminateDeadPhis() {
|
||||||
|
DeadAssignmentElimination.perform(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SSA2LocalMap getLocalMap() {
|
||||||
|
return localMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SSABuilder builder = new SSABuilder((ShrikeCTMethodWrapper) method, cha, newCfg, shrikeCFG, newInstrs, symbolTable,
|
||||||
|
buildLocalMap, options.getUsePiNodes(), warnings);
|
||||||
|
builder.build();
|
||||||
|
if (buildLocalMap)
|
||||||
|
localMap = builder.getLocalMap();
|
||||||
|
else
|
||||||
|
localMap = null;
|
||||||
|
|
||||||
|
eliminateDeadPhis();
|
||||||
|
|
||||||
|
setupLocationMap();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class SourceDirectoryTreeModule extends DirectoryTreeModule {
|
||||||
|
|
||||||
|
public SourceDirectoryTreeModule(File root) {
|
||||||
|
super( root );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean includeFile(File file) {
|
||||||
|
return file.getName().endsWith("java");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected FileModule makeFile(File file) {
|
||||||
|
return new SourceFileModule(file, root.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.classLoader;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import com.ibm.wala.util.io.FileSuffixes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A module which is a wrapper around a .java file
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public class SourceFileModule extends FileModule implements Module, ModuleEntry {
|
||||||
|
|
||||||
|
private final String fileName;
|
||||||
|
public SourceFileModule(File f, String fileName) {
|
||||||
|
super(f);
|
||||||
|
this.fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceFileModule(File f, SourceFileModule clonedFrom) {
|
||||||
|
super(f);
|
||||||
|
this.fileName = clonedFrom.fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
return "SourceFileModule:" + getFile().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#isClassFile()
|
||||||
|
*/
|
||||||
|
public boolean isClassFile() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#getClassName()
|
||||||
|
*/
|
||||||
|
public String getClassName() {
|
||||||
|
return FileSuffixes.stripSuffix(fileName).replace(File.separator.charAt(0), '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.ModuleEntry#isSourceFile()
|
||||||
|
*/
|
||||||
|
public boolean isSourceFile() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class SourceURLModule extends AbstractURLModule {
|
||||||
|
|
||||||
|
public SourceURLModule(URL url) {
|
||||||
|
super(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClassFile() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSourceFile() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import com.ibm.wala.ipa.cha.ClassHierarchy;
|
||||||
|
import com.ibm.wala.types.ClassLoaderReference;
|
||||||
|
import com.ibm.wala.types.TypeReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A Class that exists nowhere in bytecode.
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public abstract class SyntheticClass implements IClass {
|
||||||
|
|
||||||
|
private final TypeReference T;
|
||||||
|
|
||||||
|
private final ClassHierarchy cha;
|
||||||
|
/**
|
||||||
|
* @param T type reference describing this class
|
||||||
|
*/
|
||||||
|
public SyntheticClass(TypeReference T, ClassHierarchy cha) {
|
||||||
|
super();
|
||||||
|
this.T = T;
|
||||||
|
this.cha = cha;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* By default, a synthetic class is "loaded" by the primordial loader.
|
||||||
|
* Subclasses may override as necessary.
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getClassLoader()
|
||||||
|
*/
|
||||||
|
public IClassLoader getClassLoader() {
|
||||||
|
return cha.getLoader(ClassLoaderReference.Primordial);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#isInterface()
|
||||||
|
*/
|
||||||
|
public boolean isInterface() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#isAbstract()
|
||||||
|
*/
|
||||||
|
public boolean isAbstract() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getReference()
|
||||||
|
*/
|
||||||
|
public TypeReference getReference() {
|
||||||
|
return T;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#getSourceFileName()
|
||||||
|
*/
|
||||||
|
public String getSourceFileName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.IClass#isArrayClass()
|
||||||
|
*/
|
||||||
|
public boolean isArrayClass() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,360 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.classLoader;
|
||||||
|
|
||||||
|
import com.ibm.wala.cfg.InducedCFG;
|
||||||
|
import com.ibm.wala.ipa.callgraph.impl.Everywhere;
|
||||||
|
import com.ibm.wala.ssa.IR;
|
||||||
|
import com.ibm.wala.ssa.SSAInstruction;
|
||||||
|
import com.ibm.wala.ssa.SSAOptions;
|
||||||
|
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.bytecode.BytecodeStream;
|
||||||
|
import com.ibm.wala.util.debug.Assertions;
|
||||||
|
import com.ibm.wala.util.warnings.WarningSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author sfink
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SyntheticMethod implements IMethod {
|
||||||
|
|
||||||
|
public final static SSAInstruction[] NO_STATEMENTS = new SSAInstruction[0];
|
||||||
|
|
||||||
|
private final MethodReference method;
|
||||||
|
|
||||||
|
private final IMethod resolvedMethod;
|
||||||
|
|
||||||
|
private final IClass declaringClass;
|
||||||
|
|
||||||
|
private final boolean isStatic;
|
||||||
|
|
||||||
|
private final boolean isFactory;
|
||||||
|
|
||||||
|
|
||||||
|
public SyntheticMethod(MethodReference method, IClass declaringClass, boolean isStatic, boolean isFactory) {
|
||||||
|
super();
|
||||||
|
this.method = method;
|
||||||
|
this.resolvedMethod = null;
|
||||||
|
this.declaringClass = declaringClass;
|
||||||
|
this.isStatic = isStatic;
|
||||||
|
this.isFactory = isFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public SyntheticMethod(IMethod method, IClass declaringClass, boolean isStatic, boolean isFactory) {
|
||||||
|
super();
|
||||||
|
this.resolvedMethod = method;
|
||||||
|
this.method = resolvedMethod.getReference();
|
||||||
|
this.declaringClass = declaringClass;
|
||||||
|
this.isStatic = isStatic;
|
||||||
|
this.isFactory = isFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#isClinit()
|
||||||
|
*/
|
||||||
|
public boolean isClinit() {
|
||||||
|
return method.getSelector().equals(MethodReference.clinitSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#isInit()
|
||||||
|
*/
|
||||||
|
public boolean isInit() {
|
||||||
|
return method.getSelector().equals(MethodReference.initSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#isStatic()
|
||||||
|
*/
|
||||||
|
public boolean isStatic() {
|
||||||
|
return isStatic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#isNative()
|
||||||
|
*/
|
||||||
|
public boolean isNative() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#isAbstract()
|
||||||
|
*/
|
||||||
|
public boolean isAbstract() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#isPrivate()
|
||||||
|
*/
|
||||||
|
public boolean isPrivate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isProtected() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPublic() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#isFinal()
|
||||||
|
*/
|
||||||
|
public boolean isFinal() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#isAbstract()
|
||||||
|
*/
|
||||||
|
public boolean isSynchronized() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#isSynthetic()
|
||||||
|
*/
|
||||||
|
public boolean isSynthetic() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getReference()
|
||||||
|
*/
|
||||||
|
public MethodReference getReference() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InducedCFG makeControlFlowGraph() {
|
||||||
|
return new InducedCFG(getStatements(new WarningSet()), this, Everywhere.EVERYWHERE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BytecodeStream getBytecodeStream() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getMaxLocals()
|
||||||
|
*/
|
||||||
|
public int getMaxLocals() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getMaxStackHeight()
|
||||||
|
*/
|
||||||
|
public int getMaxStackHeight() {
|
||||||
|
Assertions.UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see com.ibm.wala.classLoader.IMember#getDeclaringClass()
|
||||||
|
*/
|
||||||
|
public IClass getDeclaringClass() {
|
||||||
|
return declaringClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#equals(Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (getClass().equals(obj.getClass())) {
|
||||||
|
SyntheticMethod other = (SyntheticMethod) obj;
|
||||||
|
return (method.equals(other.method));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode() {
|
||||||
|
return method.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer s = new StringBuffer("synthetic ");
|
||||||
|
if (isFactoryMethod()) {
|
||||||
|
s.append(" factory ");
|
||||||
|
}
|
||||||
|
s.append(method.toString());
|
||||||
|
return s.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#hasExceptionHandler()
|
||||||
|
*/
|
||||||
|
public boolean hasExceptionHandler() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPoison() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPoison() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getPoisonLevel() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getStatements(com.ibm.wala.util.WarningSet)
|
||||||
|
*/
|
||||||
|
public SSAInstruction[] getStatements(SSAOptions options, WarningSet warnings) {
|
||||||
|
return NO_STATEMENTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getIR(com.ibm.wala.util.WarningSet)
|
||||||
|
*/
|
||||||
|
public IR makeIR(SSAOptions options, WarningSet warnings) {
|
||||||
|
Assertions.UNREACHABLE("haven't implemented IR yet for class " + getClass());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getParameterType(int)
|
||||||
|
*/
|
||||||
|
public TypeReference getParameterType(int i) {
|
||||||
|
if (isStatic()) {
|
||||||
|
return method.getParameterType(i);
|
||||||
|
} else {
|
||||||
|
if (i == 0) {
|
||||||
|
return method.getDeclaringClass();
|
||||||
|
} else {
|
||||||
|
return method.getParameterType(i - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getNumberOfParameters()
|
||||||
|
*/
|
||||||
|
public int getNumberOfParameters() {
|
||||||
|
int n = method.getNumberOfParameters();
|
||||||
|
return isStatic() ? n : n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getDeclaredExceptions()
|
||||||
|
*/
|
||||||
|
public TypeReference[] getDeclaredExceptions() {
|
||||||
|
if (resolvedMethod == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return resolvedMethod.getDeclaredExceptions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Atom getName() {
|
||||||
|
return method.getSelector().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Descriptor getDescriptor() {
|
||||||
|
return method.getSelector().getDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getLineNumber(int)
|
||||||
|
*/
|
||||||
|
public int getLineNumber(int bcIndex) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFactoryMethod() {
|
||||||
|
return isFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getSignature()
|
||||||
|
*/
|
||||||
|
public String getSignature() {
|
||||||
|
return getReference().getSignature();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getSelector()
|
||||||
|
*/
|
||||||
|
public Selector getSelector() {
|
||||||
|
return getReference().getSelector();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getLocalVariableName(int, int)
|
||||||
|
*/
|
||||||
|
public String getLocalVariableName(int bcIndex, int localNumber) {
|
||||||
|
// no information is available
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#hasLocalVariableTable()
|
||||||
|
*/
|
||||||
|
public boolean hasLocalVariableTable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getStatements(com.ibm.wala.util.warnings.WarningSet)
|
||||||
|
*/
|
||||||
|
public SSAInstruction[] getStatements(WarningSet warnings) {
|
||||||
|
return getStatements(SSAOptions.defaultOptions(), warnings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see com.ibm.wala.classLoader.IMethod#getReturnType()
|
||||||
|
*/
|
||||||
|
public TypeReference getReturnType() {
|
||||||
|
return getReference().getReturnType();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
<HTML>
|
||||||
|
<BODY>
|
||||||
|
This package provides functionality related to class loading and
|
||||||
|
management of loaded classes.
|
||||||
|
</BODY>
|
||||||
|
</HTML>
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* 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.client;
|
||||||
|
|
||||||
|
import com.ibm.wala.util.Stopwatch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* An object to track performance of an analysis engine
|
||||||
|
*
|
||||||
|
* @author sfink
|
||||||
|
*/
|
||||||
|
public abstract class AbstractEngineStopwatch implements EngineStopwatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of distinct categories timed by this object
|
||||||
|
*/
|
||||||
|
protected abstract int getNumberOfCategories();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an array of Strings that represent names of the categories tracked
|
||||||
|
*/
|
||||||
|
protected abstract String[] getCategoryNames();
|
||||||
|
|
||||||
|
protected final Stopwatch[] stopwatch;
|
||||||
|
|
||||||
|
protected AbstractEngineStopwatch() {
|
||||||
|
stopwatch = new Stopwatch[getNumberOfCategories()];
|
||||||
|
for (int i = 0; i < getNumberOfCategories(); i++) {
|
||||||
|
stopwatch[i] = new Stopwatch(getCategoryNames()[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String report() {
|
||||||
|
StringBuffer result = new StringBuffer();
|
||||||
|
long total = 0;
|
||||||
|
for (int i = 0; i < getNumberOfCategories(); i++) {
|
||||||
|
total += stopwatch[i].getElapsedMillis();
|
||||||
|
result.append(getCategoryNames()[i] + ": " + stopwatch[i].getElapsedMillis() + "\n");
|
||||||
|
}
|
||||||
|
result.append("Total : " + total + "\n");
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void start(byte category) {
|
||||||
|
stopwatch[category].start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void stop(byte category) {
|
||||||
|
stopwatch[category].stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stopwatch getTimer(byte category) {
|
||||||
|
return stopwatch[category];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue